aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llimpanel.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:27 -0500
committerJacek Antonelli2008-08-15 23:45:27 -0500
commita8a62201ba762e98dff92cf49033e577fc34d8d4 (patch)
tree11f8513c5cdc222f2fac0c93eb724c089803c200 /linden/indra/newview/llimpanel.cpp
parentSecond Life viewer sources 1.18.6.4-RC (diff)
downloadmeta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.zip
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.gz
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.bz2
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.xz
Second Life viewer sources 1.19.0.0
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llimpanel.cpp530
1 files changed, 399 insertions, 131 deletions
diff --git a/linden/indra/newview/llimpanel.cpp b/linden/indra/newview/llimpanel.cpp
index 2307912..b80b80b 100644
--- a/linden/indra/newview/llimpanel.cpp
+++ b/linden/indra/newview/llimpanel.cpp
@@ -12,12 +12,12 @@
12 * ("GPL"), unless you have obtained a separate licensing agreement 12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of 13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or 14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlife.com/developers/opensource/gplv2 15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 * 16 *
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlife.com/developers/opensource/flossexception 20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 21 *
22 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
@@ -63,6 +63,7 @@
63#include "llviewerstats.h" 63#include "llviewerstats.h"
64#include "llviewercontrol.h" 64#include "llviewercontrol.h"
65#include "llvieweruictrlfactory.h" 65#include "llvieweruictrlfactory.h"
66#include "llviewerwindow.h"
66#include "lllogchat.h" 67#include "lllogchat.h"
67#include "llfloaterhtml.h" 68#include "llfloaterhtml.h"
68#include "llweb.h" 69#include "llweb.h"
@@ -92,10 +93,14 @@ static LLString sSessionStartString = "Starting session with [NAME] please wait.
92LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; 93LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
93LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; 94LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
94LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; 95LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
96LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
95 97
96void session_starter_helper(const LLUUID& temp_session_id, 98BOOL LLVoiceChannel::sSuspended = FALSE;
97 const LLUUID& other_participant_id, 99
98 EInstantMessage im_type) 100void session_starter_helper(
101 const LLUUID& temp_session_id,
102 const LLUUID& other_participant_id,
103 EInstantMessage im_type)
99{ 104{
100 LLMessageSystem *msg = gMessageSystem; 105 LLMessageSystem *msg = gMessageSystem;
101 106
@@ -122,47 +127,111 @@ void session_starter_helper(const LLUUID& temp_session_id,
122 msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); 127 msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
123} 128}
124 129
130void start_deprecated_conference_chat(
131 const LLUUID& temp_session_id,
132 const LLUUID& creator_id,
133 const LLUUID& other_participant_id,
134 const LLSD& agents_to_invite)
135{
136 U8* bucket;
137 U8* pos;
138 S32 count;
139 S32 bucket_size;
140
141 // *FIX: this could suffer from endian issues
142 count = agents_to_invite.size();
143 bucket_size = UUID_BYTES * count;
144 bucket = new U8[bucket_size];
145 pos = bucket;
146
147 for(S32 i = 0; i < count; ++i)
148 {
149 LLUUID agent_id = agents_to_invite[i].asUUID();
150
151 memcpy(pos, &agent_id, UUID_BYTES);
152 pos += UUID_BYTES;
153 }
154
155 session_starter_helper(
156 temp_session_id,
157 other_participant_id,
158 IM_SESSION_CONFERENCE_START);
159
160 gMessageSystem->addBinaryDataFast(
161 _PREHASH_BinaryBucket,
162 bucket,
163 bucket_size);
164
165 gAgent.sendReliableMessage();
166
167 delete[] bucket;
168}
169
170class LLStartConferenceChatResponder : public LLHTTPClient::Responder
171{
172public:
173 LLStartConferenceChatResponder(
174 const LLUUID& temp_session_id,
175 const LLUUID& creator_id,
176 const LLUUID& other_participant_id,
177 const LLSD& agents_to_invite)
178 {
179 mTempSessionID = temp_session_id;
180 mCreatorID = creator_id;
181 mOtherParticipantID = other_participant_id;
182 mAgents = agents_to_invite;
183 }
184
185 virtual void error(U32 statusNum, const std::string& reason)
186 {
187 //try an "old school" way.
188 if ( statusNum == 400 )
189 {
190 start_deprecated_conference_chat(
191 mTempSessionID,
192 mCreatorID,
193 mOtherParticipantID,
194 mAgents);
195 }
196
197 //else throw an error back to the client?
198 //in theory we should have just have these error strings
199 //etc. set up in this file as opposed to the IMMgr,
200 //but the error string were unneeded here previously
201 //and it is not worth the effort switching over all
202 //the possible different language translations
203 }
204
205private:
206 LLUUID mTempSessionID;
207 LLUUID mCreatorID;
208 LLUUID mOtherParticipantID;
209
210 LLSD mAgents;
211};
212
125// Returns true if any messages were sent, false otherwise. 213// Returns true if any messages were sent, false otherwise.
126// Is sort of equivalent to "does the server need to do anything?" 214// Is sort of equivalent to "does the server need to do anything?"
127bool send_start_session_messages(const LLUUID& temp_session_id, 215bool send_start_session_messages(
128 const LLUUID& other_participant_id, 216 const LLUUID& temp_session_id,
129 const LLDynamicArray<LLUUID>& ids, 217 const LLUUID& other_participant_id,
130 EInstantMessage dialog) 218 const LLDynamicArray<LLUUID>& ids,
219 EInstantMessage dialog)
131{ 220{
132 if ( (dialog == IM_SESSION_GROUP_START) || 221 if ( dialog == IM_SESSION_GROUP_START )
133 (dialog == IM_SESSION_CONFERENCE_START) )
134 { 222 {
135 S32 count = ids.size(); 223 session_starter_helper(
136 S32 bucket_size = UUID_BYTES * count; 224 temp_session_id,
137 U8* bucket; 225 other_participant_id,
138 U8* pos; 226 dialog);
139
140 session_starter_helper(temp_session_id,
141 other_participant_id,
142 dialog);
143 227
144 switch(dialog) 228 switch(dialog)
145 { 229 {
146 case IM_SESSION_GROUP_START: 230 case IM_SESSION_GROUP_START:
147 gMessageSystem->addBinaryDataFast(_PREHASH_BinaryBucket, 231 gMessageSystem->addBinaryDataFast(
148 EMPTY_BINARY_BUCKET, 232 _PREHASH_BinaryBucket,
149 EMPTY_BINARY_BUCKET_SIZE); 233 EMPTY_BINARY_BUCKET,
150 break; 234 EMPTY_BINARY_BUCKET_SIZE);
151 case IM_SESSION_CONFERENCE_START:
152 bucket = new U8[bucket_size];
153 pos = bucket;
154
155 // *FIX: this could suffer from endian issues
156 for(S32 i = 0; i < count; ++i)
157 {
158 memcpy(pos, &(ids.get(i)), UUID_BYTES);
159 pos += UUID_BYTES;
160 }
161 gMessageSystem->addBinaryDataFast(_PREHASH_BinaryBucket,
162 bucket,
163 bucket_size);
164 delete[] bucket;
165
166 break; 235 break;
167 default: 236 default:
168 break; 237 break;
@@ -171,6 +240,44 @@ bool send_start_session_messages(const LLUUID& temp_session_id,
171 240
172 return true; 241 return true;
173 } 242 }
243 else if ( dialog == IM_SESSION_CONFERENCE_START )
244 {
245 LLSD agents;
246 for (int i = 0; i < (S32) ids.size(); i++)
247 {
248 agents.append(ids.get(i));
249 }
250
251 //we have a new way of starting conference calls now
252 LLViewerRegion* region = gAgent.getRegion();
253 if (region)
254 {
255 std::string url = region->getCapability(
256 "ChatSessionRequest");
257 LLSD data;
258 data["method"] = "start conference";
259 data["session-id"] = temp_session_id;
260
261 data["params"] = agents;
262
263 LLHTTPClient::post(
264 url,
265 data,
266 new LLStartConferenceChatResponder(
267 temp_session_id,
268 gAgent.getID(),
269 other_participant_id,
270 data["params"]));
271 }
272 else
273 {
274 start_deprecated_conference_chat(
275 temp_session_id,
276 gAgent.getID(),
277 other_participant_id,
278 agents);
279 }
280 }
174 281
175 return false; 282 return false;
176} 283}
@@ -194,8 +301,21 @@ void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
194 << status << ": " << reason << ")" 301 << status << ": " << reason << ")"
195 << llendl; 302 << llendl;
196 LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); 303 LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
197 if (channelp) 304 if ( channelp )
198 { 305 {
306 if ( 403 == status )
307 {
308 //403 == no ability
309 LLNotifyBox::showXml(
310 "VoiceNotAllowed",
311 channelp->getNotifyArgs());
312 }
313 else
314 {
315 LLNotifyBox::showXml(
316 "VoiceCallGenericError",
317 channelp->getNotifyArgs());
318 }
199 channelp->deactivate(); 319 channelp->deactivate();
200 } 320 }
201} 321}
@@ -242,10 +362,6 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const LLString& session
242 362
243LLVoiceChannel::~LLVoiceChannel() 363LLVoiceChannel::~LLVoiceChannel()
244{ 364{
245 // CANNOT do this here, since it will crash on quit in the LLVoiceChannelProximal singleton destructor.
246 // Do it in all other subclass destructors instead.
247 // deactivate();
248
249 // Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. 365 // Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
250 if(gVoiceClient) 366 if(gVoiceClient)
251 { 367 {
@@ -266,7 +382,19 @@ void LLVoiceChannel::setChannelInfo(
266 382
267 if (mState == STATE_NO_CHANNEL_INFO) 383 if (mState == STATE_NO_CHANNEL_INFO)
268 { 384 {
269 if(!mURI.empty() && !mCredentials.empty()) 385 if (mURI.empty())
386 {
387 LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs);
388 llwarns << "Received empty URI for channel " << mSessionName << llendl;
389 deactivate();
390 }
391 else if (mCredentials.empty())
392 {
393 LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs);
394 llwarns << "Received empty credentials for channel " << mSessionName << llendl;
395 deactivate();
396 }
397 else
270 { 398 {
271 setState(STATE_READY); 399 setState(STATE_READY);
272 400
@@ -279,12 +407,6 @@ void LLVoiceChannel::setChannelInfo(
279 activate(); 407 activate();
280 } 408 }
281 } 409 }
282 else
283 {
284 //*TODO: notify user
285 llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
286 deactivate();
287 }
288 } 410 }
289} 411}
290 412
@@ -325,7 +447,7 @@ void LLVoiceChannel::handleStatusChange(EStatusType type)
325 } 447 }
326 break; 448 break;
327 case STATUS_LEFT_CHANNEL: 449 case STATUS_LEFT_CHANNEL:
328 if (callStarted() && !mIgnoreNextSessionLeave) 450 if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
329 { 451 {
330 // if forceably removed from channel 452 // if forceably removed from channel
331 // update the UI and revert to default channel 453 // update the UI and revert to default channel
@@ -496,6 +618,38 @@ void LLVoiceChannel::initClass()
496 sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); 618 sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
497} 619}
498 620
621
622//static
623void LLVoiceChannel::suspend()
624{
625 if (!sSuspended)
626 {
627 sSuspendedVoiceChannel = sCurrentVoiceChannel;
628 sSuspended = TRUE;
629 }
630}
631
632//static
633void LLVoiceChannel::resume()
634{
635 if (sSuspended)
636 {
637 if (gVoiceClient->voiceEnabled())
638 {
639 if (sSuspendedVoiceChannel)
640 {
641 sSuspendedVoiceChannel->activate();
642 }
643 else
644 {
645 LLVoiceChannelProximal::getInstance()->activate();
646 }
647 }
648 sSuspended = FALSE;
649 }
650}
651
652
499// 653//
500// LLVoiceChannelGroup 654// LLVoiceChannelGroup
501// 655//
@@ -507,11 +661,6 @@ LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const LLStrin
507 mIsRetrying = FALSE; 661 mIsRetrying = FALSE;
508} 662}
509 663
510LLVoiceChannelGroup::~LLVoiceChannelGroup()
511{
512 deactivate();
513}
514
515void LLVoiceChannelGroup::deactivate() 664void LLVoiceChannelGroup::deactivate()
516{ 665{
517 if (callStarted()) 666 if (callStarted())
@@ -635,6 +784,7 @@ void LLVoiceChannelGroup::handleError(EStatusType status)
635 } 784 }
636 785
637 break; 786 break;
787
638 case ERROR_UNKNOWN: 788 case ERROR_UNKNOWN:
639 default: 789 default:
640 break; 790 break;
@@ -677,11 +827,6 @@ LLVoiceChannelProximal::LLVoiceChannelProximal() :
677 activate(); 827 activate();
678} 828}
679 829
680LLVoiceChannelProximal::~LLVoiceChannelProximal()
681{
682 // DO NOT call deactivate() here, since this will only happen at atexit() time.
683}
684
685BOOL LLVoiceChannelProximal::isActive() 830BOOL LLVoiceChannelProximal::isActive()
686{ 831{
687 return callStarted() && LLVoiceClient::getInstance()->inProximalChannel(); 832 return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
@@ -725,6 +870,9 @@ void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
725 case STATUS_LEFT_CHANNEL: 870 case STATUS_LEFT_CHANNEL:
726 // do not notify user when leaving proximal channel 871 // do not notify user when leaving proximal channel
727 return; 872 return;
873 case STATUS_VOICE_DISABLED:
874 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
875 return;
728 default: 876 default:
729 break; 877 break;
730 } 878 }
@@ -762,29 +910,26 @@ void LLVoiceChannelProximal::deactivate()
762 } 910 }
763} 911}
764 912
913
765// 914//
766// LLVoiceChannelP2P 915// LLVoiceChannelP2P
767// 916//
768LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const LLString& session_name, const LLUUID& other_user_id) : 917LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const LLString& session_name, const LLUUID& other_user_id) :
769 LLVoiceChannelGroup(session_id, session_name), 918 LLVoiceChannelGroup(session_id, session_name),
770 mOtherUserID(other_user_id) 919 mOtherUserID(other_user_id),
920 mReceivedCall(FALSE)
771{ 921{
772 // make sure URI reflects encoded version of other user's agent id 922 // make sure URI reflects encoded version of other user's agent id
773 setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); 923 setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
774} 924}
775 925
776LLVoiceChannelP2P::~LLVoiceChannelP2P()
777{
778 deactivate();
779}
780
781void LLVoiceChannelP2P::handleStatusChange(EStatusType type) 926void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
782{ 927{
783 // status updates 928 // status updates
784 switch(type) 929 switch(type)
785 { 930 {
786 case STATUS_LEFT_CHANNEL: 931 case STATUS_LEFT_CHANNEL:
787 if (callStarted() && !mIgnoreNextSessionLeave) 932 if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
788 { 933 {
789 if (mState == STATE_RINGING) 934 if (mState == STATE_RINGING)
790 { 935 {
@@ -832,6 +977,7 @@ void LLVoiceChannelP2P::activate()
832 // no session handle yet, we're starting the call 977 // no session handle yet, we're starting the call
833 if (mSessionHandle.empty()) 978 if (mSessionHandle.empty())
834 { 979 {
980 mReceivedCall = FALSE;
835 LLVoiceClient::getInstance()->callUser(mOtherUserID); 981 LLVoiceClient::getInstance()->callUser(mOtherUserID);
836 } 982 }
837 // otherwise answering the call 983 // otherwise answering the call
@@ -879,24 +1025,37 @@ void LLVoiceChannelP2P::setSessionHandle(const LLString& handle)
879 mSessionHandle = handle; 1025 mSessionHandle = handle;
880 // The URI of a p2p session should always be the other end's SIP URI. 1026 // The URI of a p2p session should always be the other end's SIP URI.
881 setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); 1027 setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
882 1028 mReceivedCall = TRUE;
1029
883 if (needs_activate) 1030 if (needs_activate)
884 { 1031 {
885 activate(); 1032 activate();
886 } 1033 }
887} 1034}
888 1035
1036void LLVoiceChannelP2P::setState(EState state)
1037{
1038 // you only "answer" voice invites in p2p mode
1039 // so provide a special purpose message here
1040 if (mReceivedCall && state == STATE_RINGING)
1041 {
1042 gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
1043 mState = state;
1044 return;
1045 }
1046 LLVoiceChannel::setState(state);
1047}
1048
1049
889// 1050//
890// LLFloaterIMPanel 1051// LLFloaterIMPanel
891// 1052//
892LLFloaterIMPanel::LLFloaterIMPanel( 1053LLFloaterIMPanel::LLFloaterIMPanel(
893 const std::string& name,
894 const LLRect& rect,
895 const std::string& session_label, 1054 const std::string& session_label,
896 const LLUUID& session_id, 1055 const LLUUID& session_id,
897 const LLUUID& other_participant_id, 1056 const LLUUID& other_participant_id,
898 EInstantMessage dialog) : 1057 EInstantMessage dialog) :
899 LLFloater(name, rect, session_label), 1058 LLFloater(session_label, LLRect(), session_label),
900 mInputEditor(NULL), 1059 mInputEditor(NULL),
901 mHistoryEditor(NULL), 1060 mHistoryEditor(NULL),
902 mSessionUUID(session_id), 1061 mSessionUUID(session_id),
@@ -909,6 +1068,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(
909 mOtherTyping(FALSE), 1068 mOtherTyping(FALSE),
910 mTypingLineStartIndex(0), 1069 mTypingLineStartIndex(0),
911 mSentTypingState(TRUE), 1070 mSentTypingState(TRUE),
1071 mNumUnreadMessages(0),
912 mShowSpeakersOnConnect(TRUE), 1072 mShowSpeakersOnConnect(TRUE),
913 mAutoConnect(FALSE), 1073 mAutoConnect(FALSE),
914 mSpeakerPanel(NULL), 1074 mSpeakerPanel(NULL),
@@ -919,14 +1079,12 @@ LLFloaterIMPanel::LLFloaterIMPanel(
919} 1079}
920 1080
921LLFloaterIMPanel::LLFloaterIMPanel( 1081LLFloaterIMPanel::LLFloaterIMPanel(
922 const std::string& name,
923 const LLRect& rect,
924 const std::string& session_label, 1082 const std::string& session_label,
925 const LLUUID& session_id, 1083 const LLUUID& session_id,
926 const LLUUID& other_participant_id, 1084 const LLUUID& other_participant_id,
927 const LLDynamicArray<LLUUID>& ids, 1085 const LLDynamicArray<LLUUID>& ids,
928 EInstantMessage dialog) : 1086 EInstantMessage dialog) :
929 LLFloater(name, rect, session_label), 1087 LLFloater(session_label, LLRect(), session_label),
930 mInputEditor(NULL), 1088 mInputEditor(NULL),
931 mHistoryEditor(NULL), 1089 mHistoryEditor(NULL),
932 mSessionUUID(session_id), 1090 mSessionUUID(session_id),
@@ -952,13 +1110,15 @@ LLFloaterIMPanel::LLFloaterIMPanel(
952 1110
953void LLFloaterIMPanel::init(const LLString& session_label) 1111void LLFloaterIMPanel::init(const LLString& session_label)
954{ 1112{
1113 mSessionLabel = session_label;
1114
955 LLString xml_filename; 1115 LLString xml_filename;
956 switch(mDialog) 1116 switch(mDialog)
957 { 1117 {
958 case IM_SESSION_GROUP_START: 1118 case IM_SESSION_GROUP_START:
959 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); 1119 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
960 xml_filename = "floater_instant_message_group.xml"; 1120 xml_filename = "floater_instant_message_group.xml";
961 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label); 1121 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
962 break; 1122 break;
963 case IM_SESSION_INVITE: 1123 case IM_SESSION_INVITE:
964 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); 1124 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
@@ -970,21 +1130,21 @@ void LLFloaterIMPanel::init(const LLString& session_label)
970 { 1130 {
971 xml_filename = "floater_instant_message_ad_hoc.xml"; 1131 xml_filename = "floater_instant_message_ad_hoc.xml";
972 } 1132 }
973 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label); 1133 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
974 break; 1134 break;
975 case IM_SESSION_P2P_INVITE: 1135 case IM_SESSION_P2P_INVITE:
976 xml_filename = "floater_instant_message.xml"; 1136 xml_filename = "floater_instant_message.xml";
977 mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, session_label, mOtherParticipantUUID); 1137 mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID);
978 break; 1138 break;
979 case IM_SESSION_CONFERENCE_START: 1139 case IM_SESSION_CONFERENCE_START:
980 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); 1140 mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
981 xml_filename = "floater_instant_message_ad_hoc.xml"; 1141 xml_filename = "floater_instant_message_ad_hoc.xml";
982 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label); 1142 mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
983 break; 1143 break;
984 // just received text from another user 1144 // just received text from another user
985 case IM_NOTHING_SPECIAL: 1145 case IM_NOTHING_SPECIAL:
986 xml_filename = "floater_instant_message.xml"; 1146 xml_filename = "floater_instant_message.xml";
987 mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, session_label, mOtherParticipantUUID); 1147 mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID);
988 break; 1148 break;
989 default: 1149 default:
990 llwarns << "Unknown session type" << llendl; 1150 llwarns << "Unknown session type" << llendl;
@@ -999,15 +1159,14 @@ void LLFloaterIMPanel::init(const LLString& session_label)
999 &getFactoryMap(), 1159 &getFactoryMap(),
1000 FALSE); 1160 FALSE);
1001 1161
1002 setLabel(session_label); 1162 setTitle(mSessionLabel);
1003 setTitle(session_label);
1004 mInputEditor->setMaxTextLength(1023); 1163 mInputEditor->setMaxTextLength(1023);
1005 // enable line history support for instant message bar 1164 // enable line history support for instant message bar
1006 mInputEditor->setEnableLineHistory(TRUE); 1165 mInputEditor->setEnableLineHistory(TRUE);
1007 1166
1008 if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) 1167 if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
1009 { 1168 {
1010 LLLogChat::loadHistory(session_label, 1169 LLLogChat::loadHistory(mSessionLabel,
1011 &chatFromLogFile, 1170 &chatFromLogFile,
1012 (void *)this); 1171 (void *)this);
1013 } 1172 }
@@ -1060,16 +1219,12 @@ BOOL LLFloaterIMPanel::postBuild()
1060{ 1219{
1061 requires("chat_editor", WIDGET_TYPE_LINE_EDITOR); 1220 requires("chat_editor", WIDGET_TYPE_LINE_EDITOR);
1062 requires("im_history", WIDGET_TYPE_TEXT_EDITOR); 1221 requires("im_history", WIDGET_TYPE_TEXT_EDITOR);
1063 requires("live_help_dialog", WIDGET_TYPE_TEXT_BOX);
1064 requires("title_string", WIDGET_TYPE_TEXT_BOX);
1065 requires("typing_start_string", WIDGET_TYPE_TEXT_BOX);
1066 requires("session_start_string", WIDGET_TYPE_TEXT_BOX);
1067 1222
1068 if (checkRequirements()) 1223 if (checkRequirements())
1069 { 1224 {
1070 mInputEditor = LLUICtrlFactory::getLineEditorByName(this, "chat_editor"); 1225 mInputEditor = LLUICtrlFactory::getLineEditorByName(this, "chat_editor");
1071 mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived ); 1226 mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this );
1072 mInputEditor->setFocusLostCallback( onInputEditorFocusLost ); 1227 mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this );
1073 mInputEditor->setKeystrokeCallback( onInputEditorKeystroke ); 1228 mInputEditor->setKeystrokeCallback( onInputEditorKeystroke );
1074 mInputEditor->setCommitCallback( onCommitChat ); 1229 mInputEditor->setCommitCallback( onCommitChat );
1075 mInputEditor->setCallbackUserData(this); 1230 mInputEditor->setCallbackUserData(this);
@@ -1084,6 +1239,7 @@ BOOL LLFloaterIMPanel::postBuild()
1084 childSetAction("send_btn", onClickSend, this); 1239 childSetAction("send_btn", onClickSend, this);
1085 childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); 1240 childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this);
1086 1241
1242 childSetAction("moderator_kick_speaker", onKickSpeaker, this);
1087 //LLButton* close_btn = LLUICtrlFactory::getButtonByName(this, "close_btn"); 1243 //LLButton* close_btn = LLUICtrlFactory::getButtonByName(this, "close_btn");
1088 //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this); 1244 //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this);
1089 1245
@@ -1094,17 +1250,11 @@ BOOL LLFloaterIMPanel::postBuild()
1094 { 1250 {
1095 childSetEnabled("profile_btn", FALSE); 1251 childSetEnabled("profile_btn", FALSE);
1096 } 1252 }
1097 LLTextBox* title = LLUICtrlFactory::getTextBoxByName(this, "title_string"); 1253
1098 sTitleString = title->getText(); 1254 sTitleString = getFormattedUIString("title_string");
1099 1255 sTypingStartString = getFormattedUIString("typing_start_string");
1100 LLTextBox* typing_start = LLUICtrlFactory::getTextBoxByName(this, "typing_start_string"); 1256 sSessionStartString = getFormattedUIString("session_start_string");
1101 1257
1102 sTypingStartString = typing_start->getText();
1103
1104 LLTextBox* session_start = LLUICtrlFactory::getTextBoxByName(
1105 this,
1106 "session_start_string");
1107 sSessionStartString = session_start->getText();
1108 if (mSpeakerPanel) 1258 if (mSpeakerPanel)
1109 { 1259 {
1110 mSpeakerPanel->refreshSpeakers(); 1260 mSpeakerPanel->refreshSpeakers();
@@ -1112,7 +1262,7 @@ BOOL LLFloaterIMPanel::postBuild()
1112 1262
1113 if (mDialog == IM_NOTHING_SPECIAL) 1263 if (mDialog == IM_NOTHING_SPECIAL)
1114 { 1264 {
1115 childSetCommitCallback("mute_btn", onClickMuteVoice, this); 1265 childSetAction("mute_btn", onClickMuteVoice, this);
1116 childSetCommitCallback("speaker_volume", onVolumeChange, this); 1266 childSetCommitCallback("speaker_volume", onVolumeChange, this);
1117 } 1267 }
1118 1268
@@ -1131,7 +1281,7 @@ void* LLFloaterIMPanel::createSpeakersPanel(void* data)
1131} 1281}
1132 1282
1133//static 1283//static
1134void LLFloaterIMPanel::onClickMuteVoice(LLUICtrl* source, void* user_data) 1284void LLFloaterIMPanel::onClickMuteVoice(void* user_data)
1135{ 1285{
1136 LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; 1286 LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data;
1137 if (floaterp) 1287 if (floaterp)
@@ -1171,10 +1321,22 @@ void LLFloaterIMPanel::draw()
1171 && LLVoiceClient::voiceEnabled(); 1321 && LLVoiceClient::voiceEnabled();
1172 1322
1173 // hide/show start call and end call buttons 1323 // hide/show start call and end call buttons
1174 childSetVisible("end_call_btn", mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); 1324 childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
1175 childSetVisible("start_call_btn", mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED); 1325 childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
1176 childSetEnabled("start_call_btn", enable_connect); 1326 childSetEnabled("start_call_btn", enable_connect);
1177 childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); 1327 childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty());
1328
1329 LLPointer<LLSpeaker> self_speaker = mSpeakers->findSpeaker(gAgent.getID());
1330 if (self_speaker.notNull() && self_speaker->mModeratorMutedText)
1331 {
1332 mInputEditor->setEnabled(FALSE);
1333 mInputEditor->setLabel(getFormattedUIString("muted_text_label"));
1334 }
1335 else
1336 {
1337 mInputEditor->setEnabled(TRUE);
1338 mInputEditor->setLabel(getFormattedUIString("default_text_label"));
1339 }
1178 1340
1179 if (mAutoConnect && enable_connect) 1341 if (mAutoConnect && enable_connect)
1180 { 1342 {
@@ -1215,11 +1377,11 @@ void LLFloaterIMPanel::draw()
1215 else 1377 else
1216 { 1378 {
1217 // refresh volume and mute checkbox 1379 // refresh volume and mute checkbox
1218 childSetEnabled("speaker_volume", mVoiceChannel->isActive()); 1380 childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
1219 childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID)); 1381 childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID));
1220 1382
1221 childSetValue("mute_btn", gMuteListp->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); 1383 childSetValue("mute_btn", gMuteListp->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat));
1222 childSetEnabled("mute_btn", mVoiceChannel->isActive()); 1384 childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
1223 } 1385 }
1224 LLFloater::draw(); 1386 LLFloater::draw();
1225} 1387}
@@ -1235,7 +1397,6 @@ public:
1235 void error(U32 statusNum, const std::string& reason) 1397 void error(U32 statusNum, const std::string& reason)
1236 { 1398 {
1237 llinfos << "Error inviting all agents to session" << llendl; 1399 llinfos << "Error inviting all agents to session" << llendl;
1238
1239 //throw something back to the viewer here? 1400 //throw something back to the viewer here?
1240 } 1401 }
1241 1402
@@ -1272,8 +1433,8 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
1272 LLHTTPClient::post( 1433 LLHTTPClient::post(
1273 url, 1434 url,
1274 data, 1435 data,
1275 new LLSessionInviteResponder(mSessionUUID)); 1436 new LLSessionInviteResponder(
1276 1437 mSessionUUID));
1277 } 1438 }
1278 else 1439 else
1279 { 1440 {
@@ -1289,6 +1450,15 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
1289 1450
1290void LLFloaterIMPanel::addHistoryLine(const LLUUID& source, const std::string &utf8msg, const LLColor4& color, bool log_to_file) 1451void LLFloaterIMPanel::addHistoryLine(const LLUUID& source, const std::string &utf8msg, const LLColor4& color, bool log_to_file)
1291{ 1452{
1453 // start tab flashing when receiving im for background session from user
1454 LLMultiFloater* hostp = getHost();
1455 if( !isInVisibleChain()
1456 && hostp
1457 && source != gAgent.getID())
1458 {
1459 hostp->setFloaterFlashing(this, TRUE);
1460 }
1461
1292 addHistoryLine(utf8msg, color, log_to_file); 1462 addHistoryLine(utf8msg, color, log_to_file);
1293 mSpeakers->speakerChatted(source); 1463 mSpeakers->speakerChatted(source);
1294 mSpeakers->setSpeakerTyping(source, FALSE); 1464 mSpeakers->setSpeakerTyping(source, FALSE);
@@ -1296,14 +1466,6 @@ void LLFloaterIMPanel::addHistoryLine(const LLUUID& source, const std::string &u
1296 1466
1297void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file) 1467void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file)
1298{ 1468{
1299 LLMultiFloater* hostp = getHost();
1300 if( !getVisible() && hostp && log_to_file)
1301 {
1302 // Only flash for logged ("real") messages
1303 LLTabContainer* parent = (LLTabContainer*) getParent();
1304 parent->setTabPanelFlashing( this, TRUE );
1305 }
1306
1307 // Now we're adding the actual line of text, so erase the 1469 // Now we're adding the actual line of text, so erase the
1308 // "Foo is typing..." text segment, and the optional timestamp 1470 // "Foo is typing..." text segment, and the optional timestamp
1309 // if it was present. JC 1471 // if it was present. JC
@@ -1330,6 +1492,11 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
1330 1492
1331 LLLogChat::saveHistory(getTitle(),histstr); 1493 LLLogChat::saveHistory(getTitle(),histstr);
1332 } 1494 }
1495
1496 if (!isInVisibleChain())
1497 {
1498 mNumUnreadMessages++;
1499 }
1333} 1500}
1334 1501
1335 1502
@@ -1340,10 +1507,7 @@ void LLFloaterIMPanel::setVisible(BOOL b)
1340 LLMultiFloater* hostp = getHost(); 1507 LLMultiFloater* hostp = getHost();
1341 if( b && hostp ) 1508 if( b && hostp )
1342 { 1509 {
1343 LLTabContainer* parent = (LLTabContainer*) getParent(); 1510 hostp->setFloaterFlashing(this, FALSE);
1344
1345 // When this tab is displayed, you can stop flashing.
1346 parent->setTabPanelFlashing( this, FALSE );
1347 1511
1348 /* Don't change containing floater title - leave it "Instant Message" JC 1512 /* Don't change containing floater title - leave it "Instant Message" JC
1349 LLUIString title = sTitleString; 1513 LLUIString title = sTitleString;
@@ -1392,7 +1556,7 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask, BOOL called_from_paren
1392 else if ( KEY_ESCAPE == key ) 1556 else if ( KEY_ESCAPE == key )
1393 { 1557 {
1394 handled = TRUE; 1558 handled = TRUE;
1395 gFocusMgr.setKeyboardFocus(NULL, NULL); 1559 gFocusMgr.setKeyboardFocus(NULL);
1396 1560
1397 // Close talk panel with escape 1561 // Close talk panel with escape
1398 if( !gSavedSettings.getBOOL("PinTalkViewOpen") ) 1562 if( !gSavedSettings.getBOOL("PinTalkViewOpen") )
@@ -1573,14 +1737,14 @@ void LLFloaterIMPanel::onCommitChat(LLUICtrl* caller, void* userdata)
1573} 1737}
1574 1738
1575// static 1739// static
1576void LLFloaterIMPanel::onInputEditorFocusReceived( LLUICtrl* caller, void* userdata ) 1740void LLFloaterIMPanel::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata )
1577{ 1741{
1578 LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; 1742 LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata;
1579 self->mHistoryEditor->setCursorAndScrollToEnd(); 1743 self->mHistoryEditor->setCursorAndScrollToEnd();
1580} 1744}
1581 1745
1582// static 1746// static
1583void LLFloaterIMPanel::onInputEditorFocusLost(LLUICtrl* caller, void* userdata) 1747void LLFloaterIMPanel::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)
1584{ 1748{
1585 LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; 1749 LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
1586 self->setTyping(FALSE); 1750 self->setTyping(FALSE);
@@ -1628,6 +1792,14 @@ void LLFloaterIMPanel::onClose(bool app_quitting)
1628 destroy(); 1792 destroy();
1629} 1793}
1630 1794
1795void LLFloaterIMPanel::onVisibilityChange(BOOL new_visibility)
1796{
1797 if (new_visibility)
1798 {
1799 mNumUnreadMessages = 0;
1800 }
1801}
1802
1631void deliver_message(const std::string& utf8_text, 1803void deliver_message(const std::string& utf8_text,
1632 const LLUUID& im_session_id, 1804 const LLUUID& im_session_id,
1633 const LLUUID& other_participant_id, 1805 const LLUUID& other_participant_id,
@@ -1739,19 +1911,37 @@ void LLFloaterIMPanel::sendMsg()
1739 mSentTypingState = TRUE; 1911 mSentTypingState = TRUE;
1740} 1912}
1741 1913
1742void LLFloaterIMPanel::updateSpeakersList(LLSD speaker_updates) 1914void LLFloaterIMPanel::updateSpeakersList(const LLSD& speaker_updates)
1743{ 1915{
1744 mSpeakers->processSpeakerListUpdate(speaker_updates); 1916 mSpeakers->updateSpeakers(speaker_updates);
1745} 1917}
1746 1918
1747void LLFloaterIMPanel::setSpeakersListFromMap(LLSD speaker_map) 1919void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update)
1748{ 1920{
1749 mSpeakers->processSpeakerMap(speaker_map); 1921 if (
1922 session_update.has("moderated_mode") &&
1923 session_update["moderated_mode"].has("voice") )
1924 {
1925 BOOL voice_moderated = session_update["moderated_mode"]["voice"];
1926
1927 if (voice_moderated)
1928 {
1929 setTitle(mSessionLabel + LLString(" ") + getFormattedUIString("moderated_chat_label"));
1930 }
1931 else
1932 {
1933 setTitle(mSessionLabel);
1934 }
1935
1936
1937 //update the speakers dropdown too
1938 mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated);
1939 }
1750} 1940}
1751 1941
1752void LLFloaterIMPanel::setSpeakersList(LLSD speaker_list) 1942void LLFloaterIMPanel::setSpeakers(const LLSD& speaker_list)
1753{ 1943{
1754 mSpeakers->processSpeakerList(speaker_list); 1944 mSpeakers->setSpeakers(speaker_list);
1755} 1945}
1756 1946
1757void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) 1947void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id)
@@ -1897,5 +2087,83 @@ void LLFloaterIMPanel::chatFromLogFile(LLString line, void* userdata)
1897 2087
1898 //self->addHistoryLine(line, LLColor4::grey, FALSE); 2088 //self->addHistoryLine(line, LLColor4::grey, FALSE);
1899 self->mHistoryEditor->appendColoredText(line, false, true, LLColor4::grey); 2089 self->mHistoryEditor->appendColoredText(line, false, true, LLColor4::grey);
2090}
2091
2092void LLFloaterIMPanel::showSessionStartError(
2093 const std::string& error_string)
2094{
2095 //the error strings etc. should be really be static and local
2096 //to this file instead of in the LLFloaterIM
2097 //but they were in llimview.cpp first and unfortunately
2098 //some translations into non English languages already occurred
2099 //thus making it a tad harder to change over to a
2100 //"correct" solution. The best solution
2101 //would be to store all of the misc. strings into
2102 //their own XML file which would be read in by any LLIMPanel
2103 //post build function instead of repeating the same info
2104 //in the group, adhoc and normal IM xml files.
2105 LLString::format_map_t args;
2106 args["[REASON]"] =
2107 LLFloaterIM::sErrorStringsMap[error_string];
2108 args["[RECIPIENT]"] = getTitle();
2109
2110 gViewerWindow->alertXml(
2111 "ChatterBoxSessionStartError",
2112 args,
2113 onConfirmForceCloseError,
2114 new LLUUID(mSessionUUID));
2115}
2116
2117void LLFloaterIMPanel::showSessionEventError(
2118 const std::string& event_string,
2119 const std::string& error_string)
2120{
2121 LLString::format_map_t args;
2122 args["[REASON]"] =
2123 LLFloaterIM::sErrorStringsMap[error_string];
2124 args["[EVENT]"] =
2125 LLFloaterIM::sEventStringsMap[event_string];
2126 args["[RECIPIENT]"] = getTitle();
2127
2128 gViewerWindow->alertXml(
2129 "ChatterBoxSessionEventError",
2130 args);
2131}
2132
2133void LLFloaterIMPanel::showSessionForceClose(
2134 const std::string& reason_string)
2135{
2136 LLString::format_map_t args;
2137
2138 args["[NAME]"] = getTitle();
2139 args["[REASON]"] = LLFloaterIM::sForceCloseSessionMap[reason_string];
2140
2141 gViewerWindow->alertXml(
2142 "ForceCloseChatterBoxSession",
2143 args,
2144 LLFloaterIMPanel::onConfirmForceCloseError,
2145 this);
1900 2146
1901} 2147}
2148
2149//static
2150void LLFloaterIMPanel::onKickSpeaker(void* user_data)
2151{
2152
2153}
2154
2155void LLFloaterIMPanel::onConfirmForceCloseError(S32 option, void* data)
2156{
2157 //only 1 option really
2158 LLUUID session_id = *((LLUUID*) data);
2159
2160 if ( gIMMgr )
2161 {
2162 LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(
2163 session_id);
2164
2165 if ( floaterp ) floaterp->close(FALSE);
2166 }
2167}
2168
2169