summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt90
-rw-r--r--indra/newview/app_settings/settings.xml44
-rw-r--r--indra/newview/character/avatar_lad.xml7
-rw-r--r--indra/newview/llagent.cpp8
-rw-r--r--indra/newview/llagentui.cpp5
-rw-r--r--indra/newview/llagentui.h5
-rw-r--r--indra/newview/llappviewer.cpp2
-rw-r--r--indra/newview/llavatariconctrl.h2
-rw-r--r--indra/newview/llavatarlist.cpp30
-rw-r--r--indra/newview/llavatarlist.h6
-rw-r--r--indra/newview/llavatarlistitem.cpp22
-rw-r--r--indra/newview/llavatarlistitem.h4
-rw-r--r--indra/newview/llchannelmanager.cpp4
-rw-r--r--indra/newview/llchathistory.cpp245
-rw-r--r--indra/newview/llchathistory.h11
-rw-r--r--indra/newview/llfavoritesbar.cpp32
-rw-r--r--indra/newview/llfavoritesbar.h2
-rw-r--r--indra/newview/llfloaterchatterbox.cpp2
-rw-r--r--indra/newview/llfloaterinventory.cpp6
-rw-r--r--indra/newview/llfloatervoicedevicesettings.cpp2
-rw-r--r--indra/newview/llimfloater.cpp218
-rw-r--r--indra/newview/llimfloater.h20
-rw-r--r--indra/newview/llimpanel.cpp895
-rw-r--r--indra/newview/llimpanel.h136
-rw-r--r--indra/newview/llimview.cpp311
-rw-r--r--indra/newview/llimview.h93
-rw-r--r--indra/newview/lllandmarkactions.cpp2
-rw-r--r--indra/newview/lllandmarkactions.h2
-rw-r--r--indra/newview/llnavigationbar.cpp9
-rw-r--r--indra/newview/llnearbychat.cpp20
-rw-r--r--indra/newview/llnearbychatbar.cpp26
-rw-r--r--indra/newview/llnearbychatbar.h5
-rw-r--r--indra/newview/llnotificationtiphandler.cpp22
-rw-r--r--indra/newview/llpanelimcontrolpanel.cpp94
-rw-r--r--indra/newview/llpanelimcontrolpanel.h34
-rw-r--r--indra/newview/llpanellandmarks.cpp157
-rw-r--r--indra/newview/llpanellandmarks.h22
-rw-r--r--indra/newview/llpanelpeople.cpp34
-rw-r--r--indra/newview/llpanelplaceinfo.cpp66
-rw-r--r--indra/newview/llpanelplaceinfo.h8
-rw-r--r--indra/newview/llpanelplaces.cpp11
-rw-r--r--indra/newview/llpanelprimmediacontrols.cpp1095
-rw-r--r--indra/newview/llpanelprimmediacontrols.h148
-rw-r--r--indra/newview/llparticipantlist.cpp22
-rw-r--r--indra/newview/llscreenchannel.cpp28
-rw-r--r--indra/newview/llspeakers.cpp639
-rw-r--r--indra/newview/llspeakers.h172
-rw-r--r--indra/newview/llsyswellwindow.cpp6
-rw-r--r--indra/newview/llsyswellwindow.h1
-rw-r--r--indra/newview/lltexlayer.cpp3
-rw-r--r--indra/newview/lltoast.cpp18
-rw-r--r--indra/newview/lltoast.h3
-rw-r--r--indra/newview/llviewerinventory.cpp1
-rw-r--r--indra/newview/llviewermedia.cpp181
-rw-r--r--indra/newview/llviewermedia.h11
-rw-r--r--indra/newview/llviewermediafocus.cpp26
-rw-r--r--indra/newview/llviewermediafocus.h4
-rw-r--r--indra/newview/llviewermenu.cpp1
-rw-r--r--indra/newview/llviewermessage.cpp3
-rw-r--r--indra/newview/llviewerwindow.cpp1
-rw-r--r--indra/newview/llvoavatar.cpp5
-rw-r--r--indra/newview/llvoicechannel.cpp872
-rw-r--r--indra/newview/llvoicechannel.h168
-rw-r--r--indra/newview/llvoiceclient.cpp2
-rw-r--r--indra/newview/llwearable.cpp2
-rw-r--r--indra/newview/skins/default/textures/textures.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_camera.xml109
-rw-r--r--indra/newview/skins/default/xui/en/floater_nearby_chat.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_pay.xml7
-rw-r--r--indra/newview/skins/default/xui/en/floater_preview_notecard.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_report_abuse.xml102
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_textbox.xml67
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_place_add_button.xml27
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml29
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_control_panel.xml12
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_roles.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_im_control_panel.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmarks.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_prim_media_controls.xml594
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml26
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chat_history.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml3
-rw-r--r--indra/newview/skins/default/xui/en/widgets/tab_container.xml1
89 files changed, 5460 insertions, 1719 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index dd3937a6ef..a7681e4a1d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -63,13 +63,13 @@ include_directories(
)
set(viewer_SOURCE_FILES
- llaccordionctrltab.cpp
llaccordionctrl.cpp
+ llaccordionctrltab.cpp
llagent.cpp
- llagentlistener.cpp
llagentaccess.cpp
llagentdata.cpp
llagentlanguage.cpp
+ llagentlistener.cpp
llagentpicksinfo.cpp
llagentpilot.cpp
llagentui.cpp
@@ -78,8 +78,8 @@ set(viewer_SOURCE_FILES
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
- llassetuploadresponders.cpp
llassetuploadqueue.cpp
+ llassetuploadresponders.cpp
llaudiosourcevo.cpp
llavataractions.cpp
llavatariconctrl.cpp
@@ -95,8 +95,8 @@ set(viewer_SOURCE_FILES
llcaphttpsender.cpp
llchannelmanager.cpp
llchatbar.cpp
- llchatitemscontainerctrl.cpp
llchathistory.cpp
+ llchatitemscontainerctrl.cpp
llchatmsgbox.cpp
llchiclet.cpp
llclassifiedinfo.cpp
@@ -116,10 +116,10 @@ set(viewer_SOURCE_FILES
lldirpicker.cpp
lldndbutton.cpp
lldrawable.cpp
+ lldrawpool.cpp
lldrawpoolalpha.cpp
lldrawpoolavatar.cpp
lldrawpoolbump.cpp
- lldrawpool.cpp
lldrawpoolground.cpp
lldrawpoolsimple.cpp
lldrawpoolsky.cpp
@@ -151,8 +151,8 @@ set(viewer_SOURCE_FILES
llfloaterbuildoptions.cpp
llfloaterbulkpermission.cpp
llfloaterbump.cpp
- llfloaterbuycontents.cpp
llfloaterbuy.cpp
+ llfloaterbuycontents.cpp
llfloaterbuycurrency.cpp
llfloaterbuyland.cpp
llfloatercall.cpp
@@ -163,8 +163,8 @@ set(viewer_SOURCE_FILES
llfloatercustomize.cpp
llfloaterdaycycle.cpp
llfloaterenvsettings.cpp
- llfloaterfriends.cpp
llfloaterfonttest.cpp
+ llfloaterfriends.cpp
llfloatergesture.cpp
llfloatergodtools.cpp
llfloatergroupinvite.cpp
@@ -172,8 +172,6 @@ set(viewer_SOURCE_FILES
llfloaterhandler.cpp
llfloaterhardwaresettings.cpp
llfloaterhelpbrowser.cpp
- llfloatermediabrowser.cpp
- llfloatermediasettings.cpp
llfloaterhud.cpp
llfloaterimagepreview.cpp
llfloaterinspect.cpp
@@ -183,6 +181,8 @@ set(viewer_SOURCE_FILES
llfloaterland.cpp
llfloaterlandholdings.cpp
llfloatermap.cpp
+ llfloatermediabrowser.cpp
+ llfloatermediasettings.cpp
llfloatermemleak.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
@@ -227,8 +227,8 @@ set(viewer_SOURCE_FILES
llgroupmgr.cpp
llgroupnotify.cpp
llhomelocationresponder.cpp
- llhudeffectbeam.cpp
llhudeffect.cpp
+ llhudeffectbeam.cpp
llhudeffectlookat.cpp
llhudeffectpointat.cpp
llhudeffecttrail.cpp
@@ -238,11 +238,11 @@ set(viewer_SOURCE_FILES
llhudrender.cpp
llhudtext.cpp
llhudview.cpp
+ llimcontrolpanel.cpp
llimfloater.cpp
llimhandler.cpp
llimpanel.cpp
llimview.cpp
- llimcontrolpanel.cpp
llinspect.cpp
llinspectavatar.cpp
llinspectgroup.cpp
@@ -260,7 +260,6 @@ set(viewer_SOURCE_FILES
lllocaltextureobject.cpp
lllocationhistory.cpp
lllocationinputctrl.cpp
- llurllineeditorctrl.cpp
lllogchat.cpp
llloginhandler.cpp
lllogininstance.cpp
@@ -312,8 +311,8 @@ set(viewer_SOURCE_FILES
llpanelgrouplandmoney.cpp
llpanelgroupnotices.cpp
llpanelgrouproles.cpp
- llpanelinventory.cpp
llpanelimcontrolpanel.cpp
+ llpanelinventory.cpp
llpanelland.cpp
llpanellandaudio.cpp
llpanellandmarks.cpp
@@ -322,11 +321,10 @@ set(viewer_SOURCE_FILES
llpanellookinfo.cpp
llpanellooks.cpp
llpanelmedia.cpp
- llpanelmediahud.cpp
- llpanelmeprofile.cpp
llpanelmediasettingsgeneral.cpp
- llpanelmediasettingssecurity.cpp
llpanelmediasettingspermissions.cpp
+ llpanelmediasettingssecurity.cpp
+ llpanelmeprofile.cpp
llpanelobject.cpp
llpanelpeople.cpp
llpanelpeoplemenus.cpp
@@ -335,11 +333,12 @@ set(viewer_SOURCE_FILES
llpanelpicks.cpp
llpanelplace.cpp
llpanelplaceinfo.cpp
- llpanelshower.cpp
llpanelplaces.cpp
llpanelplacestab.cpp
+ llpanelprimmediacontrols.cpp
llpanelprofile.cpp
llpanelprofileview.cpp
+ llpanelshower.cpp
llpanelteleporthistory.cpp
llpanelvolume.cpp
llparcelselection.cpp
@@ -348,8 +347,8 @@ set(viewer_SOURCE_FILES
llplacesinventorybridge.cpp
llpolymesh.cpp
llpolymorph.cpp
- llpreviewanim.cpp
llpreview.cpp
+ llpreviewanim.cpp
llpreviewgesture.cpp
llpreviewnotecard.cpp
llpreviewscript.cpp
@@ -371,6 +370,7 @@ set(viewer_SOURCE_FILES
llsky.cpp
llslurl.cpp
llspatialpartition.cpp
+ llspeakers.cpp
llsplitbutton.cpp
llsprite.cpp
llstartup.cpp
@@ -397,10 +397,10 @@ set(viewer_SOURCE_FILES
lltoastimpanel.cpp
lltoastnotifypanel.cpp
lltoastpanel.cpp
+ lltool.cpp
lltoolbar.cpp
lltoolbrush.cpp
lltoolcomp.cpp
- lltool.cpp
lltooldraganddrop.cpp
lltoolface.cpp
lltoolfocus.cpp
@@ -424,6 +424,7 @@ set(viewer_SOURCE_FILES
llurl.cpp
llurldispatcher.cpp
llurlhistory.cpp
+ llurllineeditorctrl.cpp
llurlsimstring.cpp
llurlwhitelist.cpp
llvectorperfoptions.cpp
@@ -440,18 +441,18 @@ set(viewer_SOURCE_FILES
llviewerhelp.cpp
llviewerhelputil.cpp
llviewerinventory.cpp
- llviewerjointattachment.cpp
llviewerjoint.cpp
+ llviewerjointattachment.cpp
llviewerjointmesh.cpp
- llviewerjointmesh_sse2.cpp
llviewerjointmesh_sse.cpp
+ llviewerjointmesh_sse2.cpp
llviewerjointmesh_vec.cpp
llviewerjoystick.cpp
llviewerkeyboard.cpp
llviewerlayer.cpp
llviewermedia.cpp
- llviewermediafocus.cpp
llviewermedia_streamingaudio.cpp
+ llviewermediafocus.cpp
llviewermenu.cpp
llviewermenufile.cpp
llviewermessage.cpp
@@ -484,10 +485,11 @@ set(viewer_SOURCE_FILES
llvoclouds.cpp
llvograss.cpp
llvoground.cpp
+ llvoicechannel.cpp
llvoiceclient.cpp
+ llvoicecontrolpanel.cpp
llvoiceremotectrl.cpp
llvoicevisualizer.cpp
- llvoicecontrolpanel.cpp
llvoinventorylistener.cpp
llvopartgroup.cpp
llvosky.cpp
@@ -538,25 +540,25 @@ endif (LINUX)
set(viewer_HEADER_FILES
CMakeLists.txt
ViewerInstall.cmake
- llaccordionctrltab.h
llaccordionctrl.h
+ llaccordionctrltab.h
llagent.h
- llagentlistener.h
llagentaccess.h
llagentdata.h
llagentlanguage.h
+ llagentlistener.h
llagentpicksinfo.h
llagentpilot.h
llagentui.h
llagentwearables.h
llanimstatelabels.h
llappearance.h
+ llappearancemgr.h
llappviewer.h
llappviewerlistener.h
- llassetuploadresponders.h
llassetuploadqueue.h
+ llassetuploadresponders.h
llaudiosourcevo.h
- llappearancemgr.h
llavataractions.h
llavatariconctrl.h
llavatarlist.h
@@ -572,8 +574,8 @@ set(viewer_HEADER_FILES
llcaphttpsender.h
llchannelmanager.h
llchatbar.h
- llchatitemscontainerctrl.h
llchathistory.h
+ llchatitemscontainerctrl.h
llchatmsgbox.h
llchiclet.h
llclassifiedinfo.h
@@ -650,8 +652,6 @@ set(viewer_HEADER_FILES
llfloaterhandler.h
llfloaterhardwaresettings.h
llfloaterhelpbrowser.h
- llfloatermediabrowser.h
- llfloatermediasettings.h
llfloaterhud.h
llfloaterimagepreview.h
llfloaterinspect.h
@@ -661,16 +661,18 @@ set(viewer_HEADER_FILES
llfloaterland.h
llfloaterlandholdings.h
llfloatermap.h
+ llfloatermediabrowser.h
+ llfloatermediasettings.h
llfloatermemleak.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloateropenobject.h
llfloaterparcel.h
llfloaterpay.h
+ llfloaterperms.h
llfloaterpostcard.h
llfloaterpostprocess.h
llfloaterpreference.h
- llfloaterperms.h
llfloaterproperties.h
llfloaterregioninfo.h
llfloaterreporter.h
@@ -716,12 +718,12 @@ set(viewer_HEADER_FILES
llhudrender.h
llhudtext.h
llhudview.h
+ llimcontrolpanel.h
llimfloater.h
llimpanel.h
llimview.h
- llimcontrolpanel.h
- llinspectavatar.h
llinspect.h
+ llinspectavatar.h
llinspectgroup.h
llinspectobject.h
llinventorybridge.h
@@ -738,7 +740,6 @@ set(viewer_HEADER_FILES
lllocaltextureobject.h
lllocationhistory.h
lllocationinputctrl.h
- llurllineeditorctrl.h
lllogchat.h
llloginhandler.h
lllogininstance.h
@@ -747,6 +748,7 @@ set(viewer_HEADER_FILES
llmanipscale.h
llmaniptranslate.h
llmapresponders.h
+ llmediactrl.h
llmediadataclient.h
llmediaremotectrl.h
llmemoryview.h
@@ -786,8 +788,8 @@ set(viewer_HEADER_FILES
llpanelgrouplandmoney.h
llpanelgroupnotices.h
llpanelgrouproles.h
- llpanelinventory.h
llpanelimcontrolpanel.h
+ llpanelinventory.h
llpanelland.h
llpanellandaudio.h
llpanellandmarks.h
@@ -796,11 +798,10 @@ set(viewer_HEADER_FILES
llpanellookinfo.h
llpanellooks.h
llpanelmedia.h
- llpanelmediahud.h
- llpanelmeprofile.h
llpanelmediasettingsgeneral.h
- llpanelmediasettingssecurity.h
llpanelmediasettingspermissions.h
+ llpanelmediasettingssecurity.h
+ llpanelmeprofile.h
llpanelobject.h
llpanelpeople.h
llpanelpeoplemenus.h
@@ -809,11 +810,12 @@ set(viewer_HEADER_FILES
llpanelpicks.h
llpanelplace.h
llpanelplaceinfo.h
- llpanelshower.h
llpanelplaces.h
llpanelplacestab.h
+ llpanelprimmediacontrols.h
llpanelprofile.h
llpanelprofileview.h
+ llpanelshower.h
llpanelteleporthistory.h
llpanelvolume.h
llparcelselection.h
@@ -836,9 +838,9 @@ set(viewer_HEADER_FILES
llremoteparcelrequest.h
llresourcedata.h
llrootview.h
+ llsavedsettingsglue.h
llscreenchannel.h
llscrollingpanelparam.h
- llsavedsettingsglue.h
llsearchcombobox.h
llsearchhistory.h
llselectmgr.h
@@ -847,6 +849,7 @@ set(viewer_HEADER_FILES
llsky.h
llslurl.h
llspatialpartition.h
+ llspeakers.h
llsplitbutton.h
llsprite.h
llstartup.h
@@ -902,6 +905,7 @@ set(viewer_HEADER_FILES
llurl.h
llurldispatcher.h
llurlhistory.h
+ llurllineeditorctrl.h
llurlsimstring.h
llurlwhitelist.h
llvectorperfoptions.h
@@ -925,8 +929,8 @@ set(viewer_HEADER_FILES
llviewerkeyboard.h
llviewerlayer.h
llviewermedia.h
- llviewermediaobserver.h
llviewermediafocus.h
+ llviewermediaobserver.h
llviewermenu.h
llviewermenufile.h
llviewermessage.h
@@ -960,10 +964,11 @@ set(viewer_HEADER_FILES
llvoclouds.h
llvograss.h
llvoground.h
+ llvoicechannel.h
llvoiceclient.h
+ llvoicecontrolpanel.h
llvoiceremotectrl.h
llvoicevisualizer.h
- llvoicecontrolpanel.h
llvoinventorylistener.h
llvopartgroup.h
llvosky.h
@@ -981,7 +986,6 @@ set(viewer_HEADER_FILES
llwearabledictionary.h
llwearablelist.h
llweb.h
- llmediactrl.h
llwind.h
llwindebug.h
llwlanimator.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3682d48577..6bc95b9cdb 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7742,6 +7742,39 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>FriendsListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide online and all friends icons in the friend list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NearbyListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in nearby list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RecentListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in recent list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>FriendsSortOrder</key>
<map>
<key>Comment</key>
@@ -10460,6 +10493,17 @@
<key>Value</key>
<real>90.0</real>
</map>
+ <key>YouAreHereDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Radius of distance for banner that indicates if the resident is "on" the Place.(meters from avatar to requested place)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
<key>YieldTime</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index f3bfa37cea..c43ba27984 100644
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -5589,6 +5589,13 @@
</layer>
<layer
+ name="hair texture alpha layer"
+ visibility_mask="TRUE">
+ <texture
+ local_texture="hair_grain" />
+ </layer>
+
+ <layer
name="hair alpha"
visibility_mask="TRUE">
<texture
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index f62606cc50..75a72e5b17 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -42,7 +42,7 @@
#include "lldrawable.h"
#include "llfirstuse.h"
#include "llfloaterreg.h"
-#include "llfloateractivespeakers.h"
+#include "llspeakers.h"
#include "llfloatercamera.h"
#include "llfloatercustomize.h"
@@ -5391,12 +5391,6 @@ void update_group_floaters(const LLUUID& group_id)
//*TODO Implement group update for Profile View
// still actual as of July 31, 2009 (DZ)
- if (gIMMgr)
- {
- // update the talk view
- gIMMgr->refresh();
- }
-
gAgent.fireEvent(new LLOldEvents::LLEvent(&gAgent, "new group"), "");
}
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index 1a69f1d975..09f7c49f23 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -89,6 +89,11 @@ std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/)
return slurl;
}
+//static
+BOOL LLAgentUI::checkAgentDistance(const LLVector3& pole, F32 radius)
+{
+ return (gAgent.getPositionAgent() - pole).length() < radius;
+}
BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region)
{
LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h
index 47ecb04547..c7aafb71e7 100644
--- a/indra/newview/llagentui.h
+++ b/indra/newview/llagentui.h
@@ -52,6 +52,11 @@ public:
static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK);
//build location string using a region position of the avatar.
static BOOL buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region);
+ /**
+ * @brief Check whether the agent is in neighborhood of the pole Within same region
+ * @return true if the agent is in neighborhood.
+ */
+ static BOOL checkAgentDistance(const LLVector3& local_pole, F32 radius);
};
#endif //LLAGENTUI_H
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e184d99ffc..06c9171d67 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -49,7 +49,6 @@
#include "llviewerstats.h"
#include "llmd5.h"
#include "llpumpio.h"
-#include "llimpanel.h"
#include "llmimetypes.h"
#include "llslurl.h"
#include "llstartup.h"
@@ -76,6 +75,7 @@
#include "llteleporthistory.h"
#include "lllocationhistory.h"
#include "llfasttimerview.h"
+#include "llvoicechannel.h"
#include "llweb.h"
#include "llsecondlifeurls.h"
diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h
index 426fcec514..65b5c86ed5 100644
--- a/indra/newview/llavatariconctrl.h
+++ b/indra/newview/llavatariconctrl.h
@@ -103,6 +103,8 @@ public:
const std::string& getFirstName() const { return mFirstName; }
const std::string& getLastName() const { return mLastName; }
+ void setDrawTooltip(bool value) { mDrawTooltip = value;}
+
protected:
LLUUID mAvatarId;
std::string mFirstName;
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 3a07c6e5ef..e93d0dfa50 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -38,6 +38,7 @@
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcachename.h"
#include "llvoiceclient.h"
+#include "llviewercontrol.h" // for gSavedSettings
static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");
@@ -45,6 +46,21 @@ static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");
// Used to limit time spent for avatar list update per frame.
static const unsigned ADD_LIMIT = 50;
+void LLAvatarList::toggleIcons()
+{
+ // Save the new value for new items to use.
+ mShowIcons = !mShowIcons;
+ gSavedSettings.setBOOL(mIconParamName, mShowIcons);
+
+ // Show/hide icons for all existing items.
+ std::vector<LLPanel*> items;
+ getItems(items);
+ for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
+ {
+ static_cast<LLAvatarListItem*>(*it)->setAvatarIconVisible(mShowIcons);
+ }
+}
+
static bool findInsensitive(std::string haystack, const std::string& needle_upper)
{
LLStringUtil::toUpper(haystack);
@@ -73,13 +89,22 @@ LLAvatarList::LLAvatarList(const Params& p)
setComparator(&NAME_COMPARATOR);
}
+void LLAvatarList::setShowIcons(std::string param_name)
+{
+ mIconParamName= param_name;
+ mShowIcons = gSavedSettings.getBOOL(mIconParamName);
+}
+
// virtual
void LLAvatarList::draw()
{
- if (mDirty)
- refresh();
+ // *NOTE dzaporozhan
+ // Call refresh() after draw() to avoid flickering of avatar list items.
LLFlatListView::draw();
+
+ if (mDirty)
+ refresh();
}
void LLAvatarList::setNameFilter(const std::string& filter)
@@ -202,6 +227,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
item->setContextMenu(mContextMenu);
item->childSetVisible("info_btn", false);
+ item->setAvatarIconVisible(mShowIcons);
addItem(item, id, pos);
}
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index a83a72b26c..f60f1f00f3 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -70,7 +70,11 @@ public:
void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; }
+ void toggleIcons();
void sortByName();
+ void setShowIcons(std::string param_name);
+ bool getIconsVisible() const { return mShowIcons; }
+ const std::string getIconParamName() const{return mIconParamName;}
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
protected:
@@ -86,7 +90,9 @@ private:
bool mIgnoreOnlineStatus;
bool mDirty;
+ bool mShowIcons;
+ std::string mIconParamName;
std::string mNameFilter;
uuid_vector_t mIDs;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index ebc79aae48..4ecb9537ba 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -42,6 +42,7 @@
#include "llavatariconctrl.h"
#include "llbutton.h"
+S32 LLAvatarListItem::sIconWidth = 0;
LLAvatarListItem::LLAvatarListItem()
: LLPanel(),
@@ -55,6 +56,12 @@ LLAvatarListItem::LLAvatarListItem()
mOnlineStatus(E_UNKNOWN)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml");
+ // Remember avatar icon width including its padding from the name text box,
+ // so that we can hide and show the icon again later.
+ if (!sIconWidth)
+ {
+ sIconWidth = mAvatarName->getRect().mLeft - mAvatarIcon->getRect().mLeft;
+ }
}
LLAvatarListItem::~LLAvatarListItem()
@@ -188,6 +195,21 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes)
gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
}
+void LLAvatarListItem::setAvatarIconVisible(bool visible)
+{
+ // Already done? Then do nothing.
+ if (mAvatarIcon->getVisible() == (BOOL)visible)
+ return;
+
+ // Show/hide avatar icon.
+ mAvatarIcon->setVisible(visible);
+
+ // Move the avatar name horizontally by icon size + its distance from the avatar name.
+ LLRect name_rect = mAvatarName->getRect();
+ name_rect.mLeft += visible ? sIconWidth : -sIconWidth;
+ mAvatarName->setRect(name_rect);
+}
+
void LLAvatarListItem::onInfoBtnClick()
{
LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mAvatarId));
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index b9cfed4b7b..a8d3919217 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -64,6 +64,7 @@ public:
void setOnline(bool online);
void setName(const std::string& name);
void setAvatarId(const LLUUID& id, bool ignore_status_changes = false);
+ void setAvatarIconVisible(bool visible);
const LLUUID& getAvatarId() const;
const std::string getAvatarName() const;
@@ -87,7 +88,7 @@ private:
void onNameCache(const std::string& first_name, const std::string& last_name);
- LLAvatarIconCtrl*mAvatarIcon;
+ LLAvatarIconCtrl* mAvatarIcon;
LLTextBox* mAvatarName;
LLTextBox* mStatus;
@@ -98,6 +99,7 @@ private:
LLUUID mAvatarId;
EOnlineStatus mOnlineStatus;
+ static S32 sIconWidth; // icon width + padding
};
#endif //LL_LLAVATARLISTITEM_H
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 77f941eef0..6427422572 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -40,6 +40,8 @@
#include "llbottomtray.h"
#include "llviewerwindow.h"
#include "llrootview.h"
+#include "llsyswellwindow.h"
+#include "llfloaterreg.h"
#include <algorithm>
@@ -128,7 +130,7 @@ void LLChannelManager::onLoginCompleted()
S32 channel_right_bound = gViewerWindow->getWorldViewRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setShowToasts(true);
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLSysWellWindow::onStartUpToastClick, LLFloaterReg::getTypedInstance<LLSysWellWindow>("syswell_window"), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 94058365be..aaca568320 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -38,9 +38,215 @@
#include "llscrollcontainer.h"
#include "llavatariconctrl.h"
+#include "llimview.h"
+#include "llcallingcard.h" //for LLAvatarTracker
+#include "llagentdata.h"
+#include "llavataractions.h"
+#include "lltrans.h"
+
static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");
static const std::string MESSAGE_USERNAME_DATE_SEPARATOR(" ----- ");
+std::string formatCurrentTime()
+{
+ time_t utc_time;
+ utc_time = time_corrected();
+ std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:["
+ +LLTrans::getString("TimeMin")+"] ";
+
+ LLSD substitution;
+
+ substitution["datetime"] = (S32) utc_time;
+ LLStringUtil::format (timeStr, substitution);
+
+ return timeStr;
+}
+
+class LLChatHistoryHeader: public LLPanel
+{
+public:
+ static LLChatHistoryHeader* createInstance(const std::string& file_name)
+ {
+ LLChatHistoryHeader* pInstance = new LLChatHistoryHeader;
+ LLUICtrlFactory::getInstance()->buildPanel(pInstance, file_name);
+ return pInstance;
+ }
+
+ BOOL handleMouseUp(S32 x, S32 y, MASK mask)
+ {
+ return LLPanel::handleMouseUp(x,y,mask);
+ }
+
+ void onAvatarIconContextMenuItemClicked(const LLSD& userdata)
+ {
+ std::string level = userdata.asString();
+
+ if (level == "profile")
+ {
+ LLAvatarActions::showProfile(getAvatarId());
+ }
+ else if (level == "im")
+ {
+ LLAvatarActions::startIM(getAvatarId());
+ }
+ else if (level == "add")
+ {
+ std::string name;
+ name.assign(getFirstName());
+ name.append(" ");
+ name.append(getLastName());
+
+ LLAvatarActions::requestFriendshipDialog(getAvatarId(), name);
+ }
+ else if (level == "remove")
+ {
+ LLAvatarActions::removeFriendDialog(getAvatarId());
+ }
+ }
+
+ BOOL postBuild()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2));
+
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+
+ mPopupMenuHandleAvatar = menu->getHandle();
+
+ return LLPanel::postBuild();
+ }
+
+ bool pointInChild(const std::string& name,S32 x,S32 y)
+ {
+ LLUICtrl* child = findChild<LLUICtrl>(name);
+ if(!child)
+ return false;
+
+ LLView* parent = child->getParent();
+ if(parent!=this)
+ {
+ x-=parent->getRect().mLeft;
+ y-=parent->getRect().mBottom;
+ }
+
+ S32 local_x = x - child->getRect().mLeft ;
+ S32 local_y = y - child->getRect().mBottom ;
+ return child->pointInView(local_x, local_y);
+ }
+
+ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask)
+ {
+ if(pointInChild("avatar_icon",x,y) || pointInChild("user_name",x,y))
+ {
+ showContextMenu(x,y);
+ return TRUE;
+ }
+
+ return LLPanel::handleRightMouseDown(x,y,mask);
+ }
+ const LLUUID& getAvatarId () const { return mAvatarID;}
+ const std::string& getFirstName() const { return mFirstName; }
+ const std::string& getLastName () const { return mLastName; }
+
+ void setup(const LLChat& chat)
+ {
+ mAvatarID = chat.mFromID;
+ mSourceType = chat.mSourceType;
+ gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4));
+ if(chat.mFromID.isNull())
+ {
+ mSourceType = CHAT_SOURCE_SYSTEM;
+ }
+
+
+ LLTextBox* userName = getChild<LLTextBox>("user_name");
+
+ if(!chat.mFromName.empty())
+ userName->setValue(chat.mFromName);
+ else
+ {
+ std::string SL = LLTrans::getString("SECOND_LIFE");
+ userName->setValue(SL);
+ }
+
+ LLTextBox* timeBox = getChild<LLTextBox>("time_box");
+ timeBox->setValue(formatCurrentTime());
+
+ LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
+
+ if(mSourceType != CHAT_SOURCE_AGENT)
+ icon->setDrawTooltip(false);
+
+ if(!chat.mFromID.isNull())
+ {
+ icon->setValue(chat.mFromID);
+ }
+
+ }
+
+ void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group)
+ {
+ if (id != mAvatarID)
+ return;
+ mFirstName = first;
+ mLastName = last;
+ }
+protected:
+ void showContextMenu(S32 x,S32 y)
+ {
+ if(mSourceType == CHAT_SOURCE_SYSTEM)
+ showSystemContextMenu(x,y);
+ if(mSourceType == CHAT_SOURCE_AGENT)
+ showAvatarContextMenu(x,y);
+ if(mSourceType == CHAT_SOURCE_OBJECT)
+ showObjectContextMenu(x,y);
+ }
+
+ void showSystemContextMenu(S32 x,S32 y)
+ {
+ }
+ void showObjectContextMenu(S32 x,S32 y)
+ {
+ }
+
+ void showAvatarContextMenu(S32 x,S32 y)
+ {
+ LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get();
+
+ if(menu)
+ {
+ bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL;
+
+ menu->setItemEnabled("Add Friend", !is_friend);
+ menu->setItemEnabled("Remove Friend", is_friend);
+
+ if(gAgentID == mAvatarID)
+ {
+ menu->setItemEnabled("Add Friend", false);
+ menu->setItemEnabled("Send IM", false);
+ menu->setItemEnabled("Remove Friend", false);
+ }
+
+ menu->buildDrawLabels();
+ menu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(this, menu, x, y);
+ }
+ }
+
+
+
+protected:
+ LLHandle<LLView> mPopupMenuHandleAvatar;
+
+ LLUUID mAvatarID;
+ EChatSourceType mSourceType;
+ std::string mFirstName;
+ std::string mLastName;
+
+};
+
+
LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
: LLTextEditor(p),
mMessageHeaderFilename(p.message_header),
@@ -48,7 +254,7 @@ mMessageSeparatorFilename(p.message_separator),
mLeftTextPad(p.left_text_pad),
mRightTextPad(p.right_text_pad),
mLeftWidgetPad(p.left_widget_pad),
-mRightWidgetPad(p.rigth_widget_pad)
+mRightWidgetPad(p.right_widget_pad)
{
}
@@ -78,50 +284,49 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
-LLView* LLChatHistory::getHeader(const LLUUID& avatar_id, std::string& from, std::string& time)
+LLView* LLChatHistory::getHeader(const LLChat& chat)
{
- LLPanel* header = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageHeaderFilename, NULL, LLPanel::child_registry_t::instance());
- LLTextBox* userName = header->getChild<LLTextBox>("user_name");
- userName->setValue(from);
- LLTextBox* timeBox = header->getChild<LLTextBox>("time_box");
- timeBox->setValue(time);
- if(!avatar_id.isNull())
- {
- LLAvatarIconCtrl* icon = header->getChild<LLAvatarIconCtrl>("avatar_icon");
- icon->setValue(avatar_id);
- }
+ LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
+ header->setup(chat);
return header;
}
-void LLChatHistory::appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params)
+void LLChatHistory::appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params)
{
LLView* view = NULL;
std::string view_text;
- if (mLastFromName == from)
+ if (mLastFromName == chat.mFromName)
{
view = getSeparator();
view_text = "\n";
}
else
{
- view = getHeader(avatar_id, from, time);
- view_text = from + MESSAGE_USERNAME_DATE_SEPARATOR + time + '\n';
+ view = getHeader(chat);
+ view_text = chat.mFromName + MESSAGE_USERNAME_DATE_SEPARATOR + formatCurrentTime() + '\n';
}
//Prepare the rect for the view
LLRect target_rect = getDocumentView()->getRect();
- target_rect.mLeft += mLeftWidgetPad;
+ // squeeze down the widget by subtracting padding off left and right
+ target_rect.mLeft += mLeftWidgetPad + mHPad;
target_rect.mRight -= mRightWidgetPad;
view->reshape(target_rect.getWidth(), view->getRect().getHeight());
view->setOrigin(target_rect.mLeft, view->getRect().mBottom);
- appendWidget(view, view_text, FALSE, TRUE, mLeftWidgetPad, 0);
+ LLInlineViewSegment::Params p;
+ p.view = view;
+ p.force_newline = true;
+ p.left_pad = mLeftWidgetPad;
+ p.right_pad = mRightWidgetPad;
+
+ appendWidget(p, view_text, false);
//Append the text message
- message += '\n';
+ std::string message = chat.mText + '\n';
appendText(message, FALSE, style_params);
- mLastFromName = from;
+ mLastFromName = chat.mFromName;
blockUndo();
setCursorAndScrollToEnd();
}
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index d6eccf896a..92dcfdd958 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -34,6 +34,7 @@
#define LLCHATHISTORY_H_
#include "lltexteditor.h"
+#include "llchat.h"
//Chat log widget allowing addition of a message as a widget
class LLChatHistory : public LLTextEditor
@@ -52,7 +53,7 @@ class LLChatHistory : public LLTextEditor
//Widget left padding from the scroll rect
Optional<S32> left_widget_pad;
//Widget right padding from the scroll rect
- Optional<S32> rigth_widget_pad;
+ Optional<S32> right_widget_pad;
Params()
: message_header("message_header"),
@@ -60,7 +61,7 @@ class LLChatHistory : public LLTextEditor
left_text_pad("left_text_pad"),
right_text_pad("right_text_pad"),
left_widget_pad("left_widget_pad"),
- rigth_widget_pad("rigth_widget_pad")
+ right_widget_pad("right_widget_pad")
{
}
@@ -85,7 +86,7 @@ class LLChatHistory : public LLTextEditor
* @param time time of a message.
* @return pointer to LLView header object.
*/
- LLView* getHeader(const LLUUID& avatar_id, std::string& from, std::string& time);
+ LLView* getHeader(const LLChat& chat);
public:
~LLChatHistory();
@@ -94,11 +95,11 @@ class LLChatHistory : public LLTextEditor
* Appends a widget message.
* If last user appended message, concurs with current user,
* separator is added before the message, otherwise header is added.
- * @param from owner of a message.
+ * @param chat - base chat message.
* @param time time of a message.
* @param message message itself.
*/
- void appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params);
+ void appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params);
private:
std::string mLastFromName;
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 3b5b7f570e..a6afbc05be 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -503,13 +503,15 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con
return;
}
+ LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item);
+
if (dest)
{
- insertBeforeItem(mItems, dest->getLandmarkId(), item->getUUID());
+ insertBeforeItem(mItems, dest->getLandmarkId(), viewer_item);
}
else
{
- mItems.push_back(gInventory.getItem(item->getUUID()));
+ mItems.push_back(viewer_item);
}
int sortField = 0;
@@ -534,13 +536,22 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con
}
}
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- favorites_id,
- std::string(),
- cb);
+ LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance();
+ if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD)
+ {
+ viewer_item->setType(LLAssetType::AT_FAVORITE);
+ copy_inventory_from_notecard(tool_dad->getObjectID(), tool_dad->getSourceID(), viewer_item.get(), gInventoryCallbacks.registerCB(cb));
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ favorites_id,
+ std::string(),
+ cb);
+ }
llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;
}
@@ -1263,10 +1274,9 @@ void LLFavoritesBarCtrl::updateItemsOrder(LLInventoryModel::item_array_t& items,
items.insert(findItemByUUID(items, destItem->getUUID()), srcItem);
}
-void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId)
+void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem)
{
LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId);
- LLViewerInventoryItem* insertedItem = gInventory.getItem(insertedItemId);
items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem);
}
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index ea2a3d08e2..e90d13f9d5 100644
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -141,7 +141,7 @@ private:
* inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId.
* this function assumes that an item identified by insertedItemId doesn't exist in items array.
*/
- void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId);
+ void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem);
// finds an item by it's UUID in the items array
LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id);
diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp
index dea656b0e4..fbf09207fe 100644
--- a/indra/newview/llfloaterchatterbox.cpp
+++ b/indra/newview/llfloaterchatterbox.cpp
@@ -42,7 +42,7 @@
#include "llfloaterfriends.h"
#include "llfloatergroups.h"
#include "llviewercontrol.h"
-#include "llimview.h"
+#include "llvoicechannel.h"
#include "llimpanel.h"
//
diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp
index c890f9f122..a47916b7d7 100644
--- a/indra/newview/llfloaterinventory.cpp
+++ b/indra/newview/llfloaterinventory.cpp
@@ -1438,7 +1438,11 @@ void LLInventoryPanel::modelChanged(U32 mask)
}
LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID());
- if (view_item->getParentFolder() != new_parent)
+
+ // added check against NULL for cases when Inventory panel contains startFolder.
+ // in this case parent is LLFolderView (LLInventoryPanel::mFolders) itself.
+ // this check is a fix for bug EXT-1859.
+ if (NULL != new_parent && view_item->getParentFolder() != new_parent)
{
view_item->getParentFolder()->extractItem(view_item);
view_item->addToFolder(new_parent, mFolders);
diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp
index b64257b11d..aca9198f59 100644
--- a/indra/newview/llfloatervoicedevicesettings.cpp
+++ b/indra/newview/llfloatervoicedevicesettings.cpp
@@ -43,7 +43,7 @@
#include "llsliderctrl.h"
#include "llviewercontrol.h"
#include "llvoiceclient.h"
-#include "llimpanel.h"
+#include "llvoicechannel.h"
// Library includes (after viewer)
#include "lluictrlfactory.h"
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index a20b5ea66c..b86795f696 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -42,7 +42,6 @@
#include "llchiclet.h"
#include "llfloaterchat.h"
#include "llfloaterreg.h"
-#include "llimview.h"
#include "lllineeditor.h"
#include "lllogchat.h"
#include "llpanelimcontrolpanel.h"
@@ -50,6 +49,7 @@
#include "lltrans.h"
#include "llchathistory.h"
#include "llviewerwindow.h"
+#include "llvoicechannel.h"
#include "lltransientfloatermgr.h"
@@ -61,7 +61,14 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)
mLastMessageIndex(-1),
mDialog(IM_NOTHING_SPECIAL),
mChatHistory(NULL),
- mInputEditor(NULL),
+ mInputEditor(NULL),
+ mSavedTitle(),
+ mTypingStart(),
+ mShouldSendTypingState(false),
+ mMeTyping(false),
+ mOtherTyping(false),
+ mTypingTimer(),
+ mTypingTimeoutTimer(),
mPositioned(false),
mSessionInitialized(false)
{
@@ -71,12 +78,15 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)
mSessionInitialized = im_session->mSessionInitialized;
mDialog = im_session->mType;
- if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog)
- {
+ switch(mDialog){
+ case IM_NOTHING_SPECIAL:
+ case IM_SESSION_P2P_INVITE:
mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this);
- }
- else
- {
+ break;
+ case IM_SESSION_CONFERENCE_START:
+ mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelAdHocControl, this);
+ break;
+ default:
mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this);
}
}
@@ -95,6 +105,7 @@ void LLIMFloater::onFocusReceived()
// virtual
void LLIMFloater::onClose(bool app_quitting)
{
+ setTyping(false);
gIMMgr->leaveSession(mSessionID);
}
@@ -141,6 +152,7 @@ void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata )
{
LLIMFloater* self = (LLIMFloater*) userdata;
self->sendMsg();
+ self->setTyping(false);
}
void LLIMFloater::sendMsg()
@@ -193,9 +205,10 @@ BOOL LLIMFloater::postBuild()
if (other_party_id.notNull())
{
mOtherParticipantUUID = other_party_id;
- mControlPanel->setID(mOtherParticipantUUID);
}
+ mControlPanel->setSessionId(mSessionID);
+
LLButton* slide_left = getChild<LLButton>("slide_left_btn");
slide_left->setVisible(mControlPanel->getVisible());
slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this));
@@ -228,12 +241,37 @@ BOOL LLIMFloater::postBuild()
LLLogChat::loadHistory(getTitle(), &chatFromLogFile, (void *)this);
}
+ mTypingStart = LLTrans::getString("IM_typing_start_string");
+
+ // Disable input editor if session cannot accept text
+ LLIMModel::LLIMSession* im_session =
+ LLIMModel::instance().findIMSession(mSessionID);
+ if( im_session && !im_session->mTextIMPossible )
+ {
+ mInputEditor->setEnabled(FALSE);
+ mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label"));
+ }
+
//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"
//see LLFloaterIMPanel for how it is done (IB)
return LLDockableFloater::postBuild();
}
+// virtual
+void LLIMFloater::draw()
+{
+ if ( mMeTyping )
+ {
+ // Time out if user hasn't typed for a while.
+ if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS )
+ {
+ setTyping(false);
+ }
+ }
+
+ LLFloater::draw();
+}
// static
@@ -255,6 +293,15 @@ void* LLIMFloater::createPanelGroupControl(void* userdata)
return self->mControlPanel;
}
+// static
+void* LLIMFloater::createPanelAdHocControl(void* userdata)
+{
+ LLIMFloater *self = (LLIMFloater*)userdata;
+ self->mControlPanel = new LLPanelAdHocControlPanel(self->mSessionID);
+ self->mControlPanel->setXMLFilename("panel_adhoc_control_panel.xml");
+ return self->mControlPanel;
+}
+
void LLIMFloater::onSlide()
{
LLPanel* im_control_panel = getChild<LLPanel>("panel_im_control_panel");
@@ -379,10 +426,12 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
{
mSessionInitialized = true;
+ //will be different only for an ad-hoc im session
if (mSessionID != im_session_id)
{
mSessionID = im_session_id;
setKey(im_session_id);
+ mControlPanel->setSessionId(im_session_id);
}
//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB)
@@ -402,7 +451,8 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
void LLIMFloater::updateMessages()
{
- std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1);
+ std::list<LLSD> messages;
+ LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);
std::string agent_name;
gCacheName->getFullName(gAgentID, agent_name);
@@ -428,7 +478,11 @@ void LLIMFloater::updateMessages()
if (from == agent_name)
from = LLTrans::getString("You");
- mChatHistory->appendWidgetMessage(from_id, from, time, message, style_params);
+ LLChat chat(message);
+ chat.mFromID = from_id;
+ chat.mFromName = from;
+
+ mChatHistory->appendWidgetMessage(chat, style_params);
mLastMessageIndex = msg["index"].asInteger();
}
@@ -440,9 +494,14 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*
{
LLIMFloater* self= (LLIMFloater*) userdata;
- //in disconnected state IM input editor should be disabled
- self->mInputEditor->setEnabled(!gDisconnected);
-
+ // Allow enabling the LLIMFloater input editor only if session can accept text
+ LLIMModel::LLIMSession* im_session =
+ LLIMModel::instance().findIMSession(self->mSessionID);
+ if( im_session && im_session->mTextIMPossible )
+ {
+ //in disconnected state IM input editor should be disabled
+ self->mInputEditor->setEnabled(!gDisconnected);
+ }
self->mChatHistory->setCursorAndScrollToEnd();
}
@@ -450,7 +509,7 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*
void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)
{
LLIMFloater* self = (LLIMFloater*) userdata;
- self->setTyping(FALSE);
+ self->setTyping(false);
}
// static
@@ -460,19 +519,142 @@ void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata)
std::string text = self->mInputEditor->getText();
if (!text.empty())
{
- self->setTyping(TRUE);
+ self->setTyping(true);
}
else
{
// Deleting all text counts as stopping typing.
- self->setTyping(FALSE);
+ self->setTyping(false);
}
}
+void LLIMFloater::setTyping(bool typing)
+{
+ if ( typing )
+ {
+ // Started or proceeded typing, reset the typing timeout timer
+ mTypingTimeoutTimer.reset();
+ }
+
+ if ( mMeTyping != typing )
+ {
+ // Typing state is changed
+ mMeTyping = typing;
+ // So, should send current state
+ mShouldSendTypingState = true;
+ // In case typing is started, send state after some delay
+ mTypingTimer.reset();
+ }
+
+ // Don't want to send typing indicators to multiple people, potentially too
+ // much network traffic. Only send in person-to-person IMs.
+ if ( mShouldSendTypingState && mDialog == IM_NOTHING_SPECIAL )
+ {
+ if ( mMeTyping )
+ {
+ if ( mTypingTimer.getElapsedTimeF32() > 1.f )
+ {
+ // Still typing, send 'start typing' notification
+ LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, TRUE);
+ mShouldSendTypingState = false;
+ }
+ }
+ else
+ {
+ // Send 'stop typing' notification immediately
+ LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, FALSE);
+ mShouldSendTypingState = false;
+ }
+ }
-//just a stub for now
-void LLIMFloater::setTyping(BOOL typing)
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE);
+
+}
+
+void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing)
+{
+ if ( typing )
+ {
+ // other user started typing
+ addTypingIndicator(im_info);
+ }
+ else
+ {
+ // other user stopped typing
+ removeTypingIndicator(im_info);
+ }
+}
+
+void LLIMFloater::processSessionUpdate(const LLSD& session_update)
+{
+ // *TODO : verify following code when moderated mode will be implemented
+ if ( false && session_update.has("moderated_mode") &&
+ session_update["moderated_mode"].has("voice") )
+ {
+ BOOL voice_moderated = session_update["moderated_mode"]["voice"];
+ const std::string session_label = LLIMModel::instance().getName(mSessionID);
+
+ if (voice_moderated)
+ {
+ setTitle(session_label + std::string(" ") + LLTrans::getString("IM_moderated_chat_label"));
+ }
+ else
+ {
+ setTitle(session_label);
+ }
+
+ // *TODO : uncomment this when/if LLPanelActiveSpeakers panel will be added
+ //update the speakers dropdown too
+ //mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated);
+ }
+}
+
+void LLIMFloater::addTypingIndicator(const LLIMInfo* im_info)
{
+ // We may have lost a "stop-typing" packet, don't add it twice
+ if ( im_info && !mOtherTyping )
+ {
+ mOtherTyping = true;
+
+ // Create typing is started title string
+ LLUIString typing_start(mTypingStart);
+ typing_start.setArg("[NAME]", im_info->mName);
+
+ // Save and set new title
+ mSavedTitle = getTitle();
+ setTitle (typing_start);
+
+ // Update speaker
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if ( speaker_mgr )
+ {
+ speaker_mgr->setSpeakerTyping(im_info->mFromID, TRUE);
+ }
+ }
+}
+
+void LLIMFloater::removeTypingIndicator(const LLIMInfo* im_info)
+{
+ if ( mOtherTyping )
+ {
+ mOtherTyping = false;
+
+ // Revert the title to saved one
+ setTitle(mSavedTitle);
+
+ if ( im_info )
+ {
+ // Update speaker
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if ( speaker_mgr )
+ {
+ speaker_mgr->setSpeakerTyping(im_info->mFromID, FALSE);
+ }
+ }
+
+ }
}
void LLIMFloater::chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata)
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 99810b6d6d..3da27ac941 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -55,6 +55,8 @@ public:
// LLView overrides
/*virtual*/ BOOL postBuild();
/*virtual*/ void setVisible(BOOL visible);
+ // Check typing timeout timer.
+ /*virtual*/ void draw();
// LLFloater overrides
/*virtual*/ void onClose(bool app_quitting);
@@ -85,6 +87,8 @@ public:
void setPositioned(bool b) { mPositioned = b; };
void onVisibilityChange(const LLSD& new_visibility);
+ void processIMTyping(const LLIMInfo* im_info, BOOL typing);
+ void processSessionUpdate(const LLSD& session_update);
private:
// process focus events to set a currently active session
@@ -94,15 +98,21 @@ private:
static void onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata );
static void onInputEditorFocusLost(LLFocusableElement* caller, void* userdata);
static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata);
- void setTyping(BOOL typing);
+ void setTyping(bool typing);
void onSlide();
static void* createPanelIMControl(void* userdata);
static void* createPanelGroupControl(void* userdata);
+ static void* createPanelAdHocControl(void* userdata);
// gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111)
void getAllowedRect(LLRect& rect);
static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata);
+ // Add the "User is typing..." indicator.
+ void addTypingIndicator(const LLIMInfo* im_info);
+
+ // Remove the "User is typing..." indicator.
+ void removeTypingIndicator(const LLIMInfo* im_info = NULL);
LLPanelChatControlPanel* mControlPanel;
LLUUID mSessionID;
@@ -114,6 +124,14 @@ private:
LLLineEditor* mInputEditor;
bool mPositioned;
+ std::string mSavedTitle;
+ LLUIString mTypingStart;
+ bool mMeTyping;
+ bool mOtherTyping;
+ bool mShouldSendTypingState;
+ LLFrameTimer mTypingTimer;
+ LLFrameTimer mTypingTimeoutTimer;
+
bool mSessionInitialized;
LLSD mQueuedMsgsForInit;
};
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 163984f740..77ee90f681 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -54,6 +54,7 @@
#include "llconsole.h"
#include "llgroupactions.h"
#include "llfloater.h"
+#include "llfloateractivespeakers.h"
#include "llfloatercall.h"
#include "llavataractions.h"
#include "llimview.h"
@@ -77,6 +78,7 @@
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
+#include "llvoicechannel.h"
#include "lllogchat.h"
#include "llweb.h"
#include "llhttpclient.h"
@@ -90,7 +92,6 @@
const S32 LINE_HEIGHT = 16;
const S32 MIN_WIDTH = 200;
const S32 MIN_HEIGHT = 130;
-const U32 DEFAULT_RETRIES_COUNT = 3;
//
// Statics
@@ -100,831 +101,6 @@ static std::string sTitleString = "Instant Message with [NAME]";
static std::string sTypingStartString = "[NAME]: ...";
static std::string sSessionStartString = "Starting session with [NAME] please wait.";
-LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
-LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
-LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
-LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
-
-BOOL LLVoiceChannel::sSuspended = FALSE;
-
-
-
-class LLVoiceCallCapResponder : public LLHTTPClient::Responder
-{
-public:
- LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
-
- virtual void error(U32 status, const std::string& reason); // called with bad status codes
- virtual void result(const LLSD& content);
-
-private:
- LLUUID mSessionID;
-};
-
-
-void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
-{
- llwarns << "LLVoiceCallCapResponder::error("
- << status << ": " << reason << ")"
- << llendl;
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
- if ( channelp )
- {
- if ( 403 == status )
- {
- //403 == no ability
- LLNotifications::instance().add(
- "VoiceNotAllowed",
- channelp->getNotifyArgs());
- }
- else
- {
- LLNotifications::instance().add(
- "VoiceCallGenericError",
- channelp->getNotifyArgs());
- }
- channelp->deactivate();
- }
-}
-
-void LLVoiceCallCapResponder::result(const LLSD& content)
-{
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
- if (channelp)
- {
- //*TODO: DEBUG SPAM
- LLSD::map_const_iterator iter;
- for(iter = content.beginMap(); iter != content.endMap(); ++iter)
- {
- llinfos << "LLVoiceCallCapResponder::result got "
- << iter->first << llendl;
- }
-
- channelp->setChannelInfo(
- content["voice_credentials"]["channel_uri"].asString(),
- content["voice_credentials"]["channel_credentials"].asString());
- }
-}
-
-//
-// LLVoiceChannel
-//
-LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
- mSessionID(session_id),
- mState(STATE_NO_CHANNEL_INFO),
- mSessionName(session_name),
- mIgnoreNextSessionLeave(FALSE)
-{
- mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
-
- if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
- {
- // 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;
- }
-
- LLVoiceClient::getInstance()->addObserver(this);
-}
-
-LLVoiceChannel::~LLVoiceChannel()
-{
- // Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
- if(gVoiceClient)
- {
- gVoiceClient->removeObserver(this);
- }
-
- sVoiceChannelMap.erase(mSessionID);
- sVoiceChannelURIMap.erase(mURI);
-}
-
-void LLVoiceChannel::setChannelInfo(
- const std::string& uri,
- const std::string& credentials)
-{
- setURI(uri);
-
- mCredentials = credentials;
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- if (mURI.empty())
- {
- LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty URI for channel " << mSessionName << llendl;
- deactivate();
- }
- else if (mCredentials.empty())
- {
- LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty credentials for channel " << mSessionName << llendl;
- deactivate();
- }
- else
- {
- setState(STATE_READY);
-
- // if we are supposed to be active, reconnect
- // this will happen on initial connect, as we request credentials on first use
- if (sCurrentVoiceChannel == this)
- {
- // just in case we got new channel info while active
- // should move over to new channel
- activate();
- }
- }
- }
-}
-
-void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
-{
- if (channelURI != mURI)
- {
- return;
- }
-
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
-}
-
-void LLVoiceChannel::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_LOGIN_RETRY:
- //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
- LLNotifications::instance().add("VoiceLoginRetry");
- break;
- case STATUS_LOGGED_IN:
- //if (!mLoginNotificationHandle.isDead())
- //{
- // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
- // if (notifyp)
- // {
- // notifyp->close();
- // }
- // mLoginNotificationHandle.markDead();
- //}
- break;
- case STATUS_LEFT_CHANNEL:
- if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
- {
- // if forceably removed from channel
- // update the UI and revert to default channel
- LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs);
- deactivate();
- }
- mIgnoreNextSessionLeave = FALSE;
- break;
- case STATUS_JOINING:
- if (callStarted())
- {
- setState(STATE_RINGING);
- }
- break;
- case STATUS_JOINED:
- if (callStarted())
- {
- setState(STATE_CONNECTED);
- }
- default:
- break;
- }
-}
-
-// default behavior is to just deactivate channel
-// derived classes provide specific error messages
-void LLVoiceChannel::handleError(EStatusType type)
-{
- deactivate();
- setState(STATE_ERROR);
-}
-
-BOOL LLVoiceChannel::isActive()
-{
- // only considered active when currently bound channel matches what our channel
- return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
-}
-
-BOOL LLVoiceChannel::callStarted()
-{
- return mState >= STATE_CALL_STARTED;
-}
-
-void LLVoiceChannel::deactivate()
-{
- if (mState >= STATE_RINGING)
- {
- // ignore session leave event
- mIgnoreNextSessionLeave = TRUE;
- }
-
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- // mute the microphone if required when returning to the proximal channel
- if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this)
- {
- gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
- }
- }
-
- if (sCurrentVoiceChannel == this)
- {
- // default channel is proximal channel
- sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
- sCurrentVoiceChannel->activate();
- }
-}
-
-void LLVoiceChannel::activate()
-{
- if (callStarted())
- {
- return;
- }
-
- // deactivate old channel and mark ourselves as the active one
- if (sCurrentVoiceChannel != this)
- {
- // mark as current before deactivating the old channel to prevent
- // activating the proximal channel between IM calls
- LLVoiceChannel* old_channel = sCurrentVoiceChannel;
- sCurrentVoiceChannel = this;
- if (old_channel)
- {
- old_channel->deactivate();
- }
- }
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- // responsible for setting status to active
- getChannelInfo();
- }
- else
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-void LLVoiceChannel::getChannelInfo()
-{
- // pretend we have everything we need
- if (sCurrentVoiceChannel == this)
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-//static
-LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
-{
- voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
- if (found_it == sVoiceChannelMap.end())
- {
- return NULL;
- }
- else
- {
- return found_it->second;
- }
-}
-
-//static
-LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
-{
- voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
- if (found_it == sVoiceChannelURIMap.end())
- {
- return NULL;
- }
- else
- {
- return found_it->second;
- }
-}
-
-void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
-{
- sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
- mSessionID = new_session_id;
- sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
-}
-
-void LLVoiceChannel::setURI(std::string uri)
-{
- sVoiceChannelURIMap.erase(mURI);
- mURI = uri;
- sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
-}
-
-void LLVoiceChannel::setState(EState state)
-{
- switch(state)
- {
- case STATE_RINGING:
- gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- break;
- case STATE_CONNECTED:
- gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs);
- break;
- case STATE_HUNG_UP:
- gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
- break;
- default:
- break;
- }
-
- mState = state;
-}
-
-void LLVoiceChannel::toggleCallWindowIfNeeded(EState state)
-{
- if (state == STATE_CONNECTED)
- {
- LLFloaterReg::showInstance("voice_call", mSessionID);
- }
- // By checking that current state is CONNECTED we make sure that the call window
- // has been shown, hence there's something to hide. This helps when user presses
- // the "End call" button right after initiating the call.
- // *TODO: move this check to LLFloaterCall?
- else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED)
- {
- LLFloaterReg::hideInstance("voice_call", mSessionID);
- }
-}
-
-//static
-void LLVoiceChannel::initClass()
-{
- sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
-}
-
-
-//static
-void LLVoiceChannel::suspend()
-{
- if (!sSuspended)
- {
- sSuspendedVoiceChannel = sCurrentVoiceChannel;
- sSuspended = TRUE;
- }
-}
-
-//static
-void LLVoiceChannel::resume()
-{
- if (sSuspended)
- {
- if (gVoiceClient->voiceEnabled())
- {
- if (sSuspendedVoiceChannel)
- {
- sSuspendedVoiceChannel->activate();
- }
- else
- {
- LLVoiceChannelProximal::getInstance()->activate();
- }
- }
- sSuspended = FALSE;
- }
-}
-
-
-//
-// LLVoiceChannelGroup
-//
-
-LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
- LLVoiceChannel(session_id, session_name)
-{
- mRetries = DEFAULT_RETRIES_COUNT;
- mIsRetrying = FALSE;
-}
-
-void LLVoiceChannelGroup::deactivate()
-{
- if (callStarted())
- {
- LLVoiceClient::getInstance()->leaveNonSpatialChannel();
- }
- LLVoiceChannel::deactivate();
-}
-
-void LLVoiceChannelGroup::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // we have the channel info, just need to use it now
- LLVoiceClient::getInstance()->setNonSpatialChannel(
- mURI,
- mCredentials);
-
-#if 0 // *TODO
- if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel
- {
- // Add the party to the list of people with which we've recently interacted.
- for (/*people in the chat*/)
- LLRecentPeople::instance().add(buddy_id);
- }
-#endif
- }
-}
-
-void LLVoiceChannelGroup::getChannelInfo()
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- std::string url = region->getCapability("ChatSessionRequest");
- LLSD data;
- data["method"] = "call";
- data["session-id"] = mSessionID;
- LLHTTPClient::post(url,
- data,
- new LLVoiceCallCapResponder(mSessionID));
- }
-}
-
-void LLVoiceChannelGroup::setChannelInfo(
- const std::string& uri,
- const std::string& credentials)
-{
- setURI(uri);
-
- mCredentials = credentials;
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- if(!mURI.empty() && !mCredentials.empty())
- {
- setState(STATE_READY);
-
- // if we are supposed to be active, reconnect
- // this will happen on initial connect, as we request credentials on first use
- if (sCurrentVoiceChannel == this)
- {
- // just in case we got new channel info while active
- // should move over to new channel
- activate();
- }
- }
- else
- {
- //*TODO: notify user
- llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
- deactivate();
- }
- }
- else if ( mIsRetrying )
- {
- // we have the channel info, just need to use it now
- LLVoiceClient::getInstance()->setNonSpatialChannel(
- mURI,
- mCredentials);
- }
-}
-
-void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_JOINED:
- mRetries = 3;
- mIsRetrying = FALSE;
- default:
- break;
- }
-
- LLVoiceChannel::handleStatusChange(type);
-}
-
-void LLVoiceChannelGroup::handleError(EStatusType status)
-{
- std::string notify;
- switch(status)
- {
- case ERROR_CHANNEL_LOCKED:
- case ERROR_CHANNEL_FULL:
- notify = "VoiceChannelFull";
- break;
- case ERROR_NOT_AVAILABLE:
- //clear URI and credentials
- //set the state to be no info
- //and activate
- if ( mRetries > 0 )
- {
- mRetries--;
- mIsRetrying = TRUE;
- mIgnoreNextSessionLeave = TRUE;
-
- getChannelInfo();
- return;
- }
- else
- {
- notify = "VoiceChannelJoinFailed";
- mRetries = DEFAULT_RETRIES_COUNT;
- mIsRetrying = FALSE;
- }
-
- break;
-
- case ERROR_UNKNOWN:
- default:
- break;
- }
-
- // notification
- if (!notify.empty())
- {
- LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs);
- // echo to im window
- gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
- }
-
- LLVoiceChannel::handleError(status);
-}
-
-void LLVoiceChannelGroup::setState(EState state)
-{
- // HACK: Open/close the call window if needed.
- toggleCallWindowIfNeeded(state);
-
- switch(state)
- {
- case STATE_RINGING:
- if ( !mIsRetrying )
- {
- gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- }
-
- mState = state;
- break;
- default:
- LLVoiceChannel::setState(state);
- }
-}
-
-//
-// LLVoiceChannelProximal
-//
-LLVoiceChannelProximal::LLVoiceChannelProximal() :
- LLVoiceChannel(LLUUID::null, LLStringUtil::null)
-{
- activate();
-}
-
-BOOL LLVoiceChannelProximal::isActive()
-{
- return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
-}
-
-void LLVoiceChannelProximal::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // this implicitly puts you back in the spatial channel
- LLVoiceClient::getInstance()->leaveNonSpatialChannel();
- }
-}
-
-void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
-{
- if (!proximal)
- {
- return;
- }
-
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
-}
-
-void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
-{
- // status updates
- switch(status)
- {
- case STATUS_LEFT_CHANNEL:
- // do not notify user when leaving proximal channel
- return;
- case STATUS_VOICE_DISABLED:
- gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
- return;
- default:
- break;
- }
- LLVoiceChannel::handleStatusChange(status);
-}
-
-
-void LLVoiceChannelProximal::handleError(EStatusType status)
-{
- std::string notify;
- switch(status)
- {
- case ERROR_CHANNEL_LOCKED:
- case ERROR_CHANNEL_FULL:
- notify = "ProximalVoiceChannelFull";
- break;
- default:
- break;
- }
-
- // notification
- if (!notify.empty())
- {
- LLNotifications::instance().add(notify, mNotifyArgs);
- }
-
- LLVoiceChannel::handleError(status);
-}
-
-void LLVoiceChannelProximal::deactivate()
-{
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- }
-}
-
-
-//
-// LLVoiceChannelP2P
-//
-LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
- LLVoiceChannelGroup(session_id, session_name),
- mOtherUserID(other_user_id),
- mReceivedCall(FALSE)
-{
- // make sure URI reflects encoded version of other user's agent id
- setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
-}
-
-void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_LEFT_CHANNEL:
- if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
- {
- if (mState == STATE_RINGING)
- {
- // other user declined call
- LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs);
- }
- else
- {
- // other user hung up
- LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs);
- }
- deactivate();
- }
- mIgnoreNextSessionLeave = FALSE;
- return;
- default:
- break;
- }
-
- LLVoiceChannel::handleStatusChange(type);
-}
-
-void LLVoiceChannelP2P::handleError(EStatusType type)
-{
- switch(type)
- {
- case ERROR_NOT_AVAILABLE:
- LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs);
- break;
- default:
- break;
- }
-
- LLVoiceChannel::handleError(type);
-}
-
-void LLVoiceChannelP2P::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // no session handle yet, we're starting the call
- if (mSessionHandle.empty())
- {
- mReceivedCall = FALSE;
- LLVoiceClient::getInstance()->callUser(mOtherUserID);
- }
- // otherwise answering the call
- else
- {
- LLVoiceClient::getInstance()->answerInvite(mSessionHandle);
-
- // using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
- mSessionHandle.clear();
- }
-
- // Add the party to the list of people with which we've recently interacted.
- LLRecentPeople::instance().add(mOtherUserID);
- }
-}
-
-void LLVoiceChannelP2P::getChannelInfo()
-{
- // pretend we have everything we need, since P2P doesn't use channel info
- if (sCurrentVoiceChannel == this)
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-// receiving session from other user who initiated call
-void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
-{
- BOOL needs_activate = FALSE;
- if (callStarted())
- {
- // defer to lower agent id when already active
- if (mOtherUserID < gAgent.getID())
- {
- // pretend we haven't started the call yet, so we can connect to this session instead
- deactivate();
- needs_activate = TRUE;
- }
- else
- {
- // we are active and have priority, invite the other user again
- // under the assumption they will join this new session
- mSessionHandle.clear();
- LLVoiceClient::getInstance()->callUser(mOtherUserID);
- return;
- }
- }
-
- mSessionHandle = handle;
-
- // The URI of a p2p session should always be the other end's SIP URI.
- if(!inURI.empty())
- {
- setURI(inURI);
- }
- else
- {
- setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
- }
-
- mReceivedCall = TRUE;
-
- if (needs_activate)
- {
- activate();
- }
-}
-
-void LLVoiceChannelP2P::setState(EState state)
-{
- // HACK: Open/close the call window if needed.
- toggleCallWindowIfNeeded(state);
-
- // you only "answer" voice invites in p2p mode
- // so provide a special purpose message here
- if (mReceivedCall && state == STATE_RINGING)
- {
- gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
- mState = state;
- return;
- }
- LLVoiceChannel::setState(state);
-}
-
//
// LLFloaterIMPanel
@@ -1836,75 +1012,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
self->mHistoryEditor->blockUndo();
}
-void LLFloaterIMPanel::showSessionStartError(
- const std::string& error_string)
-{
- LLSD args;
- args["REASON"] = LLTrans::getString(error_string);
- args["RECIPIENT"] = getTitle();
-
- LLSD payload;
- payload["session_id"] = mSessionUUID;
-
- LLNotifications::instance().add(
- "ChatterBoxSessionStartError",
- args,
- payload,
- onConfirmForceCloseError);
-}
-
-void LLFloaterIMPanel::showSessionEventError(
- const std::string& event_string,
- const std::string& error_string)
-{
- LLSD args;
- args["REASON"] =
- LLTrans::getString(error_string);
- args["EVENT"] =
- LLTrans::getString(event_string);
- args["RECIPIENT"] = getTitle();
-
- LLNotifications::instance().add(
- "ChatterBoxSessionEventError",
- args);
-}
-
-void LLFloaterIMPanel::showSessionForceClose(
- const std::string& reason_string)
-{
- LLSD args;
-
- args["NAME"] = getTitle();
- args["REASON"] = LLTrans::getString(reason_string);
-
- LLSD payload;
- payload["session_id"] = mSessionUUID;
-
- LLNotifications::instance().add(
- "ForceCloseChatterBoxSession",
- args,
- payload,
- LLFloaterIMPanel::onConfirmForceCloseError);
-
-}
-
//static
void LLFloaterIMPanel::onKickSpeaker(void* user_data)
{
}
-
-bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLSD& response)
-{
- //only 1 option really
- LLUUID session_id = notification["payload"]["session_id"];
-
- if ( gIMMgr )
- {
- LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(
- session_id);
-
- if ( floaterp ) floaterp->closeFloater(FALSE);
- }
- return false;
-}
diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h
index 4e306c7fab..39107d9a22 100644
--- a/indra/newview/llimpanel.h
+++ b/indra/newview/llimpanel.h
@@ -50,133 +50,6 @@ class LLIMSpeakerMgr;
class LLPanelActiveSpeakers;
class LLPanelChatControlPanel;
-class LLVoiceChannel : public LLVoiceClientStatusObserver
-{
-public:
- typedef enum e_voice_channel_state
- {
- STATE_NO_CHANNEL_INFO,
- STATE_ERROR,
- STATE_HUNG_UP,
- STATE_READY,
- STATE_CALL_STARTED,
- STATE_RINGING,
- STATE_CONNECTED
- } EState;
-
- LLVoiceChannel(const LLUUID& session_id, const std::string& session_name);
- virtual ~LLVoiceChannel();
-
- /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
-
- virtual void handleStatusChange(EStatusType status);
- virtual void handleError(EStatusType status);
- virtual void deactivate();
- virtual void activate();
- virtual void setChannelInfo(
- const std::string& uri,
- const std::string& credentials);
- virtual void getChannelInfo();
- virtual BOOL isActive();
- virtual BOOL callStarted();
- const std::string& getSessionName() const { return mSessionName; }
-
- const LLUUID getSessionID() { return mSessionID; }
- EState getState() { return mState; }
-
- void updateSessionID(const LLUUID& new_session_id);
- const LLSD& getNotifyArgs() { return mNotifyArgs; }
-
- static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
- static LLVoiceChannel* getChannelByURI(std::string uri);
- static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }
- static void initClass();
-
- static void suspend();
- static void resume();
-
-protected:
- virtual void setState(EState state);
- void toggleCallWindowIfNeeded(EState state);
- void setURI(std::string uri);
-
- std::string mURI;
- std::string mCredentials;
- LLUUID mSessionID;
- EState mState;
- std::string mSessionName;
- LLSD mNotifyArgs;
- BOOL mIgnoreNextSessionLeave;
- LLHandle<LLPanel> mLoginNotificationHandle;
-
- typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t;
- static voice_channel_map_t sVoiceChannelMap;
-
- typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t;
- static voice_channel_map_uri_t sVoiceChannelURIMap;
-
- static LLVoiceChannel* sCurrentVoiceChannel;
- static LLVoiceChannel* sSuspendedVoiceChannel;
- static BOOL sSuspended;
-};
-
-class LLVoiceChannelGroup : public LLVoiceChannel
-{
-public:
- LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name);
-
- /*virtual*/ void handleStatusChange(EStatusType status);
- /*virtual*/ void handleError(EStatusType status);
- /*virtual*/ void activate();
- /*virtual*/ void deactivate();
- /*vritual*/ void setChannelInfo(
- const std::string& uri,
- const std::string& credentials);
- /*virtual*/ void getChannelInfo();
-
-protected:
- virtual void setState(EState state);
-
-private:
- U32 mRetries;
- BOOL mIsRetrying;
-};
-
-class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal>
-{
-public:
- LLVoiceChannelProximal();
-
- /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
- /*virtual*/ void handleStatusChange(EStatusType status);
- /*virtual*/ void handleError(EStatusType status);
- /*virtual*/ BOOL isActive();
- /*virtual*/ void activate();
- /*virtual*/ void deactivate();
-
-};
-
-class LLVoiceChannelP2P : public LLVoiceChannelGroup
-{
-public:
- LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id);
-
- /*virtual*/ void handleStatusChange(EStatusType status);
- /*virtual*/ void handleError(EStatusType status);
- /*virtual*/ void activate();
- /*virtual*/ void getChannelInfo();
-
- void setSessionHandle(const std::string& handle, const std::string &inURI);
-
-protected:
- virtual void setState(EState state);
-
-private:
- std::string mSessionHandle;
- LLUUID mOtherUserID;
- BOOL mReceivedCall;
-};
-
class LLFloaterIMPanel : public LLFloater
{
public:
@@ -256,15 +129,6 @@ public:
void processIMTyping(const LLIMInfo* im_info, BOOL typing);
static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata);
- //show error statuses to the user
- void showSessionStartError(const std::string& error_string);
- void showSessionEventError(
- const std::string& event_string,
- const std::string& error_string);
- void showSessionForceClose(const std::string& reason);
-
- static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response);
-
private:
// Called by UI methods.
void sendMsg();
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index b631c991ae..8a55ab41b9 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -70,6 +70,7 @@
#include "llviewerwindow.h"
#include "llnotify.h"
#include "llviewerregion.h"
+#include "llvoicechannel.h"
#include "lltrans.h"
#include "llrecentpeople.h"
@@ -144,7 +145,10 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
mInitialTargetIDs(ids),
mVoiceChannel(NULL),
mSpeakers(NULL),
- mSessionInitialized(false)
+ mSessionInitialized(false),
+ mCallBackEnabled(true),
+ mTextIMPossible(true),
+ mOtherParticipantIsAvatar(true)
{
if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)
{
@@ -168,6 +172,13 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
//so we're already initialized
mSessionInitialized = true;
}
+
+ if (IM_NOTHING_SPECIAL == type)
+ {
+ mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID);
+ mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID);
+ mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID);
+ }
}
LLIMModel::LLIMSession::~LLIMSession()
@@ -272,7 +283,8 @@ void LLIMModel::testMessages()
}
-bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id, const std::vector<LLUUID>& ids)
+bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,
+ const LLUUID& other_participant_id, const std::vector<LLUUID>& ids)
{
if (is_in_map(sSessionsMap, session_id))
{
@@ -289,7 +301,7 @@ bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage
}
-bool LLIMModel::clearSession(LLUUID session_id)
+bool LLIMModel::clearSession(const LLUUID& session_id)
{
if (sSessionsMap.find(session_id) == sSessionsMap.end()) return false;
delete (sSessionsMap[session_id]);
@@ -297,16 +309,13 @@ bool LLIMModel::clearSession(LLUUID session_id)
return true;
}
-//*TODO remake it, instead of returing the list pass it as as parameter (IB)
-std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)
+void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
{
- std::list<LLSD> return_list;
-
LLIMSession* session = findIMSession(session_id);
if (!session)
{
llwarns << "session " << session_id << "does not exist " << llendl;
- return return_list;
+ return;
}
int i = session->mMsgs.size() - start_index;
@@ -317,7 +326,7 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)
{
LLSD msg;
msg = *iter;
- return_list.push_back(*iter);
+ messages.push_back(*iter);
i--;
}
@@ -327,14 +336,9 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)
arg["session_id"] = session_id;
arg["num_unread"] = 0;
mNoUnreadMsgsSignal(arg);
-
- // TODO: in the future is there a more efficient way to return these
- //of course there is - return as parameter (IB)
- return return_list;
-
}
-bool LLIMModel::addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) {
+bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {
LLIMSession* session = findIMSession(session_id);
@@ -383,8 +387,8 @@ bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, con
return false;
}
-//*TODO add const qualifier and pass by references (IB)
-bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text, bool log2file /* = true */) {
+bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,
+ const std::string& utf8_text, bool log2file /* = true */) {
LLIMSession* session = findIMSession(session_id);
if (!session)
@@ -506,7 +510,7 @@ void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id,
gAgent.sendReliableMessage();
}
-void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id)
+void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id)
{
if(session_id.notNull())
{
@@ -890,20 +894,11 @@ public:
{
gIMMgr->clearPendingAgentListUpdates(mSessionID);
gIMMgr->clearPendingInvitation(mSessionID);
-
- LLFloaterIMPanel* floaterp =
- gIMMgr->findFloaterBySession(mSessionID);
-
- if ( floaterp )
+ if ( 404 == statusNum )
{
- if ( 404 == statusNum )
- {
- std::string error_string;
- error_string = "does not exist";
-
- floaterp->showSessionStartError(
- error_string);
- }
+ std::string error_string;
+ error_string = "does not exist";
+ gIMMgr->showSessionStartError(error_string, mSessionID);
}
}
}
@@ -955,6 +950,106 @@ LLUUID LLIMMgr::computeSessionID(
return session_id;
}
+inline LLFloater* getFloaterBySessionID(const LLUUID session_id)
+{
+ LLFloater* floater = NULL;
+ if ( gIMMgr )
+ {
+ floater = dynamic_cast < LLFloater* >
+ ( gIMMgr->findFloaterBySession(session_id) );
+ }
+ if ( !floater )
+ {
+ floater = dynamic_cast < LLFloater* >
+ ( LLIMFloater::findInstance(session_id) );
+ }
+ return floater;
+}
+
+void
+LLIMMgr::showSessionStartError(
+ const std::string& error_string,
+ const LLUUID session_id)
+{
+ const LLFloater* floater = getFloaterBySessionID (session_id);
+ if (!floater) return;
+
+ LLSD args;
+ args["REASON"] = LLTrans::getString(error_string);
+ args["RECIPIENT"] = floater->getTitle();
+
+ LLSD payload;
+ payload["session_id"] = session_id;
+
+ LLNotifications::instance().add(
+ "ChatterBoxSessionStartError",
+ args,
+ payload,
+ LLIMMgr::onConfirmForceCloseError);
+}
+
+void
+LLIMMgr::showSessionEventError(
+ const std::string& event_string,
+ const std::string& error_string,
+ const LLUUID session_id)
+{
+ const LLFloater* floater = getFloaterBySessionID (session_id);
+ if (!floater) return;
+
+ LLSD args;
+ args["REASON"] =
+ LLTrans::getString(error_string);
+ args["EVENT"] =
+ LLTrans::getString(event_string);
+ args["RECIPIENT"] = floater->getTitle();
+
+ LLNotifications::instance().add(
+ "ChatterBoxSessionEventError",
+ args);
+}
+
+void
+LLIMMgr::showSessionForceClose(
+ const std::string& reason_string,
+ const LLUUID session_id)
+{
+ const LLFloater* floater = getFloaterBySessionID (session_id);
+ if (!floater) return;
+
+ LLSD args;
+
+ args["NAME"] = floater->getTitle();
+ args["REASON"] = LLTrans::getString(reason_string);
+
+ LLSD payload;
+ payload["session_id"] = session_id;
+
+ LLNotifications::instance().add(
+ "ForceCloseChatterBoxSession",
+ args,
+ payload,
+ LLIMMgr::onConfirmForceCloseError);
+}
+
+//static
+bool
+LLIMMgr::onConfirmForceCloseError(
+ const LLSD& notification,
+ const LLSD& response)
+{
+ //only 1 option really
+ LLUUID session_id = notification["payload"]["session_id"];
+
+ LLFloater* floater = getFloaterBySessionID (session_id);
+ if ( floater )
+ {
+ floater->closeFloater(FALSE);
+ }
+ return false;
+}
+
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIncomingCallDialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1114,29 +1209,6 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
}
}
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLIMViewFriendObserver
-//
-// Bridge to suport knowing when the inventory has changed.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLIMViewFriendObserver : public LLFriendObserver
-{
-public:
- LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {}
- virtual ~LLIMViewFriendObserver() {}
- virtual void changed(U32 mask)
- {
- if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
- {
- mTV->refresh();
- }
- }
-protected:
- LLIMMgr* mTV;
-};
-
-
bool inviteUserResponse(const LLSD& notification, const LLSD& response)
{
const LLSD& payload = notification["payload"];
@@ -1237,7 +1309,6 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)
//
LLIMMgr::LLIMMgr() :
- mFriendObserver(NULL),
mIMReceived(FALSE)
{
static bool registered_dialog = false;
@@ -1246,21 +1317,11 @@ LLIMMgr::LLIMMgr() :
LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);
registered_dialog = true;
}
-
- mFriendObserver = new LLIMViewFriendObserver(this);
- LLAvatarTracker::instance().addObserver(mFriendObserver);
mPendingInvitations = LLSD::emptyMap();
mPendingAgentListUpdates = LLSD::emptyMap();
}
-LLIMMgr::~LLIMMgr()
-{
- LLAvatarTracker::instance().removeObserver(mFriendObserver);
- delete mFriendObserver;
- // Children all cleaned up by default view destructor.
-}
-
// Add a message to a session.
void LLIMMgr::addMessage(
const LLUUID& session_id,
@@ -1299,9 +1360,15 @@ void LLIMMgr::addMessage(
fixed_session_name = session_name;
}
- if (!LLIMModel::getInstance()->findIMSession(new_session_id))
+ bool new_session = !hasSession(session_id);
+ if (new_session)
{
- LLIMModel::getInstance()->newSession(session_id, fixed_session_name, dialog, other_participant_id);
+ // *NOTE dzaporozhan
+ // Workaround for critical bug EXT-1918
+
+ // *TODO
+ // Investigate cases when session_id == NULL and find solution to handle those cases
+ LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id);
}
floater = findFloaterBySession(new_session_id);
@@ -1318,15 +1385,16 @@ void LLIMMgr::addMessage(
// create IM window as necessary
if(!floater)
{
-
-
floater = createFloater(
new_session_id,
other_participant_id,
fixed_session_name,
dialog,
FALSE);
+ }
+ if (new_session)
+ {
// When we get a new IM, and if you are a god, display a bit
// of information about the source. This is to help liaisons
// when answering questions.
@@ -1336,7 +1404,7 @@ void LLIMMgr::addMessage(
std::ostringstream bonus_info;
bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " "
<< parent_estate_id
- << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")
+ << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")
<< ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : "");
// once we have web-services (or something) which returns
@@ -1439,10 +1507,7 @@ S32 LLIMMgr::getNumberOfUnreadIM()
S32 num = 0;
for(it = LLIMModel::sSessionsMap.begin(); it != LLIMModel::sSessionsMap.end(); ++it)
{
- if((*it).first != mBeingRemovedSessionID)
- {
- num += (*it).second->mNumUnread;
- }
+ num += (*it).second->mNumUnread;
}
return num;
@@ -1458,15 +1523,6 @@ BOOL LLIMMgr::getIMReceived() const
return mIMReceived;
}
-// This method returns TRUE if the local viewer has a session
-// currently open keyed to the uuid.
-BOOL LLIMMgr::isIMSessionOpen(const LLUUID& uuid)
-{
- LLFloaterIMPanel* floater = findFloaterBySession(uuid);
- if(floater) return TRUE;
- return FALSE;
-}
-
LLUUID LLIMMgr::addP2PSession(const std::string& name,
const LLUUID& other_participant_id,
const std::string& voice_session_handle,
@@ -1560,41 +1616,25 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)
return true;
}
-// This removes the panel referenced by the uuid, and then restores
-// internal consistency. The internal pointer is not deleted? Did you mean
-// a pointer to the corresponding LLIMSession? Session data is cleared now.
-// Put a copy of UUID to avoid problem when passed reference becames invalid
-// if it has been come from the object removed in observer.
-void LLIMMgr::removeSession(LLUUID session_id)
+// Removes data associated with a particular session specified by session_id
+void LLIMMgr::removeSession(const LLUUID& session_id)
{
- if (mBeingRemovedSessionID == session_id)
- {
- return;
- }
+ llassert_always(hasSession(session_id));
+ //*TODO remove this floater thing when Communicate Floater is being deleted (IB)
LLFloaterIMPanel* floater = findFloaterBySession(session_id);
if(floater)
{
mFloaters.erase(floater->getHandle());
LLFloaterChatterBox::getInstance()->removeFloater(floater);
- //mTabContainer->removeTabPanel(floater);
-
- clearPendingInvitation(session_id);
- clearPendingAgentListUpdates(session_id);
}
- // for some purposes storing ID of a sessios that is being removed
- mBeingRemovedSessionID = session_id;
- notifyObserverSessionRemoved(session_id);
+ clearPendingInvitation(session_id);
+ clearPendingAgentListUpdates(session_id);
- //if we don't clear session data on removing the session
- //we can't use LLBottomTray as observer of session creation/delettion and
- //creating chiclets only on session created even, we need to handle chiclets creation
- //the same way as LLFloaterIMPanels were managed.
LLIMModel::getInstance()->clearSession(session_id);
- // now this session is completely removed
- mBeingRemovedSessionID.setNull();
+ notifyObserverSessionRemoved(session_id);
}
void LLIMMgr::inviteToSession(
@@ -1723,10 +1763,6 @@ void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::stri
}
}
-void LLIMMgr::refresh()
-{
-}
-
void LLIMMgr::disconnectAllSessions()
{
LLFloaterIMPanel* floater = NULL;
@@ -2038,6 +2074,12 @@ void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)
{
floater->processIMTyping(im_info, typing);
}
+
+ LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
+ if ( im_floater )
+ {
+ im_floater->processIMTyping(im_info, typing);
+ }
}
class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
@@ -2087,19 +2129,21 @@ public:
}
}
+ LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
+ if ( im_floater )
+ {
+ if ( body.has("session_info") )
+ {
+ im_floater->processSessionUpdate(body["session_info"]);
+ }
+ }
+
gIMMgr->clearPendingAgentListUpdates(session_id);
}
else
{
- //throw an error dialog and close the temp session's
- //floater
- LLFloaterIMPanel* floater =
- gIMMgr->findFloaterBySession(temp_session_id);
-
- if ( floater )
- {
- floater->showSessionStartError(body["error"].asString());
- }
+ //throw an error dialog and close the temp session's floater
+ gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id);
}
gIMMgr->clearPendingAgentListUpdates(session_id);
@@ -2132,15 +2176,10 @@ public:
if ( !success )
{
//throw an error dialog
- LLFloaterIMPanel* floater =
- gIMMgr->findFloaterBySession(session_id);
-
- if (floater)
- {
- floater->showSessionEventError(
- body["event"].asString(),
- body["error"].asString());
- }
+ gIMMgr->showSessionEventError(
+ body["event"].asString(),
+ body["error"].asString(),
+ session_id);
}
}
};
@@ -2158,13 +2197,7 @@ public:
session_id = input["body"]["session_id"].asUUID();
reason = input["body"]["reason"].asString();
- LLFloaterIMPanel* floater =
- gIMMgr ->findFloaterBySession(session_id);
-
- if ( floater )
- {
- floater->showSessionForceClose(reason);
- }
+ gIMMgr->showSessionForceClose(reason, session_id);
}
};
@@ -2202,11 +2235,17 @@ public:
const LLSD& context,
const LLSD& input) const
{
- LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
+ LLUUID session_id = input["body"]["session_id"].asUUID();
+ LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);
if (floaterp)
{
floaterp->processSessionUpdate(input["body"]["info"]);
}
+ LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
+ if ( im_floater )
+ {
+ im_floater->processSessionUpdate(input["body"]["info"]);
+ }
}
};
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 68beb29034..ae8fd355ea 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -34,7 +34,7 @@
#define LL_LLIMVIEW_H
#include "lldarray.h"
-#include "llfloateractivespeakers.h" //for LLIMSpeakerMgr
+#include "llspeakers.h" //for LLIMSpeakerMgr
#include "llimpanel.h" //for voice channels
#include "llmodaldialog.h"
#include "llinstantmessage.h"
@@ -70,6 +70,13 @@ public:
LLIMSpeakerMgr* mSpeakers;
bool mSessionInitialized;
+
+ //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 mCallBackEnabled;
+
+ bool mTextIMPossible;
+ bool mOtherParticipantIsAvatar;
};
@@ -104,18 +111,35 @@ public:
boost::signals2::connection addNewMsgCallback( session_callback_t cb ) { return mNewMsgSignal.connect(cb); }
boost::signals2::connection addNoUnreadMsgsCallback( session_callback_t cb ) { return mNoUnreadMsgsSignal.connect(cb); }
- bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id,
+ /**
+ * Create new session object in a model
+ */
+ bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id,
const std::vector<LLUUID>& ids = std::vector<LLUUID>());
- bool clearSession(LLUUID session_id);
- std::list<LLSD> getMessages(LLUUID session_id, int start_index = 0);
- bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text, bool log2file = true);
- bool addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text);
+ /**
+ * Remove all session data associated with a session specified by session_id
+ */
+ bool clearSession(const LLUUID& session_id);
- bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text);
+ /**
+ * Populate supplied std::list with messages starting from index specified by start_index
+ */
+ void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0);
- //used to get the name of the session, for use as the title
- //currently just the other avatar name
+ /**
+ * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id
+ * and also saved into a file if log2file is specified.
+ * It sends new message signal for each added message.
+ */
+ bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true);
+
+ /**
+ * Get a session's name.
+ * For a P2P chat - it's an avatar's name,
+ * For a group chat - it's a group's name
+ * For an ad-hoc chat - is received from the server and is in a from of "<Avatar's name> conference"
+ */
const std::string& getName(const LLUUID& session_id) const;
/**
@@ -150,7 +174,7 @@ public:
*/
LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const;
- static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id);
+ static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id);
static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id,
const std::vector<LLUUID>& ids, EInstantMessage dialog);
static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing);
@@ -158,6 +182,19 @@ public:
const LLUUID& other_participant_id, EInstantMessage dialog);
void testMessages();
+
+private:
+
+ /**
+ * Add message to a list of message associated with session specified by session_id
+ */
+ bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
+
+ /**
+ * Save an IM message into a file
+ */
+ //*TODO should also save uuid of a sender
+ bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text);
};
class LLIMSessionObserver
@@ -183,7 +220,7 @@ public:
};
LLIMMgr();
- virtual ~LLIMMgr();
+ virtual ~LLIMMgr() {};
// Add a message to a session. The session can keyed to sesion id
// or agent id.
@@ -200,11 +237,6 @@ public:
void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args);
- // This method returns TRUE if the local viewer has a session
- // currently open keyed to the uuid. The uuid can be keyed by
- // either session id or agent id.
- BOOL isIMSessionOpen(const LLUUID& uuid);
-
// This adds a session to the talk view. The name is the local
// name of the session, dialog specifies the type of
// session. Since sessions can be keyed off of first recipient or
@@ -250,9 +282,6 @@ public:
void processIMTypingStart(const LLIMInfo* im_info);
void processIMTypingStop(const LLIMInfo* im_info);
- // Rebuild stuff
- void refresh();
-
void notifyNewIM();
void clearNewIMNotification();
@@ -268,10 +297,6 @@ public:
// good connection.
void disconnectAllSessions();
- // This is a helper function to determine what kind of im session
- // should be used for the given agent.
- static EInstantMessage defaultIMTypeForAgent(const LLUUID& agent_id);
-
BOOL hasSession(const LLUUID& session_id);
// This method returns the im panel corresponding to the uuid
@@ -290,11 +315,18 @@ public:
void clearPendingAgentListUpdates(const LLUUID& session_id);
//HACK: need a better way of enumerating existing session, or listening to session create/destroy events
+ //@deprecated, is used only by LLToolBox, which is not used anywhere, right? (IB)
const std::set<LLHandle<LLFloater> >& getIMFloaterHandles() { return mFloaters; }
void addSessionObserver(LLIMSessionObserver *);
void removeSessionObserver(LLIMSessionObserver *);
+ //show error statuses to the user
+ void showSessionStartError(const std::string& error_string, const LLUUID session_id);
+ void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id);
+ void showSessionForceClose(const std::string& reason, const LLUUID session_id);
+ static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response);
+
/**
* Start call in a session
* @return false if voice channel doesn't exist
@@ -308,10 +340,11 @@ public:
bool endCall(const LLUUID& session_id);
private:
- // This removes the panel referenced by the uuid, and then
- // restores internal consistency. The internal pointer is not
- // deleted.
- void removeSession(LLUUID session_id);
+
+ /**
+ * Remove data associated with a particular session specified by session_id
+ */
+ void removeSession(const LLUUID& session_id);
// create a panel and update internal representation for
// consistency. Returns the pointer, caller (the class instance
@@ -340,8 +373,9 @@ private:
void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
private:
+
+ //*TODO should be deleted when Communicate Floater is being deleted
std::set<LLHandle<LLFloater> > mFloaters;
- LLFriendObserver* mFriendObserver;
typedef std::list <LLIMSessionObserver *> session_observers_list_t;
session_observers_list_t mSessionObservers;
@@ -351,9 +385,6 @@ private:
LLSD mPendingInvitations;
LLSD mPendingAgentListUpdates;
- // ID of a session that is being removed: observers are already told
- // that this session is being removed, but it is still present in the sessions' map
- LLUUID mBeingRemovedSessionID;
};
class LLIncomingCallDialog : public LLModalDialog
diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp
index b36b7cf50e..091346d3b4 100644
--- a/indra/newview/lllandmarkactions.cpp
+++ b/indra/newview/lllandmarkactions.cpp
@@ -348,7 +348,7 @@ LLLandmark* LLLandmarkActions::getLandmark(const LLUUID& landmarkInventoryItemID
{
LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID);
if (NULL == item)
- return false;
+ return NULL;
const LLUUID& asset_id = item->getAssetUUID();
return gLandmarkList.getAsset(asset_id, NULL);
diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h
index d651259790..32f05e702b 100644
--- a/indra/newview/lllandmarkactions.h
+++ b/indra/newview/lllandmarkactions.h
@@ -108,7 +108,7 @@ public:
/**
* @brief Retrieve a landmark from gLandmarkList by inventory item's id
*
- * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist.
+ * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist or wasn't loaded.
*/
static LLLandmark* getLandmark(const LLUUID& landmarkInventoryItemID);
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 3802d13f8b..c32ef2f22b 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -261,6 +261,15 @@ void LLNavigationBar::draw()
onTeleportHistoryChanged();
mPurgeTPHistoryItems = false;
}
+
+ if (isBackgroundVisible())
+ {
+ static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0);
+ static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
+ gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
+ color_drop_shadow, drop_shadow_floater );
+ }
+
LLPanel::draw();
}
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 148f72703c..12638ab855 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -170,22 +170,6 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat)
return text_color;
}
-std::string formatCurrentTime()
-{
- time_t utc_time;
- utc_time = time_corrected();
- std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:["
- +LLTrans::getString("TimeMin")+"] ";
-
- LLSD substitution;
-
- substitution["datetime"] = (S32) utc_time;
- LLStringUtil::format (timeStr, substitution);
-
- return timeStr;
-}
-
-
void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color)
{
S32 font_size = gSavedSettings.getS32("ChatFontSize");
@@ -210,16 +194,14 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo
style_params.font(fontp);
LLUUID uuid = chat.mFromID;
std::string from = chat.mFromName;
- std::string time = formatCurrentTime();
std::string message = chat.mText;
- mChatHistory->appendWidgetMessage(uuid, from, time, message, style_params);
+ mChatHistory->appendWidgetMessage(chat, style_params);
}
void LLNearbyChat::addMessage(const LLChat& chat)
{
LLColor4 color = nearbychat_get_text_color(chat);
-
if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)
{
if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 5fa97926a5..217007fb15 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -45,6 +45,7 @@
#include "llviewerstats.h"
#include "llcommandhandler.h"
#include "llviewercontrol.h"
+#include "llnavigationbar.h"
S32 LLNearbyChatBar::sLastSpecialChatChannel = 0;
@@ -177,6 +178,31 @@ void LLGestureComboBox::draw()
LLComboBox::draw();
}
+//virtual
+void LLGestureComboBox::showList()
+{
+ LLComboBox::showList();
+
+ // Calculating amount of space between the navigation bar and gestures combo
+ LLNavigationBar* nb = LLNavigationBar::getInstance();
+ S32 x, nb_bottom;
+ nb->localPointToScreen(0, 0, &x, &nb_bottom);
+
+ S32 list_bottom;
+ mList->localPointToScreen(0, 0, &x, &list_bottom);
+
+ S32 max_height = nb_bottom - list_bottom;
+
+ LLRect rect = mList->getRect();
+ // List overlapped navigation bar, downsize it
+ if (rect.getHeight() > max_height)
+ {
+ rect.setOriginAndSize(rect.mLeft, rect.mBottom, rect.getWidth(), max_height);
+ mList->setRect(rect);
+ mList->reshape(rect.getWidth(), rect.getHeight());
+ }
+}
+
LLNearbyChatBar::LLNearbyChatBar()
: LLPanel()
, mChatBox(NULL)
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index b902ff86cc..06204e6367 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -40,7 +40,7 @@
#include "llchiclet.h"
#include "llvoiceclient.h"
#include "lloutputmonitorctrl.h"
-#include "llfloateractivespeakers.h"
+#include "llspeakers.h"
class LLGestureComboBox
: public LLComboBox
@@ -62,6 +62,9 @@ public:
virtual void changed() { refreshGestures(); }
protected:
+
+ virtual void showList();
+
LLFrameTimer mGestureLabelTimer;
std::vector<LLMultiGesture*> mGestures;
std::string mLabel;
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index 7239f49b7f..543198c1d2 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -86,6 +86,20 @@ bool LLTipHandler::processNotification(const LLSD& notify)
if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
{
+ // archive message in nearby chat
+ LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
+ if(nearby_chat)
+ {
+ LLChat chat_msg(notification->getMessage());
+ nearby_chat->addMessage(chat_msg);
+
+ // don't show toast if Nearby Chat is opened
+ if (nearby_chat->getVisible())
+ {
+ return true;
+ }
+ }
+
LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);
LLToast::Params p;
@@ -99,14 +113,6 @@ bool LLTipHandler::processNotification(const LLSD& notify)
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
if(channel)
channel->addToast(p);
-
- // archive message in nearby chat
- LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
- if(nearby_chat)
- {
- LLChat chat_msg(notification->getMessage());
- nearby_chat->addMessage(chat_msg);
- }
}
else if (notify["sigtype"].asString() == "delete")
{
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index 6eed956eb8..f9eeaf1e9e 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -34,6 +34,7 @@
#include "llpanelimcontrolpanel.h"
+#include "llagent.h"
#include "llavataractions.h"
#include "llavatariconctrl.h"
#include "llbutton.h"
@@ -41,6 +42,53 @@
#include "llavatarlist.h"
#include "llparticipantlist.h"
#include "llimview.h"
+#include "llvoicechannel.h"
+
+void LLPanelChatControlPanel::onCallButtonClicked()
+{
+ gIMMgr->startCall(mSessionId);
+}
+
+void LLPanelChatControlPanel::onEndCallButtonClicked()
+{
+ gIMMgr->endCall(mSessionId);
+}
+
+BOOL LLPanelChatControlPanel::postBuild()
+{
+ childSetAction("call_btn", boost::bind(&LLPanelChatControlPanel::onCallButtonClicked, this));
+ childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this));
+
+ return TRUE;
+}
+
+void LLPanelChatControlPanel::draw()
+{
+ // hide/show start call and end call buttons
+ bool voice_enabled = LLVoiceClient::voiceEnabled();
+
+ LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
+ if (!session) return;
+
+ LLVoiceChannel* voice_channel = session->mVoiceChannel;
+ if (voice_channel && voice_enabled)
+ {
+ childSetVisible("end_call_btn", voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
+ childSetVisible("call_btn", voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
+ }
+
+ bool session_initialized = session->mSessionInitialized;
+ bool callback_enabled = session->mCallBackEnabled;
+ LLViewerRegion* region = gAgent.getRegion();
+
+ BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "")
+ && session_initialized
+ && voice_enabled
+ && callback_enabled;
+ childSetEnabled("call_btn", enable_connect);
+
+ LLPanel::draw();
+}
LLPanelIMControlPanel::LLPanelIMControlPanel()
{
@@ -54,11 +102,11 @@ BOOL LLPanelIMControlPanel::postBuild()
{
childSetAction("view_profile_btn", boost::bind(&LLPanelIMControlPanel::onViewProfileButtonClicked, this));
childSetAction("add_friend_btn", boost::bind(&LLPanelIMControlPanel::onAddFriendButtonClicked, this));
- childSetAction("call_btn", boost::bind(&LLPanelIMControlPanel::onCallButtonClicked, this));
+
childSetAction("share_btn", boost::bind(&LLPanelIMControlPanel::onShareButtonClicked, this));
childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(getChild<LLAvatarIconCtrl>("avatar_icon")->getAvatarId()));
-
- return TRUE;
+
+ return LLPanelChatControlPanel::postBuild();
}
void LLPanelIMControlPanel::onViewProfileButtonClicked()
@@ -73,22 +121,29 @@ void LLPanelIMControlPanel::onAddFriendButtonClicked()
LLAvatarActions::requestFriendshipDialog(avatar_icon->getAvatarId(), full_name);
}
-void LLPanelIMControlPanel::onCallButtonClicked()
-{
- // *TODO: Implement
-}
-
void LLPanelIMControlPanel::onShareButtonClicked()
{
// *TODO: Implement
}
-void LLPanelIMControlPanel::setID(const LLUUID& avatar_id)
+void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)
{
+ LLPanelChatControlPanel::setSessionId(session_id);
+
+ LLIMModel& im_model = LLIMModel::instance();
+
+ LLUUID avatar_id = im_model.getOtherParticipantID(session_id);
+
// Disable "Add friend" button for friends.
childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(avatar_id));
getChild<LLAvatarIconCtrl>("avatar_icon")->setValue(avatar_id);
+
+ // Disable profile button if participant is not realy SL avatar
+ LLIMModel::LLIMSession* im_session =
+ im_model.findIMSession(session_id);
+ if( im_session && !im_session->mOtherParticipantIsAvatar )
+ childSetEnabled("view_profile_btn", FALSE);
}
@@ -100,12 +155,11 @@ LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id)
BOOL LLPanelGroupControlPanel::postBuild()
{
childSetAction("group_info_btn", boost::bind(&LLPanelGroupControlPanel::onGroupInfoButtonClicked, this));
- childSetAction("call_btn", boost::bind(&LLPanelGroupControlPanel::onCallButtonClicked, this));
mAvatarList = getChild<LLAvatarList>("speakers_list");
mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList);
- return TRUE;
+ return LLPanelChatControlPanel::postBuild();
}
LLPanelGroupControlPanel::~LLPanelGroupControlPanel()
@@ -127,13 +181,23 @@ void LLPanelGroupControlPanel::onGroupInfoButtonClicked()
}
-void LLPanelGroupControlPanel::onCallButtonClicked()
+void LLPanelGroupControlPanel::setSessionId(const LLUUID& session_id)
{
- // *TODO: Implement
+ LLPanelChatControlPanel::setSessionId(session_id);
+
+ mGroupID = LLIMModel::getInstance()->getOtherParticipantID(session_id);
}
-void LLPanelGroupControlPanel::setID(const LLUUID& id)
+LLPanelAdHocControlPanel::LLPanelAdHocControlPanel(const LLUUID& session_id):LLPanelGroupControlPanel(session_id)
+{
+}
+
+BOOL LLPanelAdHocControlPanel::postBuild()
{
- mGroupID = id;
+ mAvatarList = getChild<LLAvatarList>("speakers_list");
+ mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList);
+
+ return LLPanelChatControlPanel::postBuild();
}
+
diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h
index 138b1630c4..220b7b14ba 100644
--- a/indra/newview/llpanelimcontrolpanel.h
+++ b/indra/newview/llpanelimcontrolpanel.h
@@ -45,8 +45,16 @@ public:
LLPanelChatControlPanel() {};
~LLPanelChatControlPanel() {};
- // sets the group or avatar UUID
- virtual void setID(const LLUUID& avatar_id)= 0;
+ virtual BOOL postBuild();
+ virtual void draw();
+
+ void onCallButtonClicked();
+ void onEndCallButtonClicked();
+
+ virtual void setSessionId(const LLUUID& session_id) { mSessionId = session_id; }
+
+private:
+ LLUUID mSessionId;
};
@@ -58,13 +66,14 @@ public:
BOOL postBuild();
- void setID(const LLUUID& avatar_id);
+ void setSessionId(const LLUUID& session_id);
private:
void onViewProfileButtonClicked();
void onAddFriendButtonClicked();
- void onCallButtonClicked();
void onShareButtonClicked();
+
+ LLUUID mAvatarID;
};
@@ -76,19 +85,26 @@ public:
BOOL postBuild();
- void setID(const LLUUID& id);
+ void setSessionId(const LLUUID& session_id);
/*virtual*/ void draw();
-private:
- void onGroupInfoButtonClicked();
- void onCallButtonClicked();
-
+protected:
LLUUID mGroupID;
LLSpeakerMgr* mSpeakerManager;
LLAvatarList* mAvatarList;
LLParticipantList* mParticipantList;
+
+private:
+ void onGroupInfoButtonClicked();
};
+class LLPanelAdHocControlPanel : public LLPanelGroupControlPanel
+{
+public:
+ LLPanelAdHocControlPanel(const LLUUID& session_id);
+
+ BOOL postBuild();
+};
#endif // LL_LLPANELIMCONTROLPANEL_H
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 83fb147a49..3d0db71045 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -38,10 +38,12 @@
#include "llsdutil.h"
#include "llsdutil_math.h"
+#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llagentpicksinfo.h"
#include "llagentui.h"
+#include "llcallbacklist.h"
#include "lldndbutton.h"
#include "llfloaterworldmap.h"
#include "llfolderviewitem.h"
@@ -56,7 +58,7 @@
//static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");
static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn";
-static const std::string ADD_LANDMARK_BUTTON_NAME = "add_landmark_btn";
+static const std::string ADD_BUTTON_NAME = "add_btn";
static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";
static const std::string TRASH_BUTTON_NAME = "trash_btn";
@@ -75,6 +77,7 @@ LLLandmarksPanel::LLLandmarksPanel()
, mListCommands(NULL)
, mGearFolderMenu(NULL)
, mGearLandmarkMenu(NULL)
+ , mDirtyFilter(false)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");
}
@@ -98,16 +101,37 @@ BOOL LLLandmarksPanel::postBuild()
initMyInventroyPanel();
initLibraryInventroyPanel();
+ gIdleCallbacks.addFunction(LLLandmarksPanel::doIdle, this);
return TRUE;
}
// virtual
void LLLandmarksPanel::onSearchEdit(const std::string& string)
{
+ static std::string prev_string("");
+
+ if (prev_string == string) return;
+
+ // show all folders in Landmarks Accordion for empty filter
+ mLandmarksInventoryPanel->setShowFolderState(string.empty() ?
+ LLInventoryFilter::SHOW_ALL_FOLDERS :
+ LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS
+ );
+
filter_list(mFavoritesInventoryPanel, string);
filter_list(mLandmarksInventoryPanel, string);
filter_list(mMyInventoryPanel, string);
filter_list(mLibraryInventoryPanel, string);
+
+ prev_string = string;
+ mDirtyFilter = true;
+
+ // give FolderView a chance to be refreshed. So, made all accordions visible
+ for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
+ {
+ LLAccordionCtrlTab* tab = *iter;
+ tab->setVisible(true);
+ }
}
// virtual
@@ -300,6 +324,8 @@ void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)
panel_pick, panel_places,params));
panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
panel_pick, panel_places,params));
+ panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
+ panel_pick, panel_places,params));
}
}
}
@@ -389,6 +415,7 @@ void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_lis
void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list)
{
LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name);
+ mAccordionTabs.push_back(accordion_tab);
accordion_tab->setDropDownStateChangedCallback(
boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));
}
@@ -433,11 +460,11 @@ void LLLandmarksPanel::initListCommandsHandlers()
mListCommands = getChild<LLPanel>("bottom_panel");
mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
- mListCommands->childSetAction(ADD_LANDMARK_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddLandmarkButtonClick, this));
- mListCommands->childSetAction(ADD_FOLDER_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddFolderButtonClick, this));
mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this));
+ mListCommands->getChild<LLButton>(ADD_BUTTON_NAME)->setHeldDownCallback(boost::bind(&LLLandmarksPanel::onAddButtonHeldDown, this));
+ static const LLSD add_landmark_command("add_landmark");
+ mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddAction, this, add_landmark_command));
-
LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);
trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this
, _4 // BOOL drop
@@ -453,6 +480,7 @@ void LLLandmarksPanel::initListCommandsHandlers()
mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
}
@@ -488,52 +516,26 @@ void LLLandmarksPanel::onActionsButtonClick()
mGearFolderMenu->getChild<LLMenuItemCallGL>("collapse")->setVisible(cur_item->isOpen());
menu = mGearFolderMenu;
}
- if(menu)
- {
- menu->buildDrawLabels();
- menu->updateParent(LLMenuGL::sMenuContainer);
- LLView* actions_btn = getChild<LLView>(OPTIONS_BUTTON_NAME);
- S32 menu_x, menu_y;
- actions_btn->localPointToOtherView(0,actions_btn->getRect().getHeight(),&menu_x,&menu_y, this);
- menu_y += menu->getRect().getHeight();
- LLMenuGL::showPopup(this, menu, menu_x,menu_y);
- }
+ showActionMenu(menu,OPTIONS_BUTTON_NAME);
}
-void LLLandmarksPanel::onAddLandmarkButtonClick() const
+void LLLandmarksPanel::onAddButtonHeldDown()
{
- if(LLLandmarkActions::landmarkAlreadyExists())
- {
- std::string location;
- LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL);
- llwarns<<" Landmark already exists at location: "<< location<<llendl;
- return;
- }
- LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));
+ showActionMenu(mMenuAdd,ADD_BUTTON_NAME);
}
-void LLLandmarksPanel::onAddFolderButtonClick() const
+void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
{
- LLFolderViewItem* item = getCurSelectedItem();
- if(item && mCurrentSelectedList == mLandmarksInventoryPanel)
+ if (menu)
{
- LLFolderViewEventListener* folder_bridge = NULL;
- if(item-> getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
- {
- // for a landmark get parent folder bridge
- folder_bridge = item->getParentFolder()->getListener();
- }
- else if (item-> getListener()->getInventoryType() == LLInventoryType::IT_CATEGORY)
- {
- // for a folder get its own bridge
- folder_bridge = item->getListener();
- }
-
- menu_create_inventory_item(mCurrentSelectedList->getRootFolder()
- , dynamic_cast<LLFolderBridge*>(folder_bridge)
- , LLSD("category")
- , gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK)
- );
+ 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);
}
}
@@ -547,11 +549,39 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
std::string command_name = userdata.asString();
if("add_landmark" == command_name)
{
- onAddLandmarkButtonClick();
+ if(LLLandmarkActions::landmarkAlreadyExists())
+ {
+ std::string location;
+ LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL);
+ llwarns<<" Landmark already exists at location: "<< location<<llendl;
+ return;
+ }
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));
}
else if ("category" == command_name)
{
- onAddFolderButtonClick();
+ LLFolderViewItem* item = getCurSelectedItem();
+ if (item && mCurrentSelectedList == mLandmarksInventoryPanel)
+ {
+ LLFolderViewEventListener* folder_bridge = NULL;
+ if (item-> getListener()->getInventoryType()
+ == LLInventoryType::IT_LANDMARK)
+ {
+ // for a landmark get parent folder bridge
+ folder_bridge = item->getParentFolder()->getListener();
+ }
+ else if (item-> getListener()->getInventoryType()
+ == LLInventoryType::IT_CATEGORY)
+ {
+ // for a folder get its own bridge
+ folder_bridge = item->getListener();
+ }
+
+ menu_create_inventory_item(mCurrentSelectedList->getRootFolder(),
+ dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD(
+ "category"), gInventory.findCategoryUUIDForType(
+ LLAssetType::AT_LANDMARK));
+ }
}
}
@@ -854,6 +884,43 @@ bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType carg
}
+void LLLandmarksPanel::doIdle(void* landmarks_panel)
+{
+ LLLandmarksPanel* panel = (LLLandmarksPanel* ) landmarks_panel;
+
+ if (panel->mDirtyFilter)
+ {
+ panel->updateFilteredAccordions();
+ }
+
+}
+
+void LLLandmarksPanel::updateFilteredAccordions()
+{
+ LLInventoryPanel* inventory_list = NULL;
+ LLAccordionCtrlTab* accordion_tab = NULL;
+ for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
+ {
+ accordion_tab = *iter;
+ inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView());
+ if (NULL == inventory_list) continue;
+ LLFolderView* fv = inventory_list->getRootFolder();
+
+ bool has_visible_children = fv->hasVisibleChildren();
+
+ accordion_tab->setVisible(has_visible_children);
+ }
+
+ // we have to arrange accordion tabs for cases when filter string is less restrictive but
+ // all items are still filtered.
+ static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion");
+ accordion->arrange();
+
+ // now filter state is applied to accordion tabs
+ mDirtyFilter = false;
+}
+
+
//////////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index 47c9f7647c..0e7abb4865 100644
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -41,6 +41,7 @@
#include "llpanelpick.h"
#include "llremoteparcelrequest.h"
+class LLAccordionCtrlTab;
class LLFolderViewItem;
class LLMenuGL;
class LLInventoryPanel;
@@ -90,8 +91,8 @@ private:
void initListCommandsHandlers();
void updateListCommands();
void onActionsButtonClick();
- void onAddLandmarkButtonClick() const;
- void onAddFolderButtonClick() const;
+ void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
+ void onAddButtonHeldDown();
void onTrashButtonClick() const;
void onAddAction(const LLSD& command_name) const;
void onClipboardAction(const LLSD& command_name) const;
@@ -114,6 +115,18 @@ private:
*/
bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept);
+ /**
+ * Static callback for gIdleCallbacks to perform actions out of drawing
+ */
+ static void doIdle(void* landmarks_panel);
+
+ /**
+ * Updates accordions according to filtered items in lists.
+ *
+ * It hides accordion for empty lists
+ */
+ void updateFilteredAccordions();
+
private:
LLInventorySubTreePanel* mFavoritesInventoryPanel;
LLInventorySubTreePanel* mLandmarksInventoryPanel;
@@ -121,10 +134,15 @@ private:
LLInventorySubTreePanel* mLibraryInventoryPanel;
LLMenuGL* mGearLandmarkMenu;
LLMenuGL* mGearFolderMenu;
+ LLMenuGL* mMenuAdd;
LLInventorySubTreePanel* mCurrentSelectedList;
LLPanel* mListCommands;
bool mSortByDate;
+ bool mDirtyFilter;
+
+ typedef std::vector<LLAccordionCtrlTab*> accordion_tabs_t;
+ accordion_tabs_t mAccordionTabs;
};
#endif //LL_LLPANELLANDMARKS_H
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 61d66873ea..4580eeb336 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -413,13 +413,17 @@ BOOL LLPanelPeople::postBuild()
mOnlineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_online");
mAllFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_all");
mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
+ mOnlineFriendList->setShowIcons("FriendsListShowIcons");
mAllFriendList->setNoItemsCommentText(getString("no_friends"));
+ mAllFriendList->setShowIcons("FriendsListShowIcons");
mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mNearbyList->setNoItemsCommentText(getString("no_one_near"));
+ mNearbyList->setShowIcons("NearbyListShowIcons");
mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mRecentList->setNoItemsCommentText(getString("no_people"));
+ mRecentList->setShowIcons("RecentListShowIcons");
mGroupList = getChild<LLGroupList>("group_list");
mGroupList->setNoItemsCommentText(getString("no_groups"));
@@ -611,6 +615,10 @@ void LLPanelPeople::updateButtons()
bool recent_tab_active = (cur_tab == RECENT_TAB_NAME);
LLUUID selected_id;
+ std::vector<LLUUID> selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+ bool item_selected = (selected_uuids.size() == 1);
+
buttonSetVisible("group_info_btn", group_tab_active);
buttonSetVisible("chat_btn", group_tab_active);
buttonSetVisible("add_friend_btn", nearby_tab_active || recent_tab_active);
@@ -621,7 +629,6 @@ void LLPanelPeople::updateButtons()
if (group_tab_active)
{
- bool item_selected = mGroupList->getSelectedItem() != NULL;
bool cur_group_active = true;
if (item_selected)
@@ -629,7 +636,7 @@ void LLPanelPeople::updateButtons()
selected_id = mGroupList->getSelectedUUID();
cur_group_active = (gAgent.getGroupID() == selected_id);
}
-
+
LLPanel* groups_panel = mTabContainer->getCurrentPanel();
groups_panel->childSetEnabled("activate_btn", item_selected && !cur_group_active); // "none" or a non-active group selected
groups_panel->childSetEnabled("plus_btn", item_selected);
@@ -640,18 +647,18 @@ void LLPanelPeople::updateButtons()
bool is_friend = true;
// Check whether selected avatar is our friend.
- if ((selected_id = getCurrentItemID()).notNull())
+ if (item_selected)
{
+ selected_id = selected_uuids.front();
is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;
}
childSetEnabled("add_friend_btn", !is_friend);
}
- bool item_selected = selected_id.notNull();
buttonSetEnabled("teleport_btn", friends_tab_active && item_selected);
buttonSetEnabled("view_profile_btn", item_selected);
- buttonSetEnabled("im_btn", item_selected);
+ buttonSetEnabled("im_btn", (selected_uuids.size() >= 1)); // allow starting the friends conference for multiple selection
buttonSetEnabled("call_btn", item_selected && false); // not implemented yet
buttonSetEnabled("share_btn", item_selected && false); // not implemented yet
buttonSetEnabled("group_info_btn", item_selected);
@@ -877,7 +884,17 @@ void LLPanelPeople::onAddFriendWizButtonClicked()
void LLPanelPeople::onDeleteFriendButtonClicked()
{
- LLAvatarActions::removeFriendDialog(getCurrentItemID());
+ std::vector<LLUUID> selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+
+ if (selected_uuids.size() == 1)
+ {
+ LLAvatarActions::removeFriendDialog( selected_uuids.front() );
+ }
+ else if (selected_uuids.size() > 1)
+ {
+ LLAvatarActions::removeFriendsDialog( selected_uuids );
+ }
}
void LLPanelPeople::onGroupInfoButtonClicked()
@@ -963,6 +980,8 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
+ mAllFriendList->toggleIcons();
+ mOnlineFriendList->toggleIcons();
}
else if (chosen_item == "organize_offline")
{
@@ -992,6 +1011,7 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
+ mNearbyList->toggleIcons();
}
else if (chosen_item == "sort_distance")
{
@@ -1011,7 +1031,7 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- // *TODO: implement showing/hiding icons
+ mRecentList->toggleIcons();
}
}
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index cb9f7184f0..5af27a5ec1 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -55,6 +55,8 @@
#include "llagent.h"
#include "llagentui.h"
#include "llavatarpropertiesprocessor.h"
+#include "llcallbacklist.h"
+#include "llexpandabletextbox.h"
#include "llfloaterworldmap.h"
#include "llfloaterbuycurrency.h"
#include "llinventorymodel.h"
@@ -65,6 +67,7 @@
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
+#include "llviewercontrol.h"
#include "llviewertexteditor.h"
#include "llworldmap.h"
#include "llsdutil_math.h"
@@ -76,7 +79,6 @@
typedef std::pair<LLUUID, std::string> folder_pair_t;
static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right);
-static std::string getFullFolderName(const LLViewerInventoryCategory* cat);
static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats);
static LLRegisterPanelClassWrapper<LLPanelPlaceInfo> t_place_info("panel_place_info");
@@ -111,7 +113,7 @@ BOOL LLPanelPlaceInfo::postBuild()
mForSalePanel = getChild<LLPanel>("for_sale_panel");
mYouAreHerePanel = getChild<LLPanel>("here_panel");
- LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLPanelPlaceInfo::updateYouAreHereBanner,this));
+ gIdleCallbacks.addFunction(&LLPanelPlaceInfo::updateYouAreHereBanner, this);
//Icon value should contain sale price of last selected parcel.
mForSalePanel->getChild<LLIconCtrl>("icon_for_sale")->
@@ -120,7 +122,7 @@ BOOL LLPanelPlaceInfo::postBuild()
mSnapshotCtrl = getChild<LLTextureCtrl>("logo");
mRegionName = getChild<LLTextBox>("region_title");
mParcelName = getChild<LLTextBox>("parcel_title");
- mDescEditor = getChild<LLTextEditor>("description");
+ mDescEditor = getChild<LLExpandableTextBox>("description");
mMaturityRatingText = getChild<LLTextBox>("maturity_value");
mParcelOwner = getChild<LLTextBox>("owner_value");
@@ -456,13 +458,13 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)
mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id);
}
- if(!parcel_data.name.empty())
+ if(!parcel_data.sim_name.empty())
{
- mParcelName->setText(parcel_data.name);
+ mRegionName->setText(parcel_data.sim_name);
}
else
{
- mParcelName->setText(LLStringUtil::null);
+ mRegionName->setText(LLStringUtil::null);
}
if(!parcel_data.desc.empty())
@@ -509,19 +511,22 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)
region_z = llround(mPosRegion.mV[VZ]);
}
- std::string name = getString("not_available");
- if (!parcel_data.sim_name.empty())
+ if (!parcel_data.name.empty())
{
- name = llformat("%s (%d, %d, %d)",
- parcel_data.sim_name.c_str(), region_x, region_y, region_z);
- mRegionName->setText(name);
+ mParcelName->setText(llformat("%s (%d, %d, %d)",
+ parcel_data.name.c_str(), region_x, region_y, region_z));
+ }
+ else
+ {
+ mParcelName->setText(getString("not_available"));
}
if (mInfoType == CREATE_LANDMARK)
{
if (parcel_data.name.empty())
{
- mTitleEditor->setText(name);
+ mTitleEditor->setText(llformat("%s (%d, %d, %d)",
+ parcel_data.sim_name.c_str(), region_x, region_y, region_z));
}
else
{
@@ -610,6 +615,9 @@ void LLPanelPlaceInfo::displaySelectedParcelInfo(LLParcel* parcel,
parcel_data.name = parcel->getName();
parcel_data.sim_name = region->getName();
parcel_data.snapshot_id = parcel->getSnapshotID();
+ mPosRegion.setVec((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS),
+ (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS),
+ (F32)pos_global.mdV[VZ]);
parcel_data.global_x = pos_global.mdV[VX];
parcel_data.global_y = pos_global.mdV[VY];
parcel_data.global_z = pos_global.mdV[VZ];
@@ -986,18 +994,22 @@ void LLPanelPlaceInfo::populateFoldersList()
mFolderCombo->add(it->second, LLSD(it->first));
}
-void LLPanelPlaceInfo::updateYouAreHereBanner()
+//static
+void LLPanelPlaceInfo::updateYouAreHereBanner(void* userdata)
{
//YouAreHere Banner should be displayed only for selected places,
// If you want to display it for landmark or teleport history item, you should check by mParcelId
- bool is_you_are_here = false;
- if (mSelectedParcelID != S32(-1) && !mLastSelectedRegionID.isNull())
- {
- is_you_are_here = gAgent.getRegion()->getRegionID()== mLastSelectedRegionID &&
- mSelectedParcelID == LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID();
- }
- mYouAreHerePanel->setVisible(is_you_are_here);
+ LLPanelPlaceInfo* self = static_cast<LLPanelPlaceInfo*>(userdata);
+ if(!self->getVisible())
+ return;
+
+ static F32 radius = gSavedSettings.getF32("YouAreHereDistance");
+
+ BOOL display_banner = self->mLastSelectedRegionID == gAgent.getRegion()->getRegionID() &&
+ LLAgentUI::checkAgentDistance(self->mPosRegion, radius);
+
+ self->mYouAreHerePanel->setVisible(display_banner);
}
void LLPanelPlaceInfo::onForSaleBannerClick()
@@ -1028,14 +1040,9 @@ void LLPanelPlaceInfo::onForSaleBannerClick()
}
-
-
-static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right)
-{
- return left.second < right.second;
-}
-static std::string getFullFolderName(const LLViewerInventoryCategory* cat)
+/*static*/
+std::string LLPanelPlaceInfo::getFullFolderName(const LLViewerInventoryCategory* cat)
{
std::string name = cat->getName();
LLUUID parent_id;
@@ -1057,6 +1064,11 @@ static std::string getFullFolderName(const LLViewerInventoryCategory* cat)
return name;
}
+static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right)
+{
+ return left.second < right.second;
+}
+
static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)
{
LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h
index 7b3a8f050b..07a2434d59 100644
--- a/indra/newview/llpanelplaceinfo.h
+++ b/indra/newview/llpanelplaceinfo.h
@@ -43,6 +43,7 @@
class LLButton;
class LLComboBox;
+class LLExpandableTextBox;
class LLInventoryItem;
class LLLineEditor;
class LLPanelPickEdit;
@@ -52,6 +53,7 @@ class LLTextBox;
class LLTextEditor;
class LLTextureCtrl;
class LLViewerRegion;
+class LLViewerInventoryCategory;
class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver
{
@@ -131,11 +133,13 @@ public:
/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
/*virtual*/ void handleVisibilityChange (BOOL new_visibility);
+
+ static std::string getFullFolderName(const LLViewerInventoryCategory* cat);
private:
void populateFoldersList();
- void updateYouAreHereBanner();
+ static void updateYouAreHereBanner(void*);// added to gIdleCallbacks
void onForSaleBannerClick();
/**
@@ -161,7 +165,7 @@ private:
LLTextureCtrl* mSnapshotCtrl;
LLTextBox* mRegionName;
LLTextBox* mParcelName;
- LLTextEditor* mDescEditor;
+ LLExpandableTextBox*mDescEditor;
LLTextBox* mMaturityRatingText;
LLTextBox* mParcelOwner;
LLTextBox* mLastVisited;
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 5ab823b6e5..b2e9110e96 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -351,7 +351,16 @@ void LLPanelPlaces::setItem(LLInventoryItem* item)
if (is_landmark_editable)
{
- mPlaceInfo->setLandmarkFolder(mItem->getParentUUID());
+ if(!mPlaceInfo->setLandmarkFolder(mItem->getParentUUID()) && !mItem->getParentUUID().isNull())
+ {
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(mItem->getParentUUID());
+ if(cat)
+ {
+ std::string cat_fullname = LLPanelPlaceInfo::getFullFolderName(cat);
+ LLComboBox* folderList = mPlaceInfo->getChild<LLComboBox>("folder_combo");
+ folderList->add(cat_fullname, cat->getUUID(),ADD_TOP);
+ }
+ }
}
mPlaceInfo->displayItemInfo(mItem);
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
new file mode 100644
index 0000000000..ca7ebb1ad8
--- /dev/null
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -0,0 +1,1095 @@
+/**
+ * @file llpanelprimmediacontrols.cpp
+ * @brief media controls popup panel
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2007, 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"
+
+//LLPanelPrimMediaControls
+#include "llagent.h"
+#include "llparcel.h"
+#include "llpanel.h"
+#include "llselectmgr.h"
+#include "llmediaentry.h"
+#include "llrender.h"
+#include "lldrawable.h"
+#include "llviewerwindow.h"
+#include "lluictrlfactory.h"
+#include "llbutton.h"
+#include "llface.h"
+#include "llcombobox.h"
+#include "llslider.h"
+#include "llhudview.h"
+#include "lliconctrl.h"
+#include "lltoolpie.h"
+#include "llviewercamera.h"
+#include "llviewerobjectlist.h"
+#include "llpanelprimmediacontrols.h"
+#include "llpluginclassmedia.h"
+#include "llprogressbar.h"
+#include "llviewercontrol.h"
+#include "llviewerparcelmgr.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
+#include "llvovolume.h"
+#include "llweb.h"
+#include "llwindow.h"
+
+glh::matrix4f glh_get_current_modelview();
+glh::matrix4f glh_get_current_projection();
+
+const F32 ZOOM_NEAR_PADDING = 1.0f;
+const F32 ZOOM_MEDIUM_PADDING = 1.15f;
+const F32 ZOOM_FAR_PADDING = 1.5f;
+
+// Warning: make sure these two match!
+const LLPanelPrimMediaControls::EZoomLevel LLPanelPrimMediaControls::kZoomLevels[] = { ZOOM_NONE, ZOOM_MEDIUM };
+const int LLPanelPrimMediaControls::kNumZoomLevels = 2;
+
+//
+// LLPanelPrimMediaControls
+//
+
+LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
+ mAlpha(1.f),
+ mCurrentURL(""),
+ mPreviousURL(""),
+ mPauseFadeout(false),
+ mUpdateSlider(true),
+ mClearFaceOnFade(false),
+ mCurrentRate(0.0),
+ mMovieDuration(0.0),
+ mUpdatePercent(0)
+{
+ mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Forward", boost::bind(&LLPanelPrimMediaControls::onClickForward, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Home", boost::bind(&LLPanelPrimMediaControls::onClickHome, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Stop", boost::bind(&LLPanelPrimMediaControls::onClickStop, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Reload", boost::bind(&LLPanelPrimMediaControls::onClickReload, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Play", boost::bind(&LLPanelPrimMediaControls::onClickPlay, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Pause", boost::bind(&LLPanelPrimMediaControls::onClickPause, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Open", boost::bind(&LLPanelPrimMediaControls::onClickOpen, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Zoom", boost::bind(&LLPanelPrimMediaControls::onClickZoom, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", boost::bind(&LLPanelPrimMediaControls::onCommitURL, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.JumpProgress", boost::bind(&LLPanelPrimMediaControls::onCommitSlider, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", boost::bind(&LLPanelPrimMediaControls::onToggleMute, this));
+
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_prim_media_controls.xml");
+ mInactivityTimer.reset();
+ mFadeTimer.stop();
+ mCurrentZoom = ZOOM_NONE;
+ mScrollState = SCROLL_NONE;
+
+ mPanelHandle.bind(this);
+}
+LLPanelPrimMediaControls::~LLPanelPrimMediaControls()
+{
+}
+
+BOOL LLPanelPrimMediaControls::postBuild()
+{
+ LLButton* scroll_up_ctrl = getChild<LLButton>("scrollup");
+ scroll_up_ctrl->setClickedCallback(onScrollUp, this);
+ scroll_up_ctrl->setHeldDownCallback(onScrollUpHeld, this);
+ scroll_up_ctrl->setMouseUpCallback(onScrollStop, this);
+ LLButton* scroll_left_ctrl = getChild<LLButton>("scrollleft");
+ scroll_left_ctrl->setClickedCallback(onScrollLeft, this);
+ scroll_left_ctrl->setHeldDownCallback(onScrollLeftHeld, this);
+ scroll_left_ctrl->setMouseUpCallback(onScrollStop, this);
+ LLButton* scroll_right_ctrl = getChild<LLButton>("scrollright");
+ scroll_right_ctrl->setClickedCallback(onScrollRight, this);
+ scroll_right_ctrl->setHeldDownCallback(onScrollLeftHeld, this);
+ scroll_right_ctrl->setMouseUpCallback(onScrollStop, this);
+ LLButton* scroll_down_ctrl = getChild<LLButton>("scrolldown");
+ scroll_down_ctrl->setClickedCallback(onScrollDown, this);
+ scroll_down_ctrl->setHeldDownCallback(onScrollDownHeld, this);
+ scroll_down_ctrl->setMouseUpCallback(onScrollStop, this);
+
+ LLUICtrl* media_address = getChild<LLUICtrl>("media_address");
+ media_address->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this ));
+ mInactiveTimeout = gSavedSettings.getF32("MediaControlTimeout");
+ mControlFadeTime = gSavedSettings.getF32("MediaControlFadeTime");
+
+ mCurrentZoom = ZOOM_NONE;
+ // clicks on HUD buttons do not remove keyboard focus from media
+ setIsChrome(TRUE);
+ return TRUE;
+}
+
+void LLPanelPrimMediaControls::setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal)
+{
+ if (media_impl.notNull() && objectp.notNull())
+ {
+ mTargetImplID = media_impl->getMediaTextureID();
+ mTargetObjectID = objectp->getID();
+ mTargetObjectFace = face;
+ mTargetObjectNormal = pick_normal;
+ mClearFaceOnFade = false;
+ }
+ else
+ {
+ // This happens on a timer now.
+// mTargetImplID = LLUUID::null;
+// mTargetObjectID = LLUUID::null;
+// mTargetObjectFace = 0;
+ mClearFaceOnFade = true;
+ }
+
+ updateShape();
+}
+
+void LLPanelPrimMediaControls::focusOnTarget()
+{
+ // Sets the media focus to the current target of the LLPanelPrimMediaControls.
+ // This is how we transition from hover to focus when the user clicks on a control.
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ if(media_impl)
+ {
+ if(!media_impl->hasFocus())
+ {
+ // The current target doesn't have media focus -- focus on it.
+ LLViewerObject* objectp = getTargetObject();
+ LLViewerMediaFocus::getInstance()->setFocusFace(objectp, mTargetObjectFace, media_impl, mTargetObjectNormal);
+ }
+ }
+}
+
+LLViewerMediaImpl* LLPanelPrimMediaControls::getTargetMediaImpl()
+{
+ return LLViewerMedia::getMediaImplFromTextureID(mTargetImplID);
+}
+
+LLViewerObject* LLPanelPrimMediaControls::getTargetObject()
+{
+ return gObjectList.findObject(mTargetObjectID);
+}
+
+LLPluginClassMedia* LLPanelPrimMediaControls::getTargetMediaPlugin()
+{
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+ if(impl && impl->hasMedia())
+ {
+ return impl->getMediaPlugin();
+ }
+
+ return NULL;
+}
+
+void LLPanelPrimMediaControls::updateShape()
+{
+ const S32 MIN_HUD_WIDTH=400;
+ const S32 MIN_HUD_HEIGHT=120;
+
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ LLViewerObject* objectp = getTargetObject();
+
+ if(!media_impl)
+ {
+ setVisible(FALSE);
+ return;
+ }
+
+ LLPluginClassMedia* media_plugin = NULL;
+ if(media_impl->hasMedia())
+ {
+ media_plugin = media_impl->getMediaPlugin();
+ }
+
+ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+
+ bool can_navigate = parcel->getMediaAllowNavigate();
+ bool enabled = false;
+ bool has_focus = media_impl->hasFocus();
+ setVisible(enabled);
+
+ if (objectp)
+ {
+ bool mini_controls = false;
+ LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData();
+ if (media_data && NULL != dynamic_cast<LLVOVolume*>(objectp))
+ {
+ // Don't show the media HUD if we do not have permissions
+ enabled = dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL);
+ mini_controls = (LLMediaEntry::MINI == media_data->getControls());
+ }
+
+ //
+ // Set the state of the buttons
+ //
+ LLUICtrl* back_ctrl = getChild<LLUICtrl>("back");
+ LLUICtrl* fwd_ctrl = getChild<LLUICtrl>("fwd");
+ LLUICtrl* reload_ctrl = getChild<LLUICtrl>("reload");
+ LLUICtrl* play_ctrl = getChild<LLUICtrl>("play");
+ LLUICtrl* pause_ctrl = getChild<LLUICtrl>("pause");
+ LLUICtrl* stop_ctrl = getChild<LLUICtrl>("stop");
+ LLUICtrl* media_stop_ctrl = getChild<LLUICtrl>("media_stop");
+ LLUICtrl* home_ctrl = getChild<LLUICtrl>("home");
+ LLUICtrl* close_ctrl = getChild<LLUICtrl>("close");
+ LLUICtrl* open_ctrl = getChild<LLUICtrl>("new_window");
+ LLUICtrl* zoom_ctrl = getChild<LLUICtrl>("zoom_frame");
+ LLPanel* media_loading_panel = getChild<LLPanel>("media_progress_indicator");
+ LLUICtrl* media_address_ctrl = getChild<LLUICtrl>("media_address");
+ LLUICtrl* media_play_slider_ctrl = getChild<LLUICtrl>("media_play_position");
+ LLUICtrl* volume_ctrl = getChild<LLUICtrl>("media_volume");
+ LLButton* volume_btn = getChild<LLButton>("media_volume_button");
+ LLUICtrl* volume_up_ctrl = getChild<LLUICtrl>("volume_up");
+ LLUICtrl* volume_down_ctrl = getChild<LLUICtrl>("volume_down");
+ LLIconCtrl* whitelist_icon = getChild<LLIconCtrl>("media_whitelist_flag");
+ LLIconCtrl* secure_lock_icon = getChild<LLIconCtrl>("media_secure_lock_flag");
+
+ LLUICtrl* media_panel_scroll = getChild<LLUICtrl>("media_panel_scroll");
+ LLUICtrl* scroll_up_ctrl = getChild<LLUICtrl>("scrollup");
+ LLUICtrl* scroll_left_ctrl = getChild<LLUICtrl>("scrollleft");
+ LLUICtrl* scroll_right_ctrl = getChild<LLUICtrl>("scrollright");
+ LLUICtrl* scroll_down_ctrl = getChild<LLUICtrl>("scrolldown");
+
+ // XXX RSP: TODO: FIXME: clean this up so that it is clearer what mode we are in,
+ // and that only the proper controls get made visible/enabled according to that mode.
+ back_ctrl->setVisible(has_focus);
+ fwd_ctrl->setVisible(has_focus);
+ reload_ctrl->setVisible(has_focus);
+ stop_ctrl->setVisible(false);
+ home_ctrl->setVisible(has_focus);
+ close_ctrl->setVisible(has_focus);
+ open_ctrl->setVisible(true);
+ media_address_ctrl->setVisible(has_focus && !mini_controls);
+ media_play_slider_ctrl->setVisible(has_focus && !mini_controls);
+ volume_ctrl->setVisible(false);
+ volume_up_ctrl->setVisible(false);
+ volume_down_ctrl->setVisible(false);
+
+ whitelist_icon->setVisible(!mini_controls && (media_data)?media_data->getWhiteListEnable():false);
+ // Disable zoom if HUD
+ zoom_ctrl->setEnabled(!objectp->isHUDAttachment());
+ secure_lock_icon->setVisible(false);
+ mCurrentURL = media_impl->getMediaURL();
+
+ back_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate);
+ fwd_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateForward() && can_navigate);
+ stop_ctrl->setEnabled(has_focus && can_navigate);
+ home_ctrl->setEnabled(has_focus && can_navigate);
+ LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE;
+
+ if(media_plugin && media_plugin->pluginSupportsMediaTime())
+ {
+ reload_ctrl->setEnabled(FALSE);
+ reload_ctrl->setVisible(FALSE);
+ media_stop_ctrl->setVisible(has_focus);
+ home_ctrl->setVisible(FALSE);
+ back_ctrl->setEnabled(has_focus);
+ fwd_ctrl->setEnabled(has_focus);
+ media_address_ctrl->setVisible(false);
+ media_address_ctrl->setEnabled(false);
+ media_play_slider_ctrl->setVisible(!mini_controls);
+ media_play_slider_ctrl->setEnabled(!mini_controls);
+
+ volume_ctrl->setVisible(has_focus);
+ volume_up_ctrl->setVisible(has_focus);
+ volume_down_ctrl->setVisible(has_focus);
+ volume_ctrl->setEnabled(has_focus);
+
+ whitelist_icon->setVisible(false);
+ secure_lock_icon->setVisible(false);
+ scroll_up_ctrl->setVisible(false);
+ scroll_left_ctrl->setVisible(false);
+ scroll_right_ctrl->setVisible(false);
+ scroll_down_ctrl->setVisible(false);
+ media_panel_scroll->setVisible(false);
+
+ F32 volume = media_impl->getVolume();
+ // movie's url changed
+ if(mCurrentURL!=mPreviousURL)
+ {
+ mMovieDuration = media_plugin->getDuration();
+ mPreviousURL = mCurrentURL;
+ }
+
+ if(mMovieDuration == 0)
+ {
+ mMovieDuration = media_plugin->getDuration();
+ media_play_slider_ctrl->setValue(0);
+ media_play_slider_ctrl->setEnabled(false);
+ }
+ // TODO: What if it's not fully loaded
+
+ if(mUpdateSlider && mMovieDuration!= 0)
+ {
+ F64 current_time = media_plugin->getCurrentTime();
+ F32 percent = current_time / mMovieDuration;
+ media_play_slider_ctrl->setValue(percent);
+ media_play_slider_ctrl->setEnabled(true);
+ }
+
+ // video vloume
+ if(volume <= 0.0)
+ {
+ volume_up_ctrl->setEnabled(TRUE);
+ volume_down_ctrl->setEnabled(FALSE);
+ media_impl->setVolume(0.0);
+ volume_btn->setToggleState(true);
+ }
+ else if (volume >= 1.0)
+ {
+ volume_up_ctrl->setEnabled(FALSE);
+ volume_down_ctrl->setEnabled(TRUE);
+ media_impl->setVolume(1.0);
+ volume_btn->setToggleState(false);
+ }
+ else
+ {
+ volume_up_ctrl->setEnabled(TRUE);
+ volume_down_ctrl->setEnabled(TRUE);
+ }
+
+ switch(result)
+ {
+ case LLPluginClassMediaOwner::MEDIA_PLAYING:
+ play_ctrl->setEnabled(FALSE);
+ play_ctrl->setVisible(FALSE);
+ pause_ctrl->setEnabled(TRUE);
+ pause_ctrl->setVisible(has_focus);
+ media_stop_ctrl->setEnabled(TRUE);
+
+ break;
+ case LLPluginClassMediaOwner::MEDIA_PAUSED:
+ default:
+ pause_ctrl->setEnabled(FALSE);
+ pause_ctrl->setVisible(FALSE);
+ play_ctrl->setEnabled(TRUE);
+ play_ctrl->setVisible(has_focus);
+ media_stop_ctrl->setEnabled(FALSE);
+ break;
+ }
+ }
+ else // web based
+ {
+ if(media_plugin)
+ {
+ mCurrentURL = media_plugin->getLocation();
+ }
+ else
+ {
+ mCurrentURL.clear();
+ }
+
+ play_ctrl->setVisible(FALSE);
+ pause_ctrl->setVisible(FALSE);
+ media_stop_ctrl->setVisible(FALSE);
+ media_address_ctrl->setVisible(has_focus && !mini_controls);
+ media_address_ctrl->setEnabled(has_focus && !mini_controls);
+ media_play_slider_ctrl->setVisible(FALSE);
+ media_play_slider_ctrl->setEnabled(FALSE);
+
+ volume_ctrl->setVisible(FALSE);
+ volume_up_ctrl->setVisible(FALSE);
+ volume_down_ctrl->setVisible(FALSE);
+ volume_ctrl->setEnabled(FALSE);
+ volume_up_ctrl->setEnabled(FALSE);
+ volume_down_ctrl->setEnabled(FALSE);
+
+ scroll_up_ctrl->setVisible(has_focus);
+ scroll_left_ctrl->setVisible(has_focus);
+ scroll_right_ctrl->setVisible(has_focus);
+ scroll_down_ctrl->setVisible(has_focus);
+ media_panel_scroll->setVisible(has_focus);
+ // TODO: get the secure lock bool from media plug in
+ std::string prefix = std::string("https://");
+ std::string test_prefix = mCurrentURL.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if(test_prefix == prefix)
+ {
+ secure_lock_icon->setVisible(has_focus);
+ }
+
+ if(mCurrentURL!=mPreviousURL)
+ {
+ setCurrentURL();
+ mPreviousURL = mCurrentURL;
+ }
+
+ if(result == LLPluginClassMediaOwner::MEDIA_LOADING)
+ {
+ reload_ctrl->setEnabled(FALSE);
+ reload_ctrl->setVisible(FALSE);
+ stop_ctrl->setEnabled(TRUE);
+ stop_ctrl->setVisible(has_focus);
+ }
+ else
+ {
+ reload_ctrl->setEnabled(TRUE);
+ reload_ctrl->setVisible(has_focus);
+ stop_ctrl->setEnabled(FALSE);
+ stop_ctrl->setVisible(FALSE);
+ }
+ }
+
+
+ if(media_plugin)
+ {
+ //
+ // Handle progress bar
+ //
+ mUpdatePercent = media_plugin->getProgressPercent();
+ if(mUpdatePercent<100.0f)
+ {
+ media_loading_panel->setVisible(true);
+ getChild<LLProgressBar>("media_progress_bar")->setPercent(mUpdatePercent);
+ gFocusMgr.setTopCtrl(media_loading_panel);
+ }
+ else
+ {
+ media_loading_panel->setVisible(false);
+ gFocusMgr.setTopCtrl(NULL);
+ }
+ }
+
+ if(media_plugin)
+ {
+ //
+ // Handle Scrolling
+ //
+ switch (mScrollState)
+ {
+ case SCROLL_UP:
+ media_plugin->scrollEvent(0, -1, MASK_NONE);
+ break;
+ case SCROLL_DOWN:
+ media_plugin->scrollEvent(0, 1, MASK_NONE);
+ break;
+ case SCROLL_LEFT:
+ media_impl->handleKeyHere(KEY_LEFT, MASK_NONE);
+ break;
+ case SCROLL_RIGHT:
+ media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE);
+ break;
+ case SCROLL_NONE:
+ default:
+ break;
+ }
+ }
+
+ setVisible(enabled);
+
+ //
+ // Calculate position and shape of the controls
+ //
+ glh::matrix4f mat = glh_get_current_projection()*glh_get_current_modelview();
+ std::vector<LLVector3>::iterator vert_it;
+ std::vector<LLVector3>::iterator vert_end;
+ std::vector<LLVector3> vect_face;
+
+ LLVolume* volume = objectp->getVolume();
+
+ if (volume)
+ {
+ const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace);
+
+ const LLVector3* ext = vf.mExtents;
+
+ LLVector3 center = (ext[0]+ext[1])*0.5f;
+ LLVector3 size = (ext[1]-ext[0])*0.5f;
+ LLVector3 vert[] =
+ {
+ center + size.scaledVec(LLVector3(1,1,1)),
+ center + size.scaledVec(LLVector3(-1,1,1)),
+ center + size.scaledVec(LLVector3(1,-1,1)),
+ center + size.scaledVec(LLVector3(-1,-1,1)),
+ center + size.scaledVec(LLVector3(1,1,-1)),
+ center + size.scaledVec(LLVector3(-1,1,-1)),
+ center + size.scaledVec(LLVector3(1,-1,-1)),
+ center + size.scaledVec(LLVector3(-1,-1,-1)),
+ };
+
+ LLVOVolume* vo = (LLVOVolume*) objectp;
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ vect_face.push_back(vo->volumePositionToAgent(vert[i]));
+ }
+ }
+ vert_it = vect_face.begin();
+ vert_end = vect_face.end();
+
+ LLVector3 min = LLVector3(1,1,1);
+ LLVector3 max = LLVector3(-1,-1,-1);
+ for(; vert_it != vert_end; ++vert_it)
+ {
+ // project silhouette vertices into screen space
+ glh::vec3f screen_vert = glh::vec3f(vert_it->mV);
+ mat.mult_matrix_vec(screen_vert);
+
+ // add to screenspace bounding box
+ update_min_max(min, max, LLVector3(screen_vert.v));
+ }
+
+ LLCoordGL screen_min;
+ screen_min.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (min.mV[VX] + 1.f) * 0.5f);
+ screen_min.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (min.mV[VY] + 1.f) * 0.5f);
+
+ LLCoordGL screen_max;
+ screen_max.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (max.mV[VX] + 1.f) * 0.5f);
+ screen_max.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (max.mV[VY] + 1.f) * 0.5f);
+
+ // grow panel so that screenspace bounding box fits inside "media_region" element of HUD
+ LLRect media_controls_rect;
+ getParent()->screenRectToLocal(LLRect(screen_min.mX, screen_max.mY, screen_max.mX, screen_min.mY), &media_controls_rect);
+ LLView* media_region = getChild<LLView>("media_region");
+ media_controls_rect.mLeft -= media_region->getRect().mLeft;
+ media_controls_rect.mBottom -= media_region->getRect().mBottom;
+ media_controls_rect.mTop += getRect().getHeight() - media_region->getRect().mTop;
+ media_controls_rect.mRight += getRect().getWidth() - media_region->getRect().mRight;
+
+ LLRect old_hud_rect = media_controls_rect;
+ // keep all parts of HUD on-screen
+ media_controls_rect.intersectWith(getParent()->getLocalRect());
+
+ // clamp to minimum size, keeping centered
+ media_controls_rect.setCenterAndSize(media_controls_rect.getCenterX(), media_controls_rect.getCenterY(),
+ llmax(MIN_HUD_WIDTH, media_controls_rect.getWidth()), llmax(MIN_HUD_HEIGHT, media_controls_rect.getHeight()));
+
+ setShape(media_controls_rect, true);
+
+ // Test mouse position to see if the cursor is stationary
+ LLCoordWindow cursor_pos_window;
+ getWindow()->getCursorPosition(&cursor_pos_window);
+
+ // If last pos is not equal to current pos, the mouse has moved
+ // We need to reset the timer, and make sure the panel is visible
+ if(cursor_pos_window.mX != mLastCursorPos.mX ||
+ cursor_pos_window.mY != mLastCursorPos.mY ||
+ mScrollState != SCROLL_NONE)
+ {
+ mInactivityTimer.start();
+ mLastCursorPos = cursor_pos_window;
+ }
+
+ if(isMouseOver())
+ {
+ // Never fade the controls if the mouse is over them.
+ mFadeTimer.stop();
+ }
+ else if(!mClearFaceOnFade && (mInactivityTimer.getElapsedTimeF32() < mInactiveTimeout))
+ {
+ // Mouse is over the object, but has not been stationary for long enough to fade the UI
+ mFadeTimer.stop();
+ }
+ else if(! mFadeTimer.getStarted() )
+ {
+ // we need to start fading the UI (and we have not already started)
+ mFadeTimer.reset();
+ mFadeTimer.start();
+ }
+ else
+ {
+ // I don't think this is correct anymore. This is done in draw() after the fade has completed.
+// setVisible(FALSE);
+ }
+ }
+}
+
+/*virtual*/
+void LLPanelPrimMediaControls::draw()
+{
+ F32 alpha = 1.f;
+ if(mFadeTimer.getStarted())
+ {
+ F32 time = mFadeTimer.getElapsedTimeF32();
+ alpha = llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f);
+
+ if(mFadeTimer.getElapsedTimeF32() >= mControlFadeTime)
+ {
+ setVisible(FALSE);
+ if(mClearFaceOnFade)
+ {
+ mClearFaceOnFade = false;
+ mTargetImplID = LLUUID::null;
+ mTargetObjectID = LLUUID::null;
+ mTargetObjectFace = 0;
+ }
+ }
+ }
+
+ {
+ LLViewDrawContext context(alpha);
+ LLPanel::draw();
+ }
+}
+
+BOOL LLPanelPrimMediaControls::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ mInactivityTimer.start();
+ return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks);
+}
+
+BOOL LLPanelPrimMediaControls::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ mInactivityTimer.start();
+ return LLPanel::handleMouseDown(x, y, mask);
+}
+
+BOOL LLPanelPrimMediaControls::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ mInactivityTimer.start();
+ return LLPanel::handleMouseUp(x, y, mask);
+}
+
+BOOL LLPanelPrimMediaControls::handleKeyHere( KEY key, MASK mask )
+{
+ mInactivityTimer.start();
+ return LLPanel::handleKeyHere(key, mask);
+}
+
+bool LLPanelPrimMediaControls::isMouseOver()
+{
+ bool result = false;
+
+ if( getVisible() )
+ {
+ LLCoordWindow cursor_pos_window;
+ LLCoordScreen cursor_pos_screen;
+ LLCoordGL cursor_pos_gl;
+ S32 x, y;
+ getWindow()->getCursorPosition(&cursor_pos_window);
+ getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
+
+ LLPanel* controls_panel = NULL;
+ controls_panel = getChild<LLPanel>("media_hover_controls");
+ if(controls_panel && !controls_panel->getVisible())
+ {
+ // The hover controls aren't visible -- use the focused controls instead.
+ controls_panel = getChild<LLPanel>("media_focused_controls");
+ }
+
+ if(controls_panel && controls_panel->getVisible())
+ {
+ controls_panel->screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &x, &y);
+
+ LLView *hit_child = controls_panel->childFromPoint(x, y);
+ if(hit_child)
+ {
+ // This was useful for debugging both coordinate translation and view hieararchy problems...
+// llinfos << "mouse coords: " << x << ", " << y << " hit child " << hit_child->getName() << llendl;
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+void LLPanelPrimMediaControls::onClickClose()
+{
+ close();
+}
+
+void LLPanelPrimMediaControls::close()
+{
+ LLViewerMediaFocus::getInstance()->clearFocus();
+ resetZoomLevel();
+ setVisible(FALSE);
+}
+
+
+void LLPanelPrimMediaControls::onClickBack()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl =getTargetMediaImpl();
+
+ if (impl)
+ {
+ impl->navigateBack();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickForward()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if (impl)
+ {
+ impl->navigateForward();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickHome()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->navigateHome();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickOpen()
+{
+ LLViewerMediaImpl* impl =getTargetMediaImpl();
+ if(impl)
+ {
+ if(impl->getMediaPlugin())
+ {
+ if(impl->getMediaPlugin()->getLocation().empty())
+ {
+ LLWeb::loadURL(impl->getMediaURL());
+ }
+ else
+ {
+ LLWeb::loadURL( impl->getMediaPlugin()->getLocation());
+ }
+ }
+ }
+}
+
+void LLPanelPrimMediaControls::onClickReload()
+{
+ focusOnTarget();
+
+ //LLViewerMedia::navigateHome();
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->navigateReload();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickPlay()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->play();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickPause()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->pause();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickStop()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->stop();
+ }
+}
+
+void LLPanelPrimMediaControls::onClickZoom()
+{
+ focusOnTarget();
+
+ nextZoomLevel();
+}
+void LLPanelPrimMediaControls::nextZoomLevel()
+{
+ int index = 0;
+ while (index < kNumZoomLevels)
+ {
+ if (kZoomLevels[index] == mCurrentZoom)
+ {
+ index++;
+ break;
+ }
+ index++;
+ }
+ mCurrentZoom = kZoomLevels[index % kNumZoomLevels];
+ updateZoom();
+}
+
+void LLPanelPrimMediaControls::resetZoomLevel()
+{
+ if(mCurrentZoom != ZOOM_NONE)
+ {
+ mCurrentZoom = ZOOM_NONE;
+ updateZoom();
+ }
+}
+
+void LLPanelPrimMediaControls::updateZoom()
+{
+ F32 zoom_padding = 0.0f;
+ switch (mCurrentZoom)
+ {
+ case ZOOM_NONE:
+ {
+ gAgent.setFocusOnAvatar(TRUE, ANIMATE);
+ break;
+ }
+ case ZOOM_FAR:
+ {
+ zoom_padding = ZOOM_FAR_PADDING;
+ break;
+ }
+ case ZOOM_MEDIUM:
+ {
+ zoom_padding = ZOOM_MEDIUM_PADDING;
+ break;
+ }
+ case ZOOM_NEAR:
+ {
+ zoom_padding = ZOOM_NEAR_PADDING;
+ break;
+ }
+ default:
+ {
+ gAgent.setFocusOnAvatar(TRUE, ANIMATE);
+ break;
+ }
+ }
+
+ if (zoom_padding > 0.0f)
+ LLViewerMediaFocus::setCameraZoom(getTargetObject(), mTargetObjectNormal, zoom_padding);
+}
+void LLPanelPrimMediaControls::onScrollUp(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->focusOnTarget();
+
+ LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin();
+
+ if(plugin)
+ {
+ plugin->scrollEvent(0, -1, MASK_NONE);
+ }
+}
+void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->mScrollState = SCROLL_UP;
+}
+void LLPanelPrimMediaControls::onScrollRight(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->focusOnTarget();
+
+ LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->handleKeyHere(KEY_RIGHT, MASK_NONE);
+ }
+}
+void LLPanelPrimMediaControls::onScrollRightHeld(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->mScrollState = SCROLL_RIGHT;
+}
+
+void LLPanelPrimMediaControls::onScrollLeft(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->focusOnTarget();
+
+ LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl();
+
+ if(impl)
+ {
+ impl->handleKeyHere(KEY_LEFT, MASK_NONE);
+ }
+}
+void LLPanelPrimMediaControls::onScrollLeftHeld(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->mScrollState = SCROLL_LEFT;
+}
+
+void LLPanelPrimMediaControls::onScrollDown(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->focusOnTarget();
+
+ LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin();
+
+ if(plugin)
+ {
+ plugin->scrollEvent(0, 1, MASK_NONE);
+ }
+}
+void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->mScrollState = SCROLL_DOWN;
+}
+
+void LLPanelPrimMediaControls::onScrollStop(void* user_data)
+{
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data);
+ this_panel->mScrollState = SCROLL_NONE;
+}
+
+void LLPanelPrimMediaControls::onCommitURL()
+{
+ focusOnTarget();
+
+ LLUICtrl *media_address_ctrl = getChild<LLUICtrl>("media_address_url");
+ std::string url = media_address_ctrl->getValue().asString();
+ if(getTargetMediaImpl() && !url.empty())
+ {
+ getTargetMediaImpl()->navigateTo( url, "", true);
+
+ // Make sure keyboard focus is set to the media focus object.
+ gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+
+ }
+ mPauseFadeout = false;
+ mFadeTimer.start();
+}
+
+
+void LLPanelPrimMediaControls::onInputURL(LLFocusableElement* caller, void *userdata)
+{
+
+ LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (userdata);
+ this_panel->focusOnTarget();
+
+ this_panel->mPauseFadeout = true;
+ this_panel->mFadeTimer.stop();
+ this_panel->mFadeTimer.reset();
+
+}
+
+void LLPanelPrimMediaControls::setCurrentURL()
+{
+ LLComboBox* media_address_combo = getChild<LLComboBox>("media_address_combo");
+ // redirects will navigate momentarily to about:blank, don't add to history
+ if (media_address_combo && mCurrentURL != "about:blank")
+ {
+ media_address_combo->remove(mCurrentURL);
+ media_address_combo->add(mCurrentURL, ADD_SORTED);
+ media_address_combo->selectByValue(mCurrentURL);
+ }
+}
+
+void LLPanelPrimMediaControls::onCommitSlider()
+{
+ focusOnTarget();
+
+ LLSlider* media_play_slider_ctrl = getChild<LLSlider>("media_play_slider");
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ if (media_impl)
+ {
+ // get slider value
+ F64 slider_value = media_play_slider_ctrl->getValue().asReal();
+ if(slider_value <= 0.0)
+ {
+ media_impl->stop();
+ }
+ else
+ {
+ media_impl->seek(slider_value*mMovieDuration);
+ //mUpdateSlider= false;
+ }
+ }
+}
+
+void LLPanelPrimMediaControls::onCommitVolumeUp()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ if (media_impl)
+ {
+ F32 volume = media_impl->getVolume();
+
+ volume += 0.1f;
+ if(volume >= 1.0f)
+ {
+ volume = 1.0f;
+ }
+
+ media_impl->setVolume(volume);
+ getChild<LLButton>("media_volume")->setToggleState(false);
+ }
+}
+
+void LLPanelPrimMediaControls::onCommitVolumeDown()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ if (media_impl)
+ {
+ F32 volume = media_impl->getVolume();
+
+ volume -= 0.1f;
+ if(volume <= 0.0f)
+ {
+ volume = 0.0f;
+ }
+
+ media_impl->setVolume(volume);
+ getChild<LLButton>("media_volume")->setToggleState(false);
+ }
+}
+
+
+void LLPanelPrimMediaControls::onToggleMute()
+{
+ focusOnTarget();
+
+ LLViewerMediaImpl* media_impl = getTargetMediaImpl();
+ if (media_impl)
+ {
+ F32 volume = media_impl->getVolume();
+
+ if(volume > 0.0)
+ {
+ media_impl->setVolume(0.0);
+ }
+ else
+ {
+ media_impl->setVolume(0.5);
+ }
+ }
+}
+
diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h
new file mode 100644
index 0000000000..3ec7aa2356
--- /dev/null
+++ b/indra/newview/llpanelprimmediacontrols.h
@@ -0,0 +1,148 @@
+/**
+ * @file llpanelprimmediacontrols.h
+ * @brief Pop-up media controls panel
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2007, 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 LL_PANELPRIMMEDIACONTROLS_H
+#define LL_PANELPRIMMEDIACONTROLS_H
+
+#include "llpanel.h"
+#include "llviewermedia.h"
+
+class LLCoordWindow;
+class LLViewerMediaImpl;
+
+class LLPanelPrimMediaControls : public LLPanel
+{
+public:
+ LLPanelPrimMediaControls();
+ virtual ~LLPanelPrimMediaControls();
+ /*virtual*/ BOOL postBuild();
+ virtual void draw();
+ virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+
+ virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual BOOL handleKeyHere(KEY key, MASK mask);
+
+ void updateShape();
+ bool isMouseOver();
+ void nextZoomLevel();
+ void resetZoomLevel();
+ void close();
+
+ LLHandle<LLPanelPrimMediaControls> getHandle() const { return mPanelHandle; }
+ void setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero);
+
+
+ enum EZoomLevel
+ {
+ ZOOM_NONE = 0,
+ ZOOM_FAR,
+ ZOOM_MEDIUM,
+ ZOOM_NEAR
+ };
+ static const EZoomLevel kZoomLevels[];
+ static const int kNumZoomLevels;
+
+ enum EScrollDir
+ {
+ SCROLL_UP = 0,
+ SCROLL_DOWN,
+ SCROLL_LEFT,
+ SCROLL_RIGHT,
+ SCROLL_NONE
+ };
+
+private:
+ void onClickClose();
+ void onClickBack();
+ void onClickForward();
+ void onClickHome();
+ void onClickOpen();
+ void onClickReload();
+ void onClickPlay();
+ void onClickPause();
+ void onClickStop();
+ void onClickZoom();
+ void onCommitURL();
+
+ void updateZoom();
+ void setCurrentURL();
+ void onCommitSlider();
+
+ void onCommitVolumeUp();
+ void onCommitVolumeDown();
+ void onToggleMute();
+
+ static void onScrollUp(void* user_data);
+ static void onScrollUpHeld(void* user_data);
+ static void onScrollLeft(void* user_data);
+ static void onScrollLeftHeld(void* user_data);
+ static void onScrollRight(void* user_data);
+ static void onScrollRightHeld(void* user_data);
+ static void onScrollDown(void* user_data);
+ static void onScrollDownHeld(void* user_data);
+ static void onScrollStop(void* user_data);
+
+ static void onInputURL(LLFocusableElement* caller, void *userdata);
+ static bool hasControlsPermission(LLViewerObject *obj, const LLMediaEntry *media_entry);
+
+ void focusOnTarget();
+
+ LLViewerMediaImpl* getTargetMediaImpl();
+ LLViewerObject* getTargetObject();
+ LLPluginClassMedia* getTargetMediaPlugin();
+ bool mPauseFadeout;
+ bool mUpdateSlider;
+ bool mClearFaceOnFade;
+
+ LLMatrix4 mLastCameraMat;
+ EZoomLevel mCurrentZoom;
+ EScrollDir mScrollState;
+ LLCoordWindow mLastCursorPos;
+ LLFrameTimer mInactivityTimer;
+ LLFrameTimer mFadeTimer;
+ F32 mInactiveTimeout;
+ F32 mControlFadeTime;
+ LLRootHandle<LLPanelPrimMediaControls> mPanelHandle;
+ F32 mAlpha;
+ std::string mCurrentURL;
+ std::string mPreviousURL;
+ F64 mCurrentRate;
+ F64 mMovieDuration;
+ int mUpdatePercent;
+
+ LLUUID mTargetObjectID;
+ S32 mTargetObjectFace;
+ LLUUID mTargetImplID;
+ LLVector3 mTargetObjectNormal;
+};
+
+#endif // LL_PANELPRIMMEDIACONTROLS_H
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 25e773e8b8..e97eb1df2b 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -34,7 +34,7 @@
#include "llparticipantlist.h"
#include "llavatarlist.h"
-#include "llfloateractivespeakers.h"
+#include "llspeakers.h"
//LLParticipantList retrieves add, clear and remove events and updates view accordingly
LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list):
@@ -48,6 +48,18 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av
mSpeakerMgr->addListener(mSpeakerAddListener, "add");
mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");
mSpeakerMgr->addListener(mSpeakerClearListener, "clear");
+
+ //Lets fill avatarList with existing speakers
+ LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs();
+
+ LLSpeakerMgr::speaker_list_t speaker_list;
+ mSpeakerMgr->getSpeakerList(&speaker_list, true);
+ for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++)
+ {
+ group_members.push_back((*it)->mID);
+ }
+ mAvatarList->setDirty();
+ mAvatarList->sortByName();
}
LLParticipantList::~LLParticipantList()
@@ -87,8 +99,12 @@ bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::L
bool LLParticipantList::SpeakerRemoveListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
{
LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs();
- group_members.erase(std::find(group_members.begin(), group_members.end(), event->getValue().asUUID()));
- mAvatarList->setDirty();
+ LLAvatarList::uuid_vector_t::iterator pos = std::find(group_members.begin(), group_members.end(), event->getValue().asUUID());
+ if(pos != group_members.end())
+ {
+ group_members.erase(pos);
+ mAvatarList->setDirty();
+ }
return true;
}
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 1683d113a9..73dcd1dd92 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -191,19 +191,22 @@ void LLScreenChannel::onToastFade(LLToast* toast)
{
std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast));
- bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored();
- if(delete_toast)
- {
- mToastList.erase(it);
- deleteToast(toast);
- }
- else
+ if(it != mToastList.end())
{
- storeToast((*it));
- mToastList.erase(it);
- }
+ bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored();
+ if(delete_toast)
+ {
+ mToastList.erase(it);
+ deleteToast(toast);
+ }
+ else
+ {
+ storeToast((*it));
+ mToastList.erase(it);
+ }
- redrawToasts();
+ redrawToasts();
+ }
}
//--------------------------------------------------------------------------
@@ -247,6 +250,7 @@ void LLScreenChannel::loadStoredToastsToChannel()
for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)
{
+ (*it).toast->setIsHidden(false);
(*it).toast->resetTimer();
mToastList.push_back((*it));
}
@@ -266,6 +270,7 @@ void LLScreenChannel::loadStoredToastByNotificationIDToChannel(LLUUID id)
mOverflowToastHidden = false;
LLToast* toast = (*it).toast;
+ toast->setIsHidden(false);
toast->resetTimer();
mToastList.push_back((*it));
mStoredToastList.erase(it);
@@ -519,6 +524,7 @@ void LLScreenChannel::createStartUpToast(S32 notif_num, F32 timer)
LLRect toast_rect;
LLToast::Params p;
p.lifetime_secs = timer;
+ p.enable_hide_btn = false;
mStartUpToastPanel = new LLToast(p);
if(!mStartUpToastPanel)
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
new file mode 100644
index 0000000000..2341fcfc6d
--- /dev/null
+++ b/indra/newview/llspeakers.cpp
@@ -0,0 +1,639 @@
+/**
+ * @file llspeakers.cpp
+ * @brief Management interface for muting and controlling volume of residents currently speaking
+ *
+ * $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 "llspeakers.h"
+
+#include "llagent.h"
+#include "llappviewer.h"
+#include "llmutelist.h"
+#include "llsdutil.h"
+#include "lluicolortable.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatar.h"
+#include "llworld.h"
+
+const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers
+const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
+const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
+
+LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :
+ mStatus(LLSpeaker::STATUS_TEXT_ONLY),
+ mLastSpokeTime(0.f),
+ mSpeechVolume(0.f),
+ mHasSpoken(FALSE),
+ mHasLeftCurrentCall(FALSE),
+ mDotColor(LLColor4::white),
+ mID(id),
+ mTyping(FALSE),
+ mSortIndex(0),
+ mType(type),
+ mIsModerator(FALSE),
+ mModeratorMutedVoice(FALSE),
+ mModeratorMutedText(FALSE)
+{
+ if (name.empty() && type == SPEAKER_AGENT)
+ {
+ lookupName();
+ }
+ else
+ {
+ mDisplayName = name;
+ }
+
+ gVoiceClient->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id));
+
+ mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
+}
+
+
+void LLSpeaker::lookupName()
+{
+ gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4));
+}
+
+void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
+{
+ mDisplayName = first + " " + last;
+}
+
+LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source)
+: LLEvent(source, "Speaker text moderation event")
+{
+}
+
+LLSD LLSpeakerTextModerationEvent::getValue()
+{
+ return std::string("text");
+}
+
+
+LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source)
+: LLEvent(source, "Speaker voice moderation event")
+{
+}
+
+LLSD LLSpeakerVoiceModerationEvent::getValue()
+{
+ return std::string("voice");
+}
+
+LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id)
+: LLEvent(source, "Speaker added/removed from speaker mgr"),
+ mSpeakerID(speaker_id)
+{
+}
+
+LLSD LLSpeakerListChangeEvent::getValue()
+{
+ return mSpeakerID;
+}
+
+// helper sort class
+struct LLSortRecentSpeakers
+{
+ bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
+};
+
+bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
+{
+ // Sort first on status
+ if (lhs->mStatus != rhs->mStatus)
+ {
+ return (lhs->mStatus < rhs->mStatus);
+ }
+
+ // and then on last speaking time
+ if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
+ {
+ return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
+ }
+
+ // and finally (only if those are both equal), on name.
+ return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
+}
+
+
+//
+// LLSpeakerMgr
+//
+
+LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
+ mVoiceChannel(channelp)
+{
+}
+
+LLSpeakerMgr::~LLSpeakerMgr()
+{
+}
+
+LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
+{
+ if (id.isNull()) return NULL;
+
+ LLPointer<LLSpeaker> speakerp;
+ if (mSpeakers.find(id) == mSpeakers.end())
+ {
+ speakerp = new LLSpeaker(id, name, type);
+ speakerp->mStatus = status;
+ mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
+ mSpeakersSorted.push_back(speakerp);
+ fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
+ }
+ else
+ {
+ speakerp = findSpeaker(id);
+ if (speakerp.notNull())
+ {
+ // keep highest priority status (lowest value) instead of overriding current value
+ speakerp->mStatus = llmin(speakerp->mStatus, status);
+ speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
+ // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
+ // we need to override speakers that we think are objects when we find out they are really
+ // residents
+ if (type == LLSpeaker::SPEAKER_AGENT)
+ {
+ speakerp->mType = LLSpeaker::SPEAKER_AGENT;
+ speakerp->lookupName();
+ }
+ }
+ }
+
+ return speakerp;
+}
+
+void LLSpeakerMgr::update(BOOL resort_ok)
+{
+ if (!gVoiceClient)
+ {
+ return;
+ }
+
+ LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor");
+ LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor");
+
+ if(resort_ok) // only allow list changes when user is not interacting with it
+ {
+ updateSpeakerList();
+ }
+
+ // update status of all current speakers
+ BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
+ for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
+ {
+ LLUUID speaker_id = speaker_it->first;
+ LLSpeaker* speakerp = speaker_it->second;
+
+ speaker_map_t::iterator cur_speaker_it = speaker_it++;
+
+ if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id))
+ {
+ speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id);
+ BOOL moderator_muted_voice = gVoiceClient->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)
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_MUTED;
+ }
+ else if (gVoiceClient->getIsSpeaking(speaker_id))
+ {
+ // reset inactivity expiration
+ if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
+ {
+ speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
+ speakerp->mHasSpoken = TRUE;
+ }
+ speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
+ // interpolate between active color and full speaking color based on power of speech output
+ speakerp->mDotColor = speaking_color;
+ if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
+ {
+ speakerp->mDotColor = overdriven_color;
+ }
+ }
+ else
+ {
+ speakerp->mSpeechVolume = 0.f;
+ speakerp->mDotColor = ACTIVE_COLOR;
+
+ if (speakerp->mHasSpoken)
+ {
+ // have spoken once, not currently speaking
+ speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
+ }
+ else
+ {
+ // default state for being in voice channel
+ speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
+ }
+ }
+ }
+ // speaker no longer registered in voice channel, demote to text only
+ else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
+ {
+ if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
+ {
+ // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ }
+ else
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
+ speakerp->mSpeechVolume = 0.f;
+ speakerp->mDotColor = ACTIVE_COLOR;
+ }
+ }
+ }
+
+ if(resort_ok) // only allow list changes when user is not interacting with it
+ {
+ // sort by status then time last spoken
+ std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
+ }
+
+ // for recent speakers who are not currently speaking, show "recent" color dot for most recent
+ // fading to "active" color
+
+ S32 recent_speaker_count = 0;
+ S32 sort_index = 0;
+ speaker_list_t::iterator sorted_speaker_it;
+ for(sorted_speaker_it = mSpeakersSorted.begin();
+ sorted_speaker_it != mSpeakersSorted.end(); )
+ {
+ LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
+
+ // color code recent speakers who are not currently speaking
+ if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
+ {
+ speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
+ recent_speaker_count++;
+ }
+
+ // stuff sort ordinal into speaker so the ui can sort by this value
+ speakerp->mSortIndex = sort_index++;
+
+ // remove speakers that have been gone too long
+ if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired())
+ {
+ fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove");
+
+ mSpeakers.erase(speakerp->mID);
+ sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it);
+ }
+ else
+ {
+ ++sorted_speaker_it;
+ }
+ }
+}
+
+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)
+ {
+ LLVoiceClient::participantMap::iterator participant_it;
+
+ // 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));
+ }
+ }
+ }
+}
+
+LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
+{
+ speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
+ if (found_it == mSpeakers.end())
+ {
+ return NULL;
+ }
+ return found_it->second;
+}
+
+void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
+{
+ speaker_list->clear();
+ for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
+ {
+ LLPointer<LLSpeaker> speakerp = speaker_it->second;
+ // what about text only muted or inactive?
+ if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
+ {
+ speaker_list->push_back(speakerp);
+ }
+ }
+}
+
+const LLUUID LLSpeakerMgr::getSessionID()
+{
+ return mVoiceChannel->getSessionID();
+}
+
+
+void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
+{
+ LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
+ if (speakerp.notNull())
+ {
+ speakerp->mTyping = typing;
+ }
+}
+
+// speaker has chatted via either text or voice
+void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
+{
+ LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
+ if (speakerp.notNull())
+ {
+ speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
+ speakerp->mHasSpoken = TRUE;
+ }
+}
+
+BOOL LLSpeakerMgr::isVoiceActive()
+{
+ // mVoiceChannel = NULL means current voice channel, whatever it is
+ return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
+}
+
+
+//
+// LLIMSpeakerMgr
+//
+LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
+{
+}
+
+void LLIMSpeakerMgr::updateSpeakerList()
+{
+ // don't do normal updates which are pulled from voice channel
+ // rely on user list reported by sim
+
+ // We need to do this to allow PSTN callers into group chats to show in the list.
+ LLSpeakerMgr::updateSpeakerList();
+
+ return;
+}
+
+void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
+{
+ if ( !speakers.isMap() ) return;
+
+ if ( speakers.has("agent_info") && speakers["agent_info"].isMap() )
+ {
+ LLSD::map_const_iterator speaker_it;
+ for(speaker_it = speakers["agent_info"].beginMap();
+ speaker_it != speakers["agent_info"].endMap();
+ ++speaker_it)
+ {
+ LLUUID agent_id(speaker_it->first);
+
+ LLPointer<LLSpeaker> speakerp = setSpeaker(
+ agent_id,
+ LLStringUtil::null,
+ LLSpeaker::STATUS_TEXT_ONLY);
+
+ if ( speaker_it->second.isMap() )
+ {
+ speakerp->mIsModerator = speaker_it->second["is_moderator"];
+ speakerp->mModeratorMutedText =
+ speaker_it->second["mutes"]["text"];
+ }
+ }
+ }
+ else if ( speakers.has("agents" ) && speakers["agents"].isArray() )
+ {
+ //older, more decprecated way. Need here for
+ //using older version of servers
+ LLSD::array_const_iterator speaker_it;
+ for(speaker_it = speakers["agents"].beginArray();
+ speaker_it != speakers["agents"].endArray();
+ ++speaker_it)
+ {
+ const LLUUID agent_id = (*speaker_it).asUUID();
+
+ LLPointer<LLSpeaker> speakerp = setSpeaker(
+ agent_id,
+ LLStringUtil::null,
+ LLSpeaker::STATUS_TEXT_ONLY);
+ }
+ }
+}
+
+void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
+{
+ if ( !update.isMap() ) return;
+
+ if ( update.has("agent_updates") && update["agent_updates"].isMap() )
+ {
+ LLSD::map_const_iterator update_it;
+ for(
+ update_it = update["agent_updates"].beginMap();
+ update_it != update["agent_updates"].endMap();
+ ++update_it)
+ {
+ LLUUID agent_id(update_it->first);
+ LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
+
+ LLSD agent_data = update_it->second;
+
+ if (agent_data.isMap() && agent_data.has("transition"))
+ {
+ if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ speakerp->mDotColor = INACTIVE_COLOR;
+ speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
+ }
+ else if (agent_data["transition"].asString() == "ENTER")
+ {
+ // add or update speaker
+ speakerp = setSpeaker(agent_id);
+ }
+ else
+ {
+ llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
+ }
+ }
+
+ if (speakerp.isNull()) continue;
+
+ // should have a valid speaker from this point on
+ if (agent_data.isMap() && agent_data.has("info"))
+ {
+ LLSD agent_info = agent_data["info"];
+
+ if (agent_info.has("is_moderator"))
+ {
+ speakerp->mIsModerator = agent_info["is_moderator"];
+ }
+
+ if (agent_info.has("mutes"))
+ {
+ speakerp->mModeratorMutedText = agent_info["mutes"]["text"];
+ }
+ }
+ }
+ }
+ else if ( update.has("updates") && update["updates"].isMap() )
+ {
+ LLSD::map_const_iterator update_it;
+ for (
+ update_it = update["updates"].beginMap();
+ update_it != update["updates"].endMap();
+ ++update_it)
+ {
+ LLUUID agent_id(update_it->first);
+ LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
+
+ std::string agent_transition = update_it->second.asString();
+ if (agent_transition == "LEAVE" && speakerp.notNull())
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ speakerp->mDotColor = INACTIVE_COLOR;
+ speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
+ }
+ else if ( agent_transition == "ENTER")
+ {
+ // add or update speaker
+ speakerp = setSpeaker(agent_id);
+ }
+ else
+ {
+ llwarns << "bad membership list update "
+ << agent_transition << llendl;
+ }
+ }
+ }
+}
+
+
+//
+// LLActiveSpeakerMgr
+//
+
+LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
+{
+}
+
+void LLActiveSpeakerMgr::updateSpeakerList()
+{
+ // point to whatever the current voice channel is
+ mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
+
+ // always populate from active voice channel
+ if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel)
+ {
+ fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
+ mSpeakers.clear();
+ mSpeakersSorted.clear();
+ mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
+ }
+ LLSpeakerMgr::updateSpeakerList();
+
+ // clean up text only speakers
+ 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;
+ if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
+ {
+ // automatically flag text only speakers for removal
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ }
+ }
+
+}
+
+
+
+//
+// LLLocalSpeakerMgr
+//
+
+LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
+{
+}
+
+LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
+{
+}
+
+void LLLocalSpeakerMgr::updateSpeakerList()
+{
+ // pull speakers from voice channel
+ LLSpeakerMgr::updateSpeakerList();
+
+ if (gDisconnected)//the world is cleared.
+ {
+ return ;
+ }
+
+ // pick up non-voice speakers in chat range
+ std::vector<LLUUID> avatar_ids;
+ std::vector<LLVector3d> positions;
+ LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS);
+ for(U32 i=0; i<avatar_ids.size(); i++)
+ {
+ setSpeaker(avatar_ids[i]);
+ }
+
+ // check if text only speakers have moved out of chat range
+ 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;
+ if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
+ {
+ LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
+ if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ speakerp->mDotColor = INACTIVE_COLOR;
+ speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
+ }
+ }
+ }
+}
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
new file mode 100644
index 0000000000..e0f22bff4f
--- /dev/null
+++ b/indra/newview/llspeakers.h
@@ -0,0 +1,172 @@
+/**
+ * @file llspeakers.h
+ * @brief Management interface for muting and controlling volume of residents currently speaking
+ *
+ * $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$
+ */
+
+#ifndef LL_LLSPEAKERS_H
+#define LL_LLSPEAKERS_H
+
+#include "llevent.h"
+#include "llspeakers.h"
+#include "llvoicechannel.h"
+
+class LLSpeakerMgr;
+
+// data for a given participant in a voice channel
+class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable
+{
+public:
+ typedef enum e_speaker_type
+ {
+ SPEAKER_AGENT,
+ SPEAKER_OBJECT,
+ SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group)
+ } ESpeakerType;
+
+ typedef enum e_speaker_status
+ {
+ STATUS_SPEAKING,
+ STATUS_HAS_SPOKEN,
+ STATUS_VOICE_ACTIVE,
+ STATUS_TEXT_ONLY,
+ STATUS_NOT_IN_CHANNEL,
+ STATUS_MUTED
+ } ESpeakerStatus;
+
+
+ LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT);
+ ~LLSpeaker() {};
+ void lookupName();
+
+ void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
+
+ ESpeakerStatus mStatus; // current activity status in speech group
+ F32 mLastSpokeTime; // timestamp when this speaker last spoke
+ F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?)
+ std::string mDisplayName; // cache user name for this speaker
+ LLFrameTimer mActivityTimer; // time out speakers when they are not part of current voice channel
+ BOOL mHasSpoken; // has this speaker said anything this session?
+ BOOL mHasLeftCurrentCall; // has this speaker left the current voice call?
+ LLColor4 mDotColor;
+ LLUUID mID;
+ BOOL mTyping;
+ S32 mSortIndex;
+ ESpeakerType mType;
+ BOOL mIsModerator;
+ BOOL mModeratorMutedVoice;
+ BOOL mModeratorMutedText;
+};
+
+class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent
+{
+public:
+ LLSpeakerTextModerationEvent(LLSpeaker* source);
+ /*virtual*/ LLSD getValue();
+};
+
+class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent
+{
+public:
+ LLSpeakerVoiceModerationEvent(LLSpeaker* source);
+ /*virtual*/ LLSD getValue();
+};
+
+class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent
+{
+public:
+ LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id);
+ /*virtual*/ LLSD getValue();
+
+private:
+ const LLUUID& mSpeakerID;
+};
+
+class LLSpeakerMgr : public LLOldEvents::LLObservable
+{
+public:
+ LLSpeakerMgr(LLVoiceChannel* channelp);
+ virtual ~LLSpeakerMgr();
+
+ LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id);
+ void update(BOOL resort_ok);
+ void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing);
+ void speakerChatted(const LLUUID& speaker_id);
+ LLPointer<LLSpeaker> setSpeaker(const LLUUID& id,
+ const std::string& name = LLStringUtil::null,
+ LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,
+ LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT);
+
+ BOOL isVoiceActive();
+
+ typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t;
+ void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text);
+ LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
+ const LLUUID getSessionID();
+
+protected:
+ virtual void updateSpeakerList();
+
+ typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
+ speaker_map_t mSpeakers;
+
+ speaker_list_t mSpeakersSorted;
+ LLFrameTimer mSpeechTimer;
+ LLVoiceChannel* mVoiceChannel;
+};
+
+class LLIMSpeakerMgr : public LLSpeakerMgr
+{
+public:
+ LLIMSpeakerMgr(LLVoiceChannel* channel);
+
+ void updateSpeakers(const LLSD& update);
+ void setSpeakers(const LLSD& speakers);
+protected:
+ virtual void updateSpeakerList();
+};
+
+class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
+{
+public:
+ LLActiveSpeakerMgr();
+protected:
+ virtual void updateSpeakerList();
+};
+
+class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr>
+{
+public:
+ LLLocalSpeakerMgr();
+ ~LLLocalSpeakerMgr ();
+protected:
+ virtual void updateSpeakerList();
+};
+
+#endif // LL_LLSPEAKERS_H
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 86290e6695..93a931dc78 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -113,6 +113,12 @@ void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type)
}
//---------------------------------------------------------------------------------
+void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask)
+{
+ onChicletClick();
+}
+
+//---------------------------------------------------------------------------------
void LLSysWellWindow::onChicletClick()
{
// 1 - remove StartUp toast and channel if present
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index fa6a1abea4..cbc5f7358f 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -76,6 +76,7 @@ public:
void onItemClose(LLSysWellItem* item);
void onStoreToast(LLPanel* info_panel, LLUUID id);
void onChicletClick();
+ void onStartUpToastClick(S32 x, S32 y, MASK mask);
// size constants for the window and for its elements
static const S32 MAX_WINDOW_HEIGHT = 200;
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 17547cae39..5d9046ac90 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -804,8 +804,9 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
gGL.setColorMask(false, true);
gGL.setSceneBlendType(LLRender::BT_REPLACE);
+
// (Optionally) replace alpha with a single component image from a tga file.
- if (!info->mStaticAlphaFileName.empty() && mMaskLayerList.empty())
+ if (!info->mStaticAlphaFileName.empty())
{
LLGLSNoAlphaTest gls_no_alpha_test;
gGL.flush();
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index eba43d76a6..24824a095c 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -63,6 +63,7 @@ LLToast::LLToast(const LLToast::Params& p)
mHideBtnEnabled(p.enable_hide_btn),
mHideBtn(NULL),
mNotification(p.notification),
+ mIsHidden(false),
mHideBtnPressed(false)
{
LLUICtrlFactory::getInstance()->buildFloater(this, "panel_toast.xml", NULL);
@@ -143,7 +144,8 @@ void LLToast::hide()
{
setVisible(FALSE);
mTimer.stop();
- mOnFadeSignal(this);
+ mIsHidden = true;
+ mOnFadeSignal(this);
}
//--------------------------------------------------------------------------
@@ -159,9 +161,7 @@ void LLToast::tick()
{
if(mCanFade)
{
- setVisible(FALSE);
- mTimer.stop();
- mOnFadeSignal(this);
+ hide();
}
}
@@ -206,6 +206,16 @@ void LLToast::draw()
//--------------------------------------------------------------------------
void LLToast::setVisible(BOOL show)
{
+ if(mIsHidden)
+ {
+ // this toast is invisible after fade until its ScreenChannel will allow it
+ //
+ // (EXT-1849) according to this bug a toast can be resurrected from
+ // invisible state if it faded during a teleportation
+ // then it fades a second time and causes a crash
+ return;
+ }
+
if(show)
{
setBackgroundOpaque(TRUE);
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index 1826c13ebc..0698c94880 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -125,6 +125,8 @@ public:
void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; }
//
bool getCanBeStored() { return mCanBeStored; }
+ // set whether this toast considered as hidden or not
+ void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; }
// Registers signals/callbacks for events
@@ -164,6 +166,7 @@ private:
bool mCanBeStored;
bool mHideBtnEnabled;
bool mHideBtnPressed;
+ bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849)
};
}
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 57a4117d5d..366e5602bd 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -42,7 +42,6 @@
#include "llconsole.h"
#include "llinventorymodel.h"
#include "llnotify.h"
-#include "llimview.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 02fda191be..8bd74dcb04 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -156,10 +156,10 @@ public:
{
if(!mInitialized && ! mime_type.empty())
{
- if (mMediaImpl->initializeMedia(mime_type))
+ if(mMediaImpl->initializeMedia(mime_type))
{
mInitialized = true;
- mMediaImpl->play();
+ mMediaImpl->loadURI();
}
}
}
@@ -267,10 +267,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
{
needs_navigate = (media_entry->getCurrentURL() != previous_url);
}
- else if(!media_entry->getHomeURL().empty())
- {
- needs_navigate = (media_entry->getHomeURL() != previous_url);
- }
}
}
else
@@ -293,8 +289,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s
if(media_impl && needs_navigate)
{
std::string url = media_entry->getCurrentURL();
- if(url.empty())
- url = media_entry->getHomeURL();
media_impl->navigateTo(url, "", true, true);
}
@@ -639,13 +633,14 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mUsedInUI(false),
mHasFocus(false),
mPriority(LLPluginClassMedia::PRIORITY_UNLOADED),
- mDoNavigateOnLoad(false),
- mDoNavigateOnLoadRediscoverType(false),
- mDoNavigateOnLoadServerRequest(false),
+ mNavigateRediscoverType(false),
+ mNavigateServerRequest(false),
mMediaSourceFailed(false),
mRequestedVolume(1.0f),
mIsMuted(false),
mNeedsMuteCheck(false),
+ mPreviousMediaState(MEDIA_NONE),
+ mPreviousMediaTime(0.0f),
mIsUpdated(false)
{
@@ -716,7 +711,6 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
mMimeType = mime_type;
}
- // play();
return (mMediaSource != NULL);
}
@@ -729,16 +723,13 @@ void LLViewerMediaImpl::createMediaSource()
return;
}
- if(mDoNavigateOnLoad)
+ if(! mMediaURL.empty())
{
- if(! mMediaURL.empty())
- {
- navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest);
- }
- else if(! mMimeType.empty())
- {
- initializeMedia(mMimeType);
- }
+ navigateInternal();
+ }
+ else if(! mMimeType.empty())
+ {
+ initializeMedia(mMimeType);
}
}
@@ -869,6 +860,46 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
return false;
}
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::loadURI()
+{
+ if(mMediaSource)
+ {
+ mMediaSource->loadURI( mMediaURL );
+
+ if(mPreviousMediaState == MEDIA_PLAYING)
+ {
+ // This media was playing before this instance was unloaded.
+
+ if(mPreviousMediaTime != 0.0f)
+ {
+ // Seek back to where we left off, if possible.
+ seek(mPreviousMediaTime);
+ }
+
+ start();
+ }
+ else if(mPreviousMediaState == MEDIA_PAUSED)
+ {
+ // This media was paused before this instance was unloaded.
+
+ if(mPreviousMediaTime != 0.0f)
+ {
+ // Seek back to where we left off, if possible.
+ seek(mPreviousMediaTime);
+ }
+
+ pause();
+ }
+ else
+ {
+ // No relevant previous media play state -- if we're loading the URL, we want to start playing.
+ start();
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::setSize(int width, int height)
{
mMediaWidth = width;
@@ -882,24 +913,21 @@ void LLViewerMediaImpl::setSize(int width, int height)
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::play()
{
- // first stop any previously playing media
- // stop();
-
- // mMediaSource->addObserver( this );
+ // If the media source isn't there, try to initialize it and load an URL.
if(mMediaSource == NULL)
{
- if(!initializePlugin(mMimeType))
+ if(!initializeMedia(mMimeType))
{
// This may be the case where the plugin's priority is PRIORITY_UNLOADED
return;
}
+
+ // Only do this if the media source was just loaded.
+ loadURI();
}
- mMediaSource->loadURI( mMediaURL );
- if(/*mMediaSource->pluginSupportsMediaTime()*/ true)
- {
- start();
- }
+ // always start the media
+ start();
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1165,27 +1193,21 @@ void LLViewerMediaImpl::navigateHome()
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request)
{
- if(server_request)
- {
- setNavState(MEDIANAVSTATE_SERVER_SENT);
- }
- else
+ if(mMediaURL != url)
{
- setNavState(MEDIANAVSTATE_NONE);
+ // Don't carry media play state across distinct URLs.
+ resetPreviousMediaState();
}
// Always set the current URL and MIME type.
mMediaURL = url;
mMimeType = mime_type;
- // If the current URL is not null, make the instance do a navigate on load.
- mDoNavigateOnLoad = !mMediaURL.empty();
-
// if mime type discovery was requested, we'll need to do it when the media loads
- mDoNavigateOnLoadRediscoverType = rediscover_type;
+ mNavigateRediscoverType = rediscover_type;
// and if this was a server request, the navigate on load will also need to be one.
- mDoNavigateOnLoadServerRequest = server_request;
+ mNavigateServerRequest = server_request;
// An explicit navigate resets the "failed" flag.
mMediaSourceFailed = false;
@@ -1193,7 +1215,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
{
// Helpful to have media urls in log file. Shouldn't be spammy.
- llinfos << "UNLOADED media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;
+ llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;
// This impl should not be loaded at this time.
LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
@@ -1201,10 +1223,24 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
return;
}
+ navigateInternal();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::navigateInternal()
+{
// Helpful to have media urls in log file. Shouldn't be spammy.
- llinfos << "media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;
-
-
+ llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl;
+
+ if(mNavigateServerRequest)
+ {
+ setNavState(MEDIANAVSTATE_SERVER_SENT);
+ }
+ else
+ {
+ setNavState(MEDIANAVSTATE_NONE);
+ }
+
// If the caller has specified a non-empty MIME type, look that up in our MIME types list.
// If we have a plugin for that MIME type, use that instead of attempting auto-discovery.
// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
@@ -1216,11 +1252,11 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
if(!plugin_basename.empty())
{
// We have a plugin for this mime type
- rediscover_type = false;
+ mNavigateRediscoverType = false;
}
}
- if(rediscover_type)
+ if(mNavigateRediscoverType)
{
LLURI uri(mMediaURL);
@@ -1236,7 +1272,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
// We use "data" internally for a text/html url for loading the login screen
if(initializeMedia("text/html"))
{
- mMediaSource->loadURI( mMediaURL );
+ loadURI();
}
}
else
@@ -1244,24 +1280,18 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
// This catches 'rtsp://' urls
if(initializeMedia(scheme))
{
- mMediaSource->loadURI( mMediaURL );
+ loadURI();
}
}
}
- else if (mMediaSource)
+ else if(initializeMedia(mMimeType))
{
- mMediaSource->loadURI( mMediaURL );
- }
- else if(initializeMedia(mime_type) && mMediaSource)
- {
- mMediaSource->loadURI( mMediaURL );
+ loadURI();
}
else
{
- LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL;
- return;
+ LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL;
}
-
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1390,6 +1420,7 @@ void LLViewerMediaImpl::update()
if(mMediaSource->isPluginExited())
{
+ resetPreviousMediaState();
destroyMediaSource();
return;
}
@@ -1586,6 +1617,14 @@ bool LLViewerMediaImpl::hasMedia()
}
//////////////////////////////////////////////////////////////////////////////////////////
+//
+void LLViewerMediaImpl::resetPreviousMediaState()
+{
+ mPreviousMediaState = MEDIA_NONE;
+ mPreviousMediaTime = 0.0f;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event)
{
switch(event)
@@ -1595,6 +1634,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
// The plugin failed to load properly. Make sure the timer doesn't retry.
// TODO: maybe mark this plugin as not loadable somehow?
mMediaSourceFailed = true;
+
+ // Reset the last known state of the media to defaults.
+ resetPreviousMediaState();
// TODO: may want a different message for this case?
LLSD args;
@@ -1608,6 +1650,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
// The plugin crashed.
mMediaSourceFailed = true;
+ // Reset the last known state of the media to defaults.
+ resetPreviousMediaState();
+
LLSD args;
args["PLUGIN"] = LLMIMETypes::implType(mMimeType);
// SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert!
@@ -1833,11 +1878,11 @@ void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)
{
if(getVisible())
{
- mPriority = LLPluginClassMedia::PRIORITY_NORMAL;
+ setPriority(LLPluginClassMedia::PRIORITY_NORMAL);
}
else
{
- mPriority = LLPluginClassMedia::PRIORITY_HIDDEN;
+ setPriority(LLPluginClassMedia::PRIORITY_HIDDEN);
}
createMediaSource();
@@ -1858,6 +1903,15 @@ F64 LLViewerMediaImpl::getCPUUsage() const
void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
{
+ if(mPriority != priority)
+ {
+ LL_INFOS("PluginPriority")
+ << "changing priority of media id " << mTextureId
+ << " from " << LLPluginClassMedia::priorityToString(mPriority)
+ << " to " << LLPluginClassMedia::priorityToString(priority)
+ << LL_ENDL;
+ }
+
mPriority = priority;
if(priority == LLPluginClassMedia::PRIORITY_UNLOADED)
@@ -1865,6 +1919,11 @@ void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
if(mMediaSource)
{
// Need to unload the media source
+
+ // First, save off previous media state
+ mPreviousMediaState = mMediaSource->getStatus();
+ mPreviousMediaTime = mMediaSource->getCurrentTime();
+
destroyMediaSource();
}
}
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index b15314e954..4f0d39dd80 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -123,6 +123,7 @@ public:
void setMediaType(const std::string& media_type);
bool initializeMedia(const std::string& mime_type);
bool initializePlugin(const std::string& media_type);
+ void loadURI();
LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }
void setSize(int width, int height);
@@ -151,6 +152,7 @@ public:
void navigateReload();
void navigateHome();
void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false);
+ void navigateInternal();
void navigateStop();
bool handleKeyHere(KEY key, MASK mask);
bool handleUnicodeCharHere(llwchar uni_char);
@@ -174,6 +176,7 @@ public:
bool isMediaPaused();
bool hasMedia();
bool isMediaFailed() { return mMediaSourceFailed; };
+ void resetPreviousMediaState();
ECursorType getLastSetCursor() { return mLastSetCursor; };
@@ -287,14 +290,14 @@ public:
bool mUsedInUI;
bool mHasFocus;
LLPluginClassMedia::EPriority mPriority;
- bool mDoNavigateOnLoad;
- bool mDoNavigateOnLoadRediscoverType;
- bool mDoNavigateOnLoadServerRequest;
+ bool mNavigateRediscoverType;
+ bool mNavigateServerRequest;
bool mMediaSourceFailed;
F32 mRequestedVolume;
bool mIsMuted;
bool mNeedsMuteCheck;
-
+ int mPreviousMediaState;
+ F64 mPreviousMediaTime;
private:
BOOL mIsUpdated ;
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index b47e0b8406..5d0b77d4fb 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -35,7 +35,7 @@
//LLViewerMediaFocus
#include "llviewerobjectlist.h"
-#include "llpanelmediahud.h"
+#include "llpanelprimmediacontrols.h"
#include "llpluginclassmedia.h"
#include "llagent.h"
#include "lltoolpie.h"
@@ -106,19 +106,19 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac
// We must do this before processing the media HUD zoom, or it may zoom to the wrong face.
update();
- if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom())
+ if(mMediaControls.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom())
{
- mMediaHUD.get()->resetZoomLevel();
- mMediaHUD.get()->nextZoomLevel();
+ mMediaControls.get()->resetZoomLevel();
+ mMediaControls.get()->nextZoomLevel();
}
}
else
{
if(mFocusedImplID != LLUUID::null)
{
- if(mMediaHUD.get())
+ if(mMediaControls.get())
{
- mMediaHUD.get()->resetZoomLevel();
+ mMediaControls.get()->resetZoomLevel();
}
gFocusMgr.setKeyboardFocus(NULL);
@@ -327,20 +327,20 @@ void LLViewerMediaFocus::update()
// We have an object and impl to point at.
// Make sure the media HUD object exists.
- if(! mMediaHUD.get())
+ if(! mMediaControls.get())
{
- LLPanelMediaHUD* media_hud = new LLPanelMediaHUD();
- mMediaHUD = media_hud->getHandle();
- gHUDView->addChild(media_hud);
+ LLPanelPrimMediaControls* media_controls = new LLPanelPrimMediaControls();
+ mMediaControls = media_controls->getHandle();
+ gHUDView->addChild(media_controls);
}
- mMediaHUD.get()->setMediaFace(viewer_object, face, media_impl, normal);
+ mMediaControls.get()->setMediaFace(viewer_object, face, media_impl, normal);
}
else
{
// The media HUD is no longer needed.
- if(mMediaHUD.get())
+ if(mMediaControls.get())
{
- mMediaHUD.get()->setMediaFace(NULL, 0, NULL);
+ mMediaControls.get()->setMediaFace(NULL, 0, NULL);
}
}
}
diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h
index c77533ba5a..c1179de39d 100644
--- a/indra/newview/llviewermediafocus.h
+++ b/indra/newview/llviewermediafocus.h
@@ -40,7 +40,7 @@
#include "llselectmgr.h"
class LLViewerMediaImpl;
-class LLPanelMediaHUD;
+class LLPanelPrimMediaControls;
class LLViewerMediaFocus :
public LLFocusableElement,
@@ -88,7 +88,7 @@ protected:
private:
- LLHandle<LLPanelMediaHUD> mMediaHUD;
+ LLHandle<LLPanelPrimMediaControls> mMediaControls;
LLUUID mFocusedObjectID;
S32 mFocusedObjectFace;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 058f44ef57..864cf9d57b 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -3483,7 +3483,6 @@ void set_god_level(U8 god_level)
{
U8 old_god_level = gAgent.getGodLevel();
gAgent.setGodLevel( god_level );
- gIMMgr->refresh();
LLViewerParcelMgr::getInstance()->notifyObservers();
// God mode changes sim visibility
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 791ec07349..320f0f83ff 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -72,7 +72,6 @@
#include "llviewercontrol.h"
#include "lldrawpool.h"
#include "llfirstuse.h"
-#include "llfloateractivespeakers.h"
#include "llfloateranimpreview.h"
#include "llfloaterbuycurrency.h"
#include "llfloaterbuyland.h"
@@ -5680,7 +5679,7 @@ void onCovenantLoadComplete(LLVFS *vfs,
LLPanelLandCovenant::updateCovenantText(covenant_text);
LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid);
- LLPanelPlaceInfo* panel = dynamic_cast<LLPanelPlaceInfo*>(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD()));
+ LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info");
if (panel)
{
panel->updateCovenantText(covenant_text);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index f141d33729..b0b69fbae6 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -142,7 +142,6 @@
#include "llstatview.h"
#include "llsurface.h"
#include "llsurfacepatch.h"
-#include "llimview.h"
#include "lltexlayer.h"
#include "lltextbox.h"
#include "lltexturecache.h"
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index a402aff8ab..f9c95afc31 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -6400,6 +6400,11 @@ LLBBox LLVOAvatar::getHUDBBox() const
++attachment_iter)
{
const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object == NULL)
+ {
+ llwarns << "HUD attached object is NULL!" << llendl;
+ continue;
+ }
// initialize bounding box to contain identity orientation and center point for attached object
bbox.addPointLocal(attached_object->getPosition());
// add rotated bounding box for attached object
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
new file mode 100644
index 0000000000..96fcf61e62
--- /dev/null
+++ b/indra/newview/llvoicechannel.cpp
@@ -0,0 +1,872 @@
+/**
+ * @file llvoicechannel.cpp
+ * @brief Voice Channel related classes
+ *
+ * $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 "llagent.h"
+#include "llfloaterreg.h"
+#include "llimview.h"
+#include "llnotifications.h"
+#include "llpanel.h"
+#include "llrecentpeople.h"
+#include "llviewercontrol.h"
+#include "llvoicechannel.h"
+
+
+LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
+LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
+LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
+LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
+
+BOOL LLVoiceChannel::sSuspended = FALSE;
+
+//
+// Constants
+//
+const U32 DEFAULT_RETRIES_COUNT = 3;
+
+
+class LLVoiceCallCapResponder : public LLHTTPClient::Responder
+{
+public:
+ LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
+
+ virtual void error(U32 status, const std::string& reason); // called with bad status codes
+ virtual void result(const LLSD& content);
+
+private:
+ LLUUID mSessionID;
+};
+
+
+void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
+{
+ llwarns << "LLVoiceCallCapResponder::error("
+ << status << ": " << reason << ")"
+ << llendl;
+ LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
+ if ( channelp )
+ {
+ if ( 403 == status )
+ {
+ //403 == no ability
+ LLNotifications::instance().add(
+ "VoiceNotAllowed",
+ channelp->getNotifyArgs());
+ }
+ else
+ {
+ LLNotifications::instance().add(
+ "VoiceCallGenericError",
+ channelp->getNotifyArgs());
+ }
+ channelp->deactivate();
+ }
+}
+
+void LLVoiceCallCapResponder::result(const LLSD& content)
+{
+ LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
+ if (channelp)
+ {
+ //*TODO: DEBUG SPAM
+ LLSD::map_const_iterator iter;
+ for(iter = content.beginMap(); iter != content.endMap(); ++iter)
+ {
+ llinfos << "LLVoiceCallCapResponder::result got "
+ << iter->first << llendl;
+ }
+
+ channelp->setChannelInfo(
+ content["voice_credentials"]["channel_uri"].asString(),
+ content["voice_credentials"]["channel_credentials"].asString());
+ }
+}
+
+//
+// LLVoiceChannel
+//
+LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
+ mSessionID(session_id),
+ mState(STATE_NO_CHANNEL_INFO),
+ mSessionName(session_name),
+ mIgnoreNextSessionLeave(FALSE)
+{
+ mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
+
+ if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
+ {
+ // 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;
+ }
+
+ LLVoiceClient::getInstance()->addObserver(this);
+}
+
+LLVoiceChannel::~LLVoiceChannel()
+{
+ // Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
+ if(gVoiceClient)
+ {
+ gVoiceClient->removeObserver(this);
+ }
+
+ sVoiceChannelMap.erase(mSessionID);
+ sVoiceChannelURIMap.erase(mURI);
+}
+
+void LLVoiceChannel::setChannelInfo(
+ const std::string& uri,
+ const std::string& credentials)
+{
+ setURI(uri);
+
+ mCredentials = credentials;
+
+ if (mState == STATE_NO_CHANNEL_INFO)
+ {
+ if (mURI.empty())
+ {
+ LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
+ llwarns << "Received empty URI for channel " << mSessionName << llendl;
+ deactivate();
+ }
+ else if (mCredentials.empty())
+ {
+ LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
+ llwarns << "Received empty credentials for channel " << mSessionName << llendl;
+ deactivate();
+ }
+ else
+ {
+ setState(STATE_READY);
+
+ // if we are supposed to be active, reconnect
+ // this will happen on initial connect, as we request credentials on first use
+ if (sCurrentVoiceChannel == this)
+ {
+ // just in case we got new channel info while active
+ // should move over to new channel
+ activate();
+ }
+ }
+ }
+}
+
+void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
+{
+ if (channelURI != mURI)
+ {
+ return;
+ }
+
+ if (type < BEGIN_ERROR_STATUS)
+ {
+ handleStatusChange(type);
+ }
+ else
+ {
+ handleError(type);
+ }
+}
+
+void LLVoiceChannel::handleStatusChange(EStatusType type)
+{
+ // status updates
+ switch(type)
+ {
+ case STATUS_LOGIN_RETRY:
+ //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
+ LLNotifications::instance().add("VoiceLoginRetry");
+ break;
+ case STATUS_LOGGED_IN:
+ //if (!mLoginNotificationHandle.isDead())
+ //{
+ // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
+ // if (notifyp)
+ // {
+ // notifyp->close();
+ // }
+ // mLoginNotificationHandle.markDead();
+ //}
+ break;
+ case STATUS_LEFT_CHANNEL:
+ if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
+ {
+ // if forceably removed from channel
+ // update the UI and revert to default channel
+ LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs);
+ deactivate();
+ }
+ mIgnoreNextSessionLeave = FALSE;
+ break;
+ case STATUS_JOINING:
+ if (callStarted())
+ {
+ setState(STATE_RINGING);
+ }
+ break;
+ case STATUS_JOINED:
+ if (callStarted())
+ {
+ setState(STATE_CONNECTED);
+ }
+ default:
+ break;
+ }
+}
+
+// default behavior is to just deactivate channel
+// derived classes provide specific error messages
+void LLVoiceChannel::handleError(EStatusType type)
+{
+ deactivate();
+ setState(STATE_ERROR);
+}
+
+BOOL LLVoiceChannel::isActive()
+{
+ // only considered active when currently bound channel matches what our channel
+ return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
+}
+
+BOOL LLVoiceChannel::callStarted()
+{
+ return mState >= STATE_CALL_STARTED;
+}
+
+void LLVoiceChannel::deactivate()
+{
+ if (mState >= STATE_RINGING)
+ {
+ // ignore session leave event
+ mIgnoreNextSessionLeave = TRUE;
+ }
+
+ if (callStarted())
+ {
+ setState(STATE_HUNG_UP);
+ // mute the microphone if required when returning to the proximal channel
+ if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this)
+ {
+ gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
+ }
+ }
+
+ if (sCurrentVoiceChannel == this)
+ {
+ // default channel is proximal channel
+ sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
+ sCurrentVoiceChannel->activate();
+ }
+}
+
+void LLVoiceChannel::activate()
+{
+ if (callStarted())
+ {
+ return;
+ }
+
+ // deactivate old channel and mark ourselves as the active one
+ if (sCurrentVoiceChannel != this)
+ {
+ // mark as current before deactivating the old channel to prevent
+ // activating the proximal channel between IM calls
+ LLVoiceChannel* old_channel = sCurrentVoiceChannel;
+ sCurrentVoiceChannel = this;
+ if (old_channel)
+ {
+ old_channel->deactivate();
+ }
+ }
+
+ if (mState == STATE_NO_CHANNEL_INFO)
+ {
+ // responsible for setting status to active
+ getChannelInfo();
+ }
+ else
+ {
+ setState(STATE_CALL_STARTED);
+ }
+}
+
+void LLVoiceChannel::getChannelInfo()
+{
+ // pretend we have everything we need
+ if (sCurrentVoiceChannel == this)
+ {
+ setState(STATE_CALL_STARTED);
+ }
+}
+
+//static
+LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
+{
+ voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
+ if (found_it == sVoiceChannelMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return found_it->second;
+ }
+}
+
+//static
+LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
+{
+ voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
+ if (found_it == sVoiceChannelURIMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return found_it->second;
+ }
+}
+
+void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
+{
+ sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
+ mSessionID = new_session_id;
+ sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
+}
+
+void LLVoiceChannel::setURI(std::string uri)
+{
+ sVoiceChannelURIMap.erase(mURI);
+ mURI = uri;
+ sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
+}
+
+void LLVoiceChannel::setState(EState state)
+{
+ switch(state)
+ {
+ case STATE_RINGING:
+ gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
+ break;
+ case STATE_CONNECTED:
+ gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs);
+ break;
+ case STATE_HUNG_UP:
+ gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
+ break;
+ default:
+ break;
+ }
+
+ mState = state;
+}
+
+void LLVoiceChannel::toggleCallWindowIfNeeded(EState state)
+{
+ if (state == STATE_CONNECTED)
+ {
+ LLFloaterReg::showInstance("voice_call", mSessionID);
+ }
+ // By checking that current state is CONNECTED we make sure that the call window
+ // has been shown, hence there's something to hide. This helps when user presses
+ // the "End call" button right after initiating the call.
+ // *TODO: move this check to LLFloaterCall?
+ else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED)
+ {
+ LLFloaterReg::hideInstance("voice_call", mSessionID);
+ }
+}
+
+//static
+void LLVoiceChannel::initClass()
+{
+ sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
+}
+
+
+//static
+void LLVoiceChannel::suspend()
+{
+ if (!sSuspended)
+ {
+ sSuspendedVoiceChannel = sCurrentVoiceChannel;
+ sSuspended = TRUE;
+ }
+}
+
+//static
+void LLVoiceChannel::resume()
+{
+ if (sSuspended)
+ {
+ if (gVoiceClient->voiceEnabled())
+ {
+ if (sSuspendedVoiceChannel)
+ {
+ sSuspendedVoiceChannel->activate();
+ }
+ else
+ {
+ LLVoiceChannelProximal::getInstance()->activate();
+ }
+ }
+ sSuspended = FALSE;
+ }
+}
+
+
+//
+// LLVoiceChannelGroup
+//
+
+LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
+ LLVoiceChannel(session_id, session_name)
+{
+ mRetries = DEFAULT_RETRIES_COUNT;
+ mIsRetrying = FALSE;
+}
+
+void LLVoiceChannelGroup::deactivate()
+{
+ if (callStarted())
+ {
+ LLVoiceClient::getInstance()->leaveNonSpatialChannel();
+ }
+ LLVoiceChannel::deactivate();
+}
+
+void LLVoiceChannelGroup::activate()
+{
+ if (callStarted()) return;
+
+ LLVoiceChannel::activate();
+
+ if (callStarted())
+ {
+ // we have the channel info, just need to use it now
+ LLVoiceClient::getInstance()->setNonSpatialChannel(
+ mURI,
+ mCredentials);
+
+#if 0 // *TODO
+ if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel
+ {
+ // Add the party to the list of people with which we've recently interacted.
+ for (/*people in the chat*/)
+ LLRecentPeople::instance().add(buddy_id);
+ }
+#endif
+ }
+}
+
+void LLVoiceChannelGroup::getChannelInfo()
+{
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ std::string url = region->getCapability("ChatSessionRequest");
+ LLSD data;
+ data["method"] = "call";
+ data["session-id"] = mSessionID;
+ LLHTTPClient::post(url,
+ data,
+ new LLVoiceCallCapResponder(mSessionID));
+ }
+}
+
+void LLVoiceChannelGroup::setChannelInfo(
+ const std::string& uri,
+ const std::string& credentials)
+{
+ setURI(uri);
+
+ mCredentials = credentials;
+
+ if (mState == STATE_NO_CHANNEL_INFO)
+ {
+ if(!mURI.empty() && !mCredentials.empty())
+ {
+ setState(STATE_READY);
+
+ // if we are supposed to be active, reconnect
+ // this will happen on initial connect, as we request credentials on first use
+ if (sCurrentVoiceChannel == this)
+ {
+ // just in case we got new channel info while active
+ // should move over to new channel
+ activate();
+ }
+ }
+ else
+ {
+ //*TODO: notify user
+ llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
+ deactivate();
+ }
+ }
+ else if ( mIsRetrying )
+ {
+ // we have the channel info, just need to use it now
+ LLVoiceClient::getInstance()->setNonSpatialChannel(
+ mURI,
+ mCredentials);
+ }
+}
+
+void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
+{
+ // status updates
+ switch(type)
+ {
+ case STATUS_JOINED:
+ mRetries = 3;
+ mIsRetrying = FALSE;
+ default:
+ break;
+ }
+
+ LLVoiceChannel::handleStatusChange(type);
+}
+
+void LLVoiceChannelGroup::handleError(EStatusType status)
+{
+ std::string notify;
+ switch(status)
+ {
+ case ERROR_CHANNEL_LOCKED:
+ case ERROR_CHANNEL_FULL:
+ notify = "VoiceChannelFull";
+ break;
+ case ERROR_NOT_AVAILABLE:
+ //clear URI and credentials
+ //set the state to be no info
+ //and activate
+ if ( mRetries > 0 )
+ {
+ mRetries--;
+ mIsRetrying = TRUE;
+ mIgnoreNextSessionLeave = TRUE;
+
+ getChannelInfo();
+ return;
+ }
+ else
+ {
+ notify = "VoiceChannelJoinFailed";
+ mRetries = DEFAULT_RETRIES_COUNT;
+ mIsRetrying = FALSE;
+ }
+
+ break;
+
+ case ERROR_UNKNOWN:
+ default:
+ break;
+ }
+
+ // notification
+ if (!notify.empty())
+ {
+ LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs);
+ // echo to im window
+ gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
+ }
+
+ LLVoiceChannel::handleError(status);
+}
+
+void LLVoiceChannelGroup::setState(EState state)
+{
+ // HACK: Open/close the call window if needed.
+ toggleCallWindowIfNeeded(state);
+
+ switch(state)
+ {
+ case STATE_RINGING:
+ if ( !mIsRetrying )
+ {
+ gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
+ }
+
+ mState = state;
+ break;
+ default:
+ LLVoiceChannel::setState(state);
+ }
+}
+
+//
+// LLVoiceChannelProximal
+//
+LLVoiceChannelProximal::LLVoiceChannelProximal() :
+ LLVoiceChannel(LLUUID::null, LLStringUtil::null)
+{
+ activate();
+}
+
+BOOL LLVoiceChannelProximal::isActive()
+{
+ return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
+}
+
+void LLVoiceChannelProximal::activate()
+{
+ if (callStarted()) return;
+
+ LLVoiceChannel::activate();
+
+ if (callStarted())
+ {
+ // this implicitly puts you back in the spatial channel
+ LLVoiceClient::getInstance()->leaveNonSpatialChannel();
+ }
+}
+
+void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
+{
+ if (!proximal)
+ {
+ return;
+ }
+
+ if (type < BEGIN_ERROR_STATUS)
+ {
+ handleStatusChange(type);
+ }
+ else
+ {
+ handleError(type);
+ }
+}
+
+void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
+{
+ // status updates
+ switch(status)
+ {
+ case STATUS_LEFT_CHANNEL:
+ // do not notify user when leaving proximal channel
+ return;
+ case STATUS_VOICE_DISABLED:
+ gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
+ return;
+ default:
+ break;
+ }
+ LLVoiceChannel::handleStatusChange(status);
+}
+
+
+void LLVoiceChannelProximal::handleError(EStatusType status)
+{
+ std::string notify;
+ switch(status)
+ {
+ case ERROR_CHANNEL_LOCKED:
+ case ERROR_CHANNEL_FULL:
+ notify = "ProximalVoiceChannelFull";
+ break;
+ default:
+ break;
+ }
+
+ // notification
+ if (!notify.empty())
+ {
+ LLNotifications::instance().add(notify, mNotifyArgs);
+ }
+
+ LLVoiceChannel::handleError(status);
+}
+
+void LLVoiceChannelProximal::deactivate()
+{
+ if (callStarted())
+ {
+ setState(STATE_HUNG_UP);
+ }
+}
+
+
+//
+// LLVoiceChannelP2P
+//
+LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
+ LLVoiceChannelGroup(session_id, session_name),
+ mOtherUserID(other_user_id),
+ mReceivedCall(FALSE)
+{
+ // make sure URI reflects encoded version of other user's agent id
+ setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
+}
+
+void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
+{
+ // status updates
+ switch(type)
+ {
+ case STATUS_LEFT_CHANNEL:
+ if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
+ {
+ if (mState == STATE_RINGING)
+ {
+ // other user declined call
+ LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs);
+ }
+ else
+ {
+ // other user hung up
+ LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs);
+ }
+ deactivate();
+ }
+ mIgnoreNextSessionLeave = FALSE;
+ return;
+ default:
+ break;
+ }
+
+ LLVoiceChannel::handleStatusChange(type);
+}
+
+void LLVoiceChannelP2P::handleError(EStatusType type)
+{
+ switch(type)
+ {
+ case ERROR_NOT_AVAILABLE:
+ LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs);
+ break;
+ default:
+ break;
+ }
+
+ LLVoiceChannel::handleError(type);
+}
+
+void LLVoiceChannelP2P::activate()
+{
+ if (callStarted()) return;
+
+ LLVoiceChannel::activate();
+
+ if (callStarted())
+ {
+ // no session handle yet, we're starting the call
+ if (mSessionHandle.empty())
+ {
+ mReceivedCall = FALSE;
+ LLVoiceClient::getInstance()->callUser(mOtherUserID);
+ }
+ // otherwise answering the call
+ else
+ {
+ LLVoiceClient::getInstance()->answerInvite(mSessionHandle);
+
+ // using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
+ mSessionHandle.clear();
+ }
+
+ // Add the party to the list of people with which we've recently interacted.
+ LLRecentPeople::instance().add(mOtherUserID);
+ }
+}
+
+void LLVoiceChannelP2P::getChannelInfo()
+{
+ // pretend we have everything we need, since P2P doesn't use channel info
+ if (sCurrentVoiceChannel == this)
+ {
+ setState(STATE_CALL_STARTED);
+ }
+}
+
+// receiving session from other user who initiated call
+void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
+{
+ BOOL needs_activate = FALSE;
+ if (callStarted())
+ {
+ // defer to lower agent id when already active
+ if (mOtherUserID < gAgent.getID())
+ {
+ // pretend we haven't started the call yet, so we can connect to this session instead
+ deactivate();
+ needs_activate = TRUE;
+ }
+ else
+ {
+ // we are active and have priority, invite the other user again
+ // under the assumption they will join this new session
+ mSessionHandle.clear();
+ LLVoiceClient::getInstance()->callUser(mOtherUserID);
+ return;
+ }
+ }
+
+ mSessionHandle = handle;
+
+ // The URI of a p2p session should always be the other end's SIP URI.
+ if(!inURI.empty())
+ {
+ setURI(inURI);
+ }
+ else
+ {
+ setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
+ }
+
+ mReceivedCall = TRUE;
+
+ if (needs_activate)
+ {
+ activate();
+ }
+}
+
+void LLVoiceChannelP2P::setState(EState state)
+{
+ // HACK: Open/close the call window if needed.
+ toggleCallWindowIfNeeded(state);
+
+ // you only "answer" voice invites in p2p mode
+ // so provide a special purpose message here
+ if (mReceivedCall && state == STATE_RINGING)
+ {
+ gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
+ mState = state;
+ return;
+ }
+ LLVoiceChannel::setState(state);
+}
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
new file mode 100644
index 0000000000..9966bdd5ab
--- /dev/null
+++ b/indra/newview/llvoicechannel.h
@@ -0,0 +1,168 @@
+/**
+ * @file llvoicechannel.h
+ * @brief Voice channel related classes
+ *
+ * $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_VOICECHANNEL_H
+#define LL_VOICECHANNEL_H
+
+#include "llhandle.h"
+#include "llvoiceclient.h"
+
+class LLPanel;
+
+class LLVoiceChannel : public LLVoiceClientStatusObserver
+{
+public:
+ typedef enum e_voice_channel_state
+ {
+ STATE_NO_CHANNEL_INFO,
+ STATE_ERROR,
+ STATE_HUNG_UP,
+ STATE_READY,
+ STATE_CALL_STARTED,
+ STATE_RINGING,
+ STATE_CONNECTED
+ } EState;
+
+ LLVoiceChannel(const LLUUID& session_id, const std::string& session_name);
+ virtual ~LLVoiceChannel();
+
+ /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
+ virtual void handleStatusChange(EStatusType status);
+ virtual void handleError(EStatusType status);
+ virtual void deactivate();
+ virtual void activate();
+ virtual void setChannelInfo(
+ const std::string& uri,
+ const std::string& credentials);
+ virtual void getChannelInfo();
+ virtual BOOL isActive();
+ virtual BOOL callStarted();
+ const std::string& getSessionName() const { return mSessionName; }
+
+ const LLUUID getSessionID() { return mSessionID; }
+ EState getState() { return mState; }
+
+ void updateSessionID(const LLUUID& new_session_id);
+ const LLSD& getNotifyArgs() { return mNotifyArgs; }
+
+ static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
+ static LLVoiceChannel* getChannelByURI(std::string uri);
+ static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }
+ static void initClass();
+
+ static void suspend();
+ static void resume();
+
+protected:
+ virtual void setState(EState state);
+ void toggleCallWindowIfNeeded(EState state);
+ void setURI(std::string uri);
+
+ std::string mURI;
+ std::string mCredentials;
+ LLUUID mSessionID;
+ EState mState;
+ std::string mSessionName;
+ LLSD mNotifyArgs;
+ BOOL mIgnoreNextSessionLeave;
+ LLHandle<LLPanel> mLoginNotificationHandle;
+
+ typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t;
+ static voice_channel_map_t sVoiceChannelMap;
+
+ typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t;
+ static voice_channel_map_uri_t sVoiceChannelURIMap;
+
+ static LLVoiceChannel* sCurrentVoiceChannel;
+ static LLVoiceChannel* sSuspendedVoiceChannel;
+ static BOOL sSuspended;
+};
+
+class LLVoiceChannelGroup : public LLVoiceChannel
+{
+public:
+ LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name);
+
+ /*virtual*/ void handleStatusChange(EStatusType status);
+ /*virtual*/ void handleError(EStatusType status);
+ /*virtual*/ void activate();
+ /*virtual*/ void deactivate();
+ /*vritual*/ void setChannelInfo(
+ const std::string& uri,
+ const std::string& credentials);
+ /*virtual*/ void getChannelInfo();
+
+protected:
+ virtual void setState(EState state);
+
+private:
+ U32 mRetries;
+ BOOL mIsRetrying;
+};
+
+class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal>
+{
+public:
+ LLVoiceChannelProximal();
+
+ /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+ /*virtual*/ void handleStatusChange(EStatusType status);
+ /*virtual*/ void handleError(EStatusType status);
+ /*virtual*/ BOOL isActive();
+ /*virtual*/ void activate();
+ /*virtual*/ void deactivate();
+
+};
+
+class LLVoiceChannelP2P : public LLVoiceChannelGroup
+{
+public:
+ LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id);
+
+ /*virtual*/ void handleStatusChange(EStatusType status);
+ /*virtual*/ void handleError(EStatusType status);
+ /*virtual*/ void activate();
+ /*virtual*/ void getChannelInfo();
+
+ void setSessionHandle(const std::string& handle, const std::string &inURI);
+
+protected:
+ virtual void setState(EState state);
+
+private:
+ std::string mSessionHandle;
+ LLUUID mOtherUserID;
+ BOOL mReceivedCall;
+};
+
+#endif // LL_VOICECHANNEL_H
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 02f63a848b..2834284a9b 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -57,13 +57,13 @@
#include "llagent.h"
#include "llcachename.h"
#include "llimview.h" // for LLIMMgr
-#include "llimpanel.h" // for LLVoiceChannel
#include "llparcel.h"
#include "llviewerparcelmgr.h"
#include "llfirstuse.h"
#include "llviewerwindow.h"
#include "llviewercamera.h"
#include "llvoavatarself.h"
+#include "llvoicechannel.h"
#include "llfloaterfriends.h" //VIVOX, inorder to refresh communicate panel
#include "llfloaterchat.h" // for LLFloaterChat::addChat()
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 8f74ea29ac..a091028ec2 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -545,7 +545,7 @@ BOOL LLWearable::isDirty() const
else
{
// image found in current image list but not saved image list
- return FALSE;
+ return TRUE;
}
}
}
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index b46b766fc0..d3366cdcaa 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -144,6 +144,7 @@
<texture name="Info" file_name="icons/Info.png" preload="false" />
<texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />
<texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" />
+ <texture name="Info_Over" file_name="icons/Info_Over.png" preload="false" />
<texture name="Info_Press" file_name="navbar/Info_Press.png" preload="false" />
<texture name="Inspector_Background" file_name="windows/Inspector_Background.png" preload="false" />
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 072fafd06e..aa0b4094b4 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -28,7 +28,9 @@
follows="left|top|right|bottom"
height="400"
layout="topleft"
+ font="SansSerifSmall"
left="1"
+ tab_padding_right="5"
name="landtab"
tab_position="top"
top="20"
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index 520249c2a2..a713cc32a0 100644
--- a/indra/newview/skins/default/xui/en/floater_camera.xml
+++ b/indra/newview/skins/default/xui/en/floater_camera.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
can_dock="true"
- can_minimize="true"
- can_close="true"
+ can_minimize="false"
+ can_close="true"
center_horiz="true"
- follows="top"
- height="110"
+ follows="bottom"
+ height="152"
layout="topleft"
name="camera_floater"
help_topic="camera_floater"
save_rect="true"
save_visibility="true"
- width="105">
+ width="150">
<floater.string
name="rotate_tooltip">
Rotate Camera Around Focus
@@ -25,69 +25,71 @@
Move Camera Up and Down, Left and Right
</floater.string>
<panel
- border="true"
- height="79"
+ border="false"
+ height="110"
layout="topleft"
- left="0"
+ left="2"
top="0"
- mouse_opaque="false"
+ mouse_opaque="false"
name="controls"
- width="105">
- <joystick_rotate
- follows="top|left"
- height="64"
- image_selected="cam_rotate_in.tga"
- image_unselected="cam_rotate_out.tga"
- layout="topleft"
- left="2"
- name="cam_rotate_stick"
- picture_style="true"
- quadrant="left"
- scale_image="false"
- sound_flags="3"
- tool_tip="Orbit camera around focus"
- top="15"
- width="64" />
+ width="148">
<joystick_track
follows="top|left"
- height="64"
- image_selected="cam_tracking_in.tga"
- image_unselected="cam_tracking_out.tga"
+ height="78"
+ image_selected="Cam_Tracking_In"
+ image_unselected="Cam_Tracking_Out"
layout="topleft"
- left="2"
+ left="45"
name="cam_track_stick"
picture_style="true"
quadrant="left"
scale_image="false"
sound_flags="3"
tool_tip="Move camera up and down, left and right"
- top="15"
+ top="22"
visible="false"
- width="64" />
+ width="78" />
+ <!--TODO: replace with slider, + - images -->
<joystick_zoom
follows="top|left"
- height="64"
- image_unselected="cam_zoom_out.tga"
+ height="78"
+ image_unselected="ScrollThumb_Vert"
layout="topleft"
- left_delta="70"
- minus_image="cam_zoom_minus_in.tga"
+ left="7"
+ minus_image="ScrollThumb_Vert"
name="zoom"
picture_style="true"
- plus_image="cam_zoom_plus_in.tga"
+ plus_image="ScrollThumb_Vert"
quadrant="left"
scale_image="false"
sound_flags="3"
tool_tip="Zoom camera toward focus"
- top_delta="0"
- width="16" />
+ top="22"
+ width="20" />
+ <joystick_rotate
+ follows="top|left"
+ height="78"
+ image_selected="Cam_Rotate_In"
+ image_unselected="Cam_Rotate_Out"
+ layout="topleft"
+ left="45"
+ name="cam_rotate_stick"
+ picture_style="true"
+ quadrant="left"
+ scale_image="false"
+ sound_flags="3"
+ visible="true"
+ tool_tip="Orbit camera around focus"
+ top="22"
+ width="78" />
<panel
- height="70"
+ height="78"
layout="topleft"
- left="15"
+ left="36"
name="camera_presets"
- top="15"
+ top="30"
visible="false"
- width="75">
+ width="78">
<button
height="30"
image_selected="CameraPreset_Rear"
@@ -127,7 +129,7 @@
name="front_view"
picture_style="true"
tool_tip="Front View"
- top_pad="2"
+ top_pad="5"
width="30">
<click_callback
function="CameraPresets.ChangeView"
@@ -151,21 +153,21 @@
</panel>
</panel>
<panel
- border="true"
- height="25"
+ border="false"
+ height="42"
layout="topleft"
- left="0"
- top_pad="1"
+ left="2"
+ top_pad="0"
name="buttons"
- width="105">
+ width="148">
<button
height="23"
label=""
layout="topleft"
- left="2"
+ left="23"
is_toggle="true"
image_overlay="Cam_Orbit_Off"
- image_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
name="orbit_btn"
tab_stop="false"
tool_tip="Orbit camera"
@@ -179,7 +181,7 @@
left_pad="0"
is_toggle="true"
image_overlay="Cam_Pan_Off"
- image_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
name="pan_btn"
tab_stop="false"
tool_tip="Pan camera"
@@ -191,7 +193,7 @@
layout="topleft"
left_pad="0"
image_overlay="Cam_Avatar_Off"
- image_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
name="avatarview_btn"
tab_stop="false"
tool_tip="See as avatar"
@@ -204,12 +206,11 @@
left_pad="0"
is_toggle="true"
image_overlay="Cam_FreeCam_Off"
- image_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
name="freecamera_btn"
tab_stop="false"
tool_tip="View object"
width="25">
</button>
-
</panel>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
index 0bd4b441c6..d24d1b7064 100644
--- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
+++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
@@ -14,7 +14,7 @@
save_rect="true"
title="Nearby Chat"
save_visibility="true"
- single_instance="true"
+ single_instance="true"
width="320">
<chat_history
allow_html="true"
diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml
index 5f70f09a34..69525d48d2 100644
--- a/indra/newview/skins/default/xui/en/floater_pay.xml
+++ b/indra/newview/skins/default/xui/en/floater_pay.xml
@@ -34,7 +34,7 @@
type="string"
length="1"
follows="left|top"
- font="SansSerif"
+ font="SansSerifSmall"
height="16"
layout="topleft"
left_pad="7"
@@ -44,6 +44,7 @@
</text>
<button
height="23"
+ font="SansSerifSmall"
label="L$1"
label_selected="L$1"
layout="topleft"
@@ -53,7 +54,8 @@
width="80" />
<button
height="23"
- label="L$5"
+ label="L$1"
+ font="SansSerif"
label_selected="L$5"
layout="topleft"
left_pad="15"
@@ -62,6 +64,7 @@
<button
height="23"
label="L$10"
+ font="SansSerifHuge"
label_selected="L$10"
layout="topleft"
left="25"
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 8cdafe110a..d2b8455eab 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
@@ -83,7 +83,7 @@
Loading...
</text_editor>
<button
- follows="left|bottom"
+ follows="right|bottom"
height="22"
label="Save"
label_selected="Save"
diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
index abde4ba5fa..884532c7a3 100644
--- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
@@ -14,19 +14,19 @@
allow_no_texture="true"
default_image_name="None"
follows="left|top"
- height="125"
+ height="150"
layout="topleft"
- left="10"
- name="screenshot"
- top="23"
- width="160" />
+ left="60"
+ name=""
+ top="15"
+ width="220" />
<check_box
height="15"
label="Use this screenshot"
layout="topleft"
- left_pad="5"
+ left="8"
name="screen_check"
- top="120"
+ top_pad="-12"
width="116" />
<text
type="string"
@@ -38,8 +38,8 @@
layout="topleft"
left="10"
name="reporter_title"
- top="140"
- width="60">
+ top_pad="0"
+ width="100">
Reporter:
</text>
<text
@@ -48,24 +48,25 @@
follows="left|top"
height="16"
layout="topleft"
- left_pad="10"
+ left_pad="5"
name="reporter_field"
top_delta="0"
- width="193">
- Loremipsum Dolorsitamut
+ use_ellipses="true"
+ width="200">
+ Loremipsum Dolorsitamut Longnamez
</text>
<text
type="string"
length="1"
follows="left|top"
height="16"
- font.name="SansSerif"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left="10"
name="sim_title"
- top_pad="5"
- width="60">
+ top_pad="2"
+ width="100">
Region:
</text>
<text
@@ -74,10 +75,11 @@
follows="left|top"
height="16"
layout="topleft"
- left_pad="2"
+ left_pad="5"
name="sim_field"
top_delta="0"
- width="193">
+ use_ellipses="true"
+ width="200">
Region Name
</text>
<text
@@ -85,13 +87,13 @@
length="1"
follows="left|top"
height="16"
- font.name="SansSerif"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left="10"
name="pos_title"
- top_pad="5"
- width="50">
+ top_pad="2"
+ width="100">
Position:
</text>
<text
@@ -100,10 +102,10 @@
follows="left|top"
height="16"
layout="topleft"
- left_pad="12"
+ left_pad="5"
name="pos_field"
top_delta="0"
- width="193">
+ width="200">
{128.1, 128.1, 15.4}
</text>
<text
@@ -114,7 +116,7 @@
layout="topleft"
left="10"
name="select_object_label"
- top_pad="5"
+ top_pad="2"
width="310">
Click the button, then the abusive object:
</text>
@@ -133,13 +135,13 @@
length="1"
follows="left|top"
height="16"
- font.name="SansSerif"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left="48"
name="object_name_label"
top_delta="0"
- width="60">
+ width="80">
Object:
</text>
<text
@@ -151,7 +153,8 @@
left_pad="6"
name="object_name"
top_delta="0"
- width="157">
+ use_ellipses="true"
+ width="185">
Consetetur Sadipscing
</text>
<text
@@ -159,13 +162,13 @@
length="1"
follows="left|top"
height="16"
- font.name="SansSerif"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left="48"
name="owner_name_label"
top_pad="0"
- width="60">
+ width="80">
Owner:
</text>
<text
@@ -177,8 +180,9 @@
left_pad="6"
name="owner_name"
top_delta="0"
- width="157">
- Hendrerit Vulputate
+ use_ellipses="true"
+ width="185">
+ Hendrerit Vulputate Kamawashi Longname
</text>
<combo_box
height="23"
@@ -349,8 +353,8 @@
type="string"
length="1"
follows="left|top"
- height="16"
- font.name="SansSerif"
+ height="14"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left_delta="0"
@@ -368,11 +372,10 @@
left_delta="0"
max_length="32"
name="abuser_name_edit"
- top_pad="2"
+ top_pad="0"
width="195" />
<button
height="23"
- font="SansSerifSmall"
label="Choose"
layout="topleft"
left_pad="5"
@@ -394,13 +397,13 @@
type="string"
length="1"
follows="left|top"
- height="16"
- font.name="SansSerif"
+ height="14"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left="10"
name="abuser_name_title2"
- top_pad="5"
+ top_pad="2"
width="313">
Location of Abuse:
</text>
@@ -413,19 +416,19 @@
left="10"
max_length="256"
name="abuse_location_edit"
- top_pad="2"
+ top_pad="0"
width="313" />
<text
type="string"
length="1"
follows="left|top"
height="16"
- font.name="SansSerif"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left_delta="0"
name="sum_title"
- top_pad="5"
+ top_pad="2"
width="313">
Summary:
</text>
@@ -438,14 +441,14 @@
left_delta="0"
max_length="64"
name="summary_edit"
- top_pad="2"
+ top_pad="0"
width="313" />
<text
type="string"
length="1"
follows="left|top"
- height="16"
- font.name="SansSerif"
+ height="14"
+ font.name="SansSerif"
font.style="BOLD"
layout="topleft"
left_delta="0"
@@ -461,9 +464,9 @@
height="16"
layout="topleft"
name="bug_aviso"
- left_pad="0"
+ left_pad="10"
width="200">
- Please be as specific as possible.
+ Please be as specific as possible
</text>
<text_editor
follows="left|top"
@@ -479,16 +482,15 @@
type="string"
length="1"
follows="left|top"
- height="50"
+ height="30"
layout="topleft"
left="10"
- font.name="SansSerif"
- font.style="BOLD"
+ font.name="SansSerifSmall"
name="incomplete_title"
- top_pad="5"
+ top_pad="2"
word_wrap="true"
width="313">
- Note: Incomplete reports won't be investigated.
+ * Incomplete reports won't be investigated
</text>
<button
left="80"
diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
index 8305452c85..c33ab8aa70 100644
--- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
@@ -114,16 +114,59 @@
Escaped greater than &gt;
</text>
<text
- type="string"
- length="1"
- bottom="390"
- label="N"
- layout="topleft"
- left="10"
- name="floater_map_north"
- right="30"
- text_color="1 1 1 0.7"
- top="370">
- N
- </text>
+ type="string"
+ length="1"
+ bottom="390"
+ label="N"
+ layout="topleft"
+ left="10"
+ name="right_aligned_text"
+ width="380"
+ halign="right"
+ text_color="1 1 1 0.7"
+ top_pad="10">
+ Right aligned text
+ </text>
+ <text
+ type="string"
+ length="1"
+ bottom="390"
+ label="N"
+ layout="topleft"
+ left="10"
+ name="centered_text"
+ width="380"
+ halign="center"
+ text_color="1 1 1 0.7"
+ top_pad="10">
+ Centered text
+ </text>
+ <text
+ type="string"
+ length="1"
+ bottom="390"
+ label="N"
+ layout="topleft"
+ left="10"
+ name="centered_text"
+ width="380"
+ halign="left"
+ text_color="1 1 1 0.7"
+ top_pad="10">
+ Left aligned text
+ </text>
+ <text
+ type="string"
+ length="1"
+ bottom="390"
+ label="N"
+ layout="topleft"
+ left="10"
+ name="floater_map_north"
+ right="30"
+ text_color="1 1 1 0.7"
+ top="370">
+ N
+ </text>
+
</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
index cc17e9dd4b..eedb4383bb 100644
--- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
@@ -23,9 +23,14 @@
parameter="sort_status" />
</menu_item_check>
<menu_item_separator layout="topleft" />
- <menu_item_call name="view_icons" label="View People Icons">
- <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="view_icons" />
- </menu_item_call>
+ <menu_item_check name="view_icons" label="View People Icons">
+ <menu_item_check.on_click
+ function="People.Friends.ViewSort.Action"
+ parameter="view_icons" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="FriendsListShowIcons" />
+ </menu_item_check>
<menu_item_call name="organize_offline" label="Organize Offline Friends">
<menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="organize_offline" />
</menu_item_call>
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
index f91a961388..c002cd078f 100644
--- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
@@ -12,9 +12,14 @@
<menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="sort_distance" />
</menu_item_call>
<menu_item_separator layout="topleft" />
- <menu_item_call name="view_icons" label="View People Icons">
- <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="view_icons" />
- </menu_item_call>
+ <menu_item_check name="view_icons" label="View People Icons">
+ <menu_item_check.on_click
+ function="People.Nearby.ViewSort.Action"
+ parameter="view_icons" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="NearbyListShowIcons" />
+ </menu_item_check>
<menu_item_separator layout="topleft" />
<menu_item_call name="show_blocked_list" label="Show Blocked Residents &amp; Objects">
<menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" />
diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
index d09871cff3..cfd6dc78b6 100644
--- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
@@ -23,9 +23,14 @@
parameter="sort_name" />
</menu_item_check>
<menu_item_separator layout="topleft" />
- <menu_item_call name="view_icons" label="View People Icons">
- <menu_item_call.on_click function="People.Recent.ViewSort.Action" userdata="view_icons" />
- </menu_item_call>
+ <menu_item_check name="view_icons" label="View People Icons">
+ <menu_item_check.on_click
+ function="People.Recent.ViewSort.Action"
+ parameter="view_icons" />
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="RecentListShowIcons" />
+ </menu_item_check>
<menu_item_separator layout="topleft" />
<menu_item_call name="show_blocked_list" label="Show Blocked Residents &amp; Objects">
<menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" />
diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml
new file mode 100644
index 0000000000..e3a39a1242
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="menu_folder_gear"
+ visible="false">
+ <menu_item_call
+ label="Add Folder"
+ layout="topleft"
+ name="add_folder">
+ <on_click
+ function="Places.LandmarksGear.Add.Action"
+ parameter="category" />
+ <on_enable
+ function="Places.LandmarksGear.Enable"
+ parameter="category" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add Landmark"
+ layout="topleft"
+ name="add_landmark">
+ <on_click
+ function="Places.LandmarksGear.Add.Action"
+ parameter="add_landmark" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7d2ef4923e..ac98907199 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6151,8 +6151,7 @@ Your L$ balance is shown in the upper-right.
type="notify">
Thank you for your payment!
-When the processing completes, your L$ balance will be updated at the top of your screen.
-If processing your payment takes more than 20 minutes to complete, the purchase amount will be credited to your account for use on your next purchase.
+Your L$ balance will be updated when processing completes. If processing takes more than 20 mins, your transaction may be cancelled. In that case, the purchase amount will be credited to your US$ balance.
The status of your payment can be checked on your Transaction History page at Me > My Dashboard, or http://secondlife.com/account/
</notification>
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
new file mode 100644
index 0000000000..8db745fab7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ name="panel_im_control_panel"
+ width="146"
+ height="215"
+ border="false">
+ <avatar_list
+ color="DkGray2"
+ follows="left|top|right|bottom"
+ height="130"
+ ignore_online_status="true"
+ layout="topleft"
+ left="3"
+ name="speakers_list"
+ opaque="false"
+ top="10"
+ width="140" />
+ <button
+ name="call_btn"
+ label="Call"
+ width="90"
+ height="20" />
+ <button
+ name="end_call_btn"
+ label="End Call"
+ width="90"
+ height="20"
+ visible="false"/>
+</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 9767a673f6..15b6b2a00d 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
@@ -7,12 +7,14 @@
<avatar_list
color="DkGray2"
follows="left|top|right|bottom"
- height="150"
+ height="130"
+ ignore_online_status="true"
layout="topleft"
left="3"
name="speakers_list"
+ opaque="false"
top="10"
- width="140"/>
+ width="140" />
<button
name="group_info_btn"
label="Group Info"
@@ -24,4 +26,10 @@
label="Call"
width="90"
height="20" />
+ <button
+ name="end_call_btn"
+ label="End Call"
+ width="90"
+ height="20"
+ visible="false"/>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml
index 75ded4f249..af1919bd8f 100644
--- a/indra/newview/skins/default/xui/en/panel_group_roles.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml
@@ -486,7 +486,7 @@ things in this group. There&apos;s a broad variety of Abilities.
</panel>
</tab_container>
<panel
- height="170"
+ height="190"
layout="topleft"
follows="left|top"
left="10"
@@ -556,7 +556,7 @@ things in this group. There&apos;s a broad variety of Abilities.
</scroll_list>
</panel>
<panel
- height="215"
+ height="252"
layout="topleft"
left_delta="0"
name="roles_footer"
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 7dc94d1141..dca52def49 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
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel name="panel_im_control_panel"
width="96"
- height="215"
+ height="225"
border="false">
<avatar_icon name="avatar_icon"
@@ -24,6 +24,13 @@
width="90"
height="20" />
+ <button
+ height="20"
+ label="End Call"
+ name="end_call_btn"
+ visible="false"
+ width="90" />
+
<button name="share_btn"
label="Share"
width="90"
diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml
index c33f68eaf7..5293043ba7 100644
--- a/indra/newview/skins/default/xui/en/panel_landmarks.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml
@@ -114,22 +114,10 @@
image_disabled="AddItem_Disabled"
layout="topleft"
left_pad="5"
- name="add_landmark_btn"
+ name="add_btn"
picture_style="true"
tool_tip="Add new landmark"
width="18" />
- <button
- follows="bottom|left"
- height="18"
- image_selected="AddItem_Press"
- image_unselected="AddItem_Off"
- image_disabled="AddItem_Disabled"
- layout="topleft"
- left_pad="5"
- name="add_folder_btn"
- picture_style="true"
- tool_tip="Add new folder"
- width="18" />
<dnd_button
follows="bottom|right"
height="18"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 7b19ab1a1c..69089e0e26 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -49,11 +49,13 @@ background_visible="true"
height="500"
layout="topleft"
left="10"
+ font="SansSerifBigBold"
name="tabs"
tab_min_width="70"
tab_height="30"
tab_position="top"
top_pad="10"
+ halign="center"
width="313">
<panel
follows="all"
diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
new file mode 100644
index 0000000000..b21fbc1795
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="left|right|top|bottom"
+ name="MediaControls"
+ bg_alpha_color="1 1 1 0"
+ height="160"
+ layout="topleft"
+ mouse_opaque="false"
+ width="800">
+ <panel
+ name="media_region"
+ bottom="125"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="20"
+ mouse_opaque="false"
+ right="-20"
+ top="20" />
+ <layout_stack
+ follows="left|right|bottom"
+ height="32"
+ layout="topleft"
+ animate="false"
+ left="0"
+ orientation="horizontal"
+ top="96">
+ <!-- outer layout_panels center the inner one -->
+ <layout_panel
+ width="0"
+ layout="topleft"
+ user_resize="false" />
+ <panel
+ name="media_progress_indicator"
+ height="22"
+ layout="topleft"
+ left="0"
+ top="0"
+ auto_resize="false"
+ user_resize="false"
+ min_width="100"
+ width="200">
+ <progress_bar
+ name="media_progress_bar"
+ color_bar="1 1 1 0.96"
+ follows="left|right|top"
+ height="16"
+ layout="topleft"
+ left="0"
+ tool_tip="Media is Loading"/>
+ </panel>
+ <layout_panel
+ width="0"
+ layout="topleft"
+ user_resize="false" />
+ </layout_stack>
+ <layout_stack
+ name="media_controls"
+ follows="left|right"
+ animate="false"
+ height="32"
+ layout="topleft"
+ left="0"
+ orientation="horizontal"
+ top="128">
+ <!-- outer layout_panels center the inner one -->
+ <layout_panel
+ width="0"
+ layout="topleft"
+ user_resize="false" />
+ <layout_panel
+ name="back"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ min_width="22"
+ width="22"
+ top="4">
+ <button
+ auto_resize="false"
+ height="22"
+ image_selected="media_btn_back.png"
+ image_unselected="media_btn_back.png"
+ layout="topleft"
+ tool_tip="Step back"
+ picture_style="true"
+ width="22"
+ top_delta="4">
+ <button.commit_callback
+ function="MediaCtrl.Back" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="fwd"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="10"
+ min_width="17"
+ width="17">
+ <button
+ height="22"
+ image_selected="media_btn_forward.png"
+ image_unselected="media_btn_forward.png"
+ layout="topleft"
+ tool_tip="Step forward"
+ picture_style="true"
+ top_delta="0"
+ min_width="17"
+ width="17">
+ <button.commit_callback
+ function="MediaCtrl.Forward" />
+ </button>
+ </layout_panel>
+<!--
+ <panel
+ height="22"
+ layout="topleft"
+ auto_resize="false"
+ min_width="3"
+ width="3">
+ <icon
+ height="22"
+ image_name="media_panel_divider.png"
+ layout="topleft"
+ top="0"
+ min_width="3"
+ width="3" />
+ </panel>
+-->
+ <layout_panel
+ name="home"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="-2"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="media_btn_home.png"
+ image_unselected="media_btn_home.png"
+ layout="topleft"
+ tool_tip="Home page"
+ picture_style="true"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Home" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="media_stop"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="2"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="button_anim_stop.tga"
+ image_unselected="button_anim_stop.tga"
+ layout="topleft"
+ tool_tip="Stop media"
+ picture_style="true"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Stop" />
+ </button>
+ </layout_panel>
+<!--
+ <panel
+ height="22"
+ layout="topleft"
+ auto_resize="false"
+ min_width="3"
+ width="3">
+ <icon
+ height="22"
+ image_name="media_panel_divider.png"
+ layout="topleft"
+ top="0"
+ min_width="3"
+ width="3" />
+ </panel>
+-->
+ <layout_panel
+ name="reload"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="6"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="media_btn_reload.png"
+ image_unselected="media_btn_reload.png"
+ layout="topleft"
+ tool_tip="Reload"
+ picture_style="true"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Reload" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="stop"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="10"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="media_btn_stoploading.png"
+ image_unselected="media_btn_stoploading.png"
+ layout="topleft"
+ picture_style="true"
+ tool_tip = "Stop loading"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Stop" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="play"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="14"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="button_anim_play.tga"
+ image_unselected="button_anim_play.tga"
+ layout="topleft"
+ tool_tip = "Play media"
+ picture_style="true"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Play" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="pause"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ top="18"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="button_anim_pause.tga"
+ image_unselected="button_anim_pause.tga"
+ layout="topleft"
+ tool_tip = "Pause media"
+ picture_style="true">
+ <button.commit_callback
+ function="MediaCtrl.Pause" />
+ </button>
+ </layout_panel>
+ <!-- media URL entry -->
+ <layout_panel
+ name="media_address"
+ auto_resize="true"
+ user_resize="false"
+ height="22"
+ follows="left|right|bottom"
+ layout="topleft"
+ width="190"
+ min_width="90">
+ <!--
+ RE-ENABLE THIS WHEN WE HAVE A HISTORY DROP-DOWN AGAIN
+
+<combo_box
+name="media_address_url"
+allow_text_entry="true"
+height="22"
+layout="topleft"
+max_chars="1024"
+tool_tip = "Media URL"
+<combo_box.commit_callback
+function="MediaCtrl.CommitURL" />
+</combo_box>
+ -->
+ <line_editor
+ name="media_address_url"
+ follows="left|right"
+ height="22"
+ top="0"
+ tool_tip="Media URL"
+ text_pad_right="16">
+ <line_editor.commit_callback
+ function="MediaCtrl.CommitURL"/>
+ </line_editor>
+ <layout_stack
+ animate="false"
+ follows="right"
+ width="32"
+ min_width="32"
+ height="16"
+ top="3"
+ orientation="horizontal"
+ left_pad="-38">
+ <icon
+ name="media_whitelist_flag"
+ follows="top|right"
+ height="16"
+ image_name="smicon_warn.tga"
+ layout="topleft"
+ tool_tip="White List enabled"
+ min_width="16"
+ width="16" />
+ <icon
+ name="media_secure_lock_flag"
+ height="16"
+ image_name="inv_item_eyes.tga"
+ layout="topleft"
+ tool_tip="Secured Browsing"
+ min_width="16"
+ width="16" />
+ </layout_stack>
+ </layout_panel>
+ <layout_panel
+ name="media_play_position"
+ auto_resize="true"
+ user_resize="false"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ min_width="100"
+ width="200">
+ <slider_bar
+ name="media_play_slider"
+ follows="left|right|top"
+ height="22"
+ increment="0.05"
+ initial_value="0.5"
+ layout="topleft"
+ tool_tip="Movie play progress"
+ min_width="100"
+ width="200">
+ <slider_bar.commit_callback
+ function="MediaCtrl.JumpProgress" />
+ </slider_bar>
+ </layout_panel>
+ <layout_panel
+ name="media_volume"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ height="24"
+ min_width="24"
+ width="24">
+ <button
+ name="media_volume_button"
+ height="22"
+ image_selected="icn_speaker-muted_dark.tga"
+ image_unselected="icn_speaker_dark.tga"
+ is_toggle="true"
+ layout="topleft"
+ scale_image="false"
+ picture_style="true"
+ tool_tip="Mute This Media"
+ top_delta="22"
+ min_width="24"
+ width="24" >
+ <button.commit_callback
+ function="MediaCtrl.ToggleMute" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="volume_up"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ min_width="20"
+ height="14"
+ width="20">
+ <button
+ top="-3"
+ height="14"
+ image_selected="media_btn_scrollup.png"
+ image_unselected="media_btn_scrollup.png"
+ layout="topleft"
+ tool_tip="Volume up"
+ picture_style="true"
+ scale_image="true"
+ min_width="20"
+ width="20" >
+ <button.commit_callback
+ function="MediaCtrl.CommitVolumeUp" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ name="volume_down"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ min_width="20"
+ height="14"
+ width="20">
+ <button
+ top="-5"
+ height="14"
+ image_selected="media_btn_scrolldown.png"
+ image_unselected="media_btn_scrolldown.png"
+ layout="topleft"
+ tool_tip="Volume down"
+ picture_style="true"
+ scale_image="true"
+ min_width="20"
+ width="20">
+ <button.commit_callback
+ function="MediaCtrl.CommitVolumeDown" />
+ </button>
+ </layout_panel>
+ <!-- Scroll pad -->
+ <layout_panel
+ name="media_panel_scroll"
+ auto_resize="false"
+ user_resize="false"
+ height="32"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ min_width="32"
+ width="32">
+ <icon
+ height="32"
+ image_name="media_panel_scrollbg.png"
+ layout="topleft"
+ top="0"
+ min_width="32"
+ width="32" />
+ <button
+ name="scrollup"
+ height="8"
+ image_selected="media_btn_scrollup.png"
+ image_unselected="media_btn_scrollup.png"
+ layout="topleft"
+ tool_tip="Scroll up"
+ picture_style="true"
+ scale_image="false"
+ left="12"
+ top_delta="4"
+ min_width="8"
+ width="8" />
+ <button
+ name="scrollleft"
+ height="8"
+ image_selected="media_btn_scrollleft.png"
+ image_unselected="media_btn_scrollleft.png"
+ layout="topleft"
+ left="3"
+ tool_tip="Scroll left"
+ picture_style="true"
+ scale_image="false"
+ top="12"
+ min_width="8"
+ width="8" />
+ <button
+ name="scrollright"
+ height="8"
+ image_selected="media_btn_scrollright.png"
+ image_unselected="media_btn_scrollright.png"
+ layout="topleft"
+ left_pad="9"
+ tool_tip="Scroll right"
+ picture_style="true"
+ scale_image="false"
+ top_delta="0"
+ min_width="8"
+ width="8" />
+ <button
+ name="scrolldown"
+ height="8"
+ image_selected="media_btn_scrolldown.png"
+ image_unselected="media_btn_scrolldown.png"
+ layout="topleft"
+ left="12"
+ tool_tip="Scroll down"
+ picture_style="true"
+ scale_image="false"
+ top="20"
+ min_width="8"
+ width="8" />
+ </layout_panel>
+ <layout_panel
+ name="zoom_frame"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ height="28"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="media_btn_optimalzoom.png"
+ image_unselected="media_btn_optimalzoom.png"
+ layout="topleft"
+ tool_tip="Zoom"
+ picture_style="true"
+ min_width="22"
+ width="22">
+ <button.commit_callback
+ function="MediaCtrl.Zoom" />
+ </button>
+ </layout_panel>
+<!--
+ <panel
+ height="22"
+ layout="topleft"
+ auto_resize="false"
+ min_width="3"
+ width="3">
+ <icon
+ height="22"
+ image_name="media_panel_divider.png"
+ layout="topleft"
+ top="0"
+ min_width="3"
+ width="3" />
+ </panel>
+-->
+ <layout_panel
+ name="new_window"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ min_width="22"
+ width="22">
+ <button
+ height="22"
+ image_selected="media_btn_newwindow.png"
+ image_unselected="media_btn_newwindow.png"
+ layout="topleft"
+ tool_tip = "Open URL in browser"
+ picture_style="true"
+ top_delta="-3"
+ min_width="24"
+ width="24" >
+ <button.commit_callback
+ function="MediaCtrl.Open" />
+ </button>
+ </layout_panel>
+<!--
+ <panel
+ height="22"
+ layout="topleft"
+ auto_resize="false"
+ min_width="3"
+ width="3">
+ <icon
+ height="22"
+ image_name="media_panel_divider.png"
+ layout="topleft"
+ top="0"
+ min_width="3"
+ width="3" />
+ </panel>
+-->
+ <layout_panel
+ name="close"
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ min_width="21"
+ width="21" >
+ <button
+ height="22"
+ image_selected="media_btn_done.png"
+ image_unselected="media_btn_done.png"
+ layout="topleft"
+ tool_tip ="Close media control"
+ picture_style="true"
+ top_delta="-4"
+ width="21" >
+ <button.commit_callback
+ function="MediaCtrl.Close" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ width="0"
+ layout="topleft"
+ user_resize="false" />
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 81bc12c33c..4eacd72a7d 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -61,9 +61,7 @@
<string name="TooltipFlagGroupScripts">Group Scripts</string>
<string name="TooltipFlagNoScripts">No Scripts</string>
<string name="TooltipLand">Land:</string>
- <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
- <string name="TooltipAltLeft">Alt+&#8592; for previous tab</string>
- <string name="TooltipAltRight">Alt+&#8594; for next tab</string>
+ <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
<!-- tooltips for Urls -->
<string name="TooltipHttpUrl">Click to view this web page</string>
@@ -264,10 +262,6 @@
<string name="TrackYourCamera">Track your camera</string>
<string name="ControlYourCamera">Control your camera</string>
- <!-- IM -->
- <string name="IM_logging_string">-- Instant message logging enabled --</string>
- <string name="Unnamed">(Unnamed)</string>
-
<!-- Sim Access labels -->
<string name="SIM_ACCESS_PG">PG</string>
<string name="SIM_ACCESS_MATURE">Mature</string>
@@ -2022,15 +2016,14 @@ this texture in your inventory
<string name="IMTeen">teen</string>
<!-- floater region info -->
+ <!-- The following will replace variable [ALL_ESTATES] in notifications EstateAllowed*, EstateBanned*, EstateManager* -->
<string name="RegionInfoError">error</string>
<string name="RegionInfoAllEstatesOwnedBy">
- all estates
-owned by [OWNER]
+ all estates owned by [OWNER]
</string>
- <string name="RegionInfoAllEstatesYouOwn">all estates you owned</string>
+ <string name="RegionInfoAllEstatesYouOwn">all estates that you own</string>
<string name="RegionInfoAllEstatesYouManage">
- all estates that
-you managed for [OWNER]
+ all estates that you manage for [OWNER]
</string>
<string name="RegionInfoAllowedResidents">Allowed residents: ([ALLOWEDAGENTS], max [MAXACCESS])</string>
<string name="RegionInfoAllowedGroups">Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS])</string>
@@ -2884,7 +2877,14 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
Failed to start viewer
</string>
- <!-- IM system messages -->
+ <!-- IM system messages -->
+ <string name="IM_logging_string">-- Instant message logging enabled --</string>
+ <string name="IM_typing_start_string">[NAME] is typing...</string>
+ <string name="Unnamed">(Unnamed)</string>
+ <string name="IM_moderated_chat_label">(Moderated: Voices off by default)</string>
+ <string name="IM_unavailable_text_label">Text chat is not available for this call.</string>
+
+
<string name="ringing-im">
Joining Voice Chat...
</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/chat_history.xml b/indra/newview/skins/default/xui/en/widgets/chat_history.xml
index b72d59524e..ea6997ebd5 100644
--- a/indra/newview/skins/default/xui/en/widgets/chat_history.xml
+++ b/indra/newview/skins/default/xui/en/widgets/chat_history.xml
@@ -4,8 +4,8 @@
message_separator="panel_chat_separator.xml"
left_text_pad="10"
right_text_pad="15"
- left_widget_pad="5"
- rigth_widget_pad="10"
+ left_widget_pad="0"
+ right_widget_pad="10"
max_length="2147483647"
enabled="false"
track_bottom="true"
diff --git a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml
index 89e442baec..ab4ad94089 100644
--- a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml
+++ b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml
@@ -23,7 +23,8 @@
image_selected="DropDown_Selected"
image_disabled="DropDown_Disabled"
image_disabled_selected="DropDown_Disabled_Selected" />
- <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" />
+ <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor"
+ scroll_bar_bg_visible="true" />
<gesture_combo_box.combo_editor name="Combo Text Entry"
select_on_focus="true"
font="SansSerifSmall" />
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 2fe5f517a2..7d10df1af7 100644
--- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml
+++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<tab_container tab_min_width="60"
tab_max_width="150"
+ font_halign="left"
tab_height="16">
<first_tab tab_top_image_unselected="TabTop_Left_Off"
tab_top_image_selected="TabTop_Left_Selected"