summaryrefslogtreecommitdiff
path: root/indra/newview/llimpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llimpanel.cpp')
-rw-r--r--indra/newview/llimpanel.cpp979
1 files changed, 489 insertions, 490 deletions
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 0586409283..9cf3e57e22 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -35,6 +35,7 @@
#include "llimpanel.h"
#include "indra_constants.h"
+#include "llfloaterreg.h"
#include "llfocusmgr.h"
#include "llfontgl.h"
#include "llrect.h"
@@ -45,22 +46,29 @@
#include "llagent.h"
#include "llbutton.h"
+#include "llbottomtray.h"
#include "llcallingcard.h"
#include "llchat.h"
+#include "llchiclet.h"
#include "llconsole.h"
+#include "llgroupactions.h"
#include "llfloater.h"
-#include "llfloatergroupinfo.h"
+#include "llfloatercall.h"
+#include "llavataractions.h"
#include "llimview.h"
#include "llinventory.h"
#include "llinventorymodel.h"
-#include "llinventoryview.h"
-#include "llfloateractivespeakers.h"
-#include "llfloateravatarinfo.h"
+#include "llfloaterinventory.h"
#include "llfloaterchat.h"
+#include "lliconctrl.h"
+#include "llimview.h" // for LLIMModel to get other avatar id in chat
#include "llkeyboard.h"
#include "lllineeditor.h"
#include "llnotify.h"
+#include "llpanelimcontrolpanel.h"
+#include "llrecentpeople.h"
#include "llresmgr.h"
+#include "lltrans.h"
#include "lltabcontainer.h"
#include "llviewertexteditor.h"
#include "llviewermessage.h"
@@ -69,7 +77,6 @@
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
#include "lllogchat.h"
-#include "llfloaterhtml.h"
#include "llweb.h"
#include "llhttpclient.h"
#include "llmutelist.h"
@@ -98,190 +105,7 @@ LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
BOOL LLVoiceChannel::sSuspended = FALSE;
-void session_starter_helper(
- const LLUUID& temp_session_id,
- const LLUUID& other_participant_id,
- EInstantMessage im_type)
-{
- LLMessageSystem *msg = gMessageSystem;
-
- msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- msg->nextBlockFast(_PREHASH_MessageBlock);
- msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
- msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id);
- msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
- msg->addU8Fast(_PREHASH_Dialog, im_type);
- msg->addUUIDFast(_PREHASH_ID, temp_session_id);
- msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
-
- std::string name;
- gAgent.buildFullname(name);
-
- msg->addStringFast(_PREHASH_FromAgentName, name);
- msg->addStringFast(_PREHASH_Message, LLStringUtil::null);
- msg->addU32Fast(_PREHASH_ParentEstateID, 0);
- msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
- msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
-}
-
-void start_deprecated_conference_chat(
- const LLUUID& temp_session_id,
- const LLUUID& creator_id,
- const LLUUID& other_participant_id,
- const LLSD& agents_to_invite)
-{
- U8* bucket;
- U8* pos;
- S32 count;
- S32 bucket_size;
-
- // *FIX: this could suffer from endian issues
- count = agents_to_invite.size();
- bucket_size = UUID_BYTES * count;
- bucket = new U8[bucket_size];
- pos = bucket;
-
- for(S32 i = 0; i < count; ++i)
- {
- LLUUID agent_id = agents_to_invite[i].asUUID();
-
- memcpy(pos, &agent_id, UUID_BYTES);
- pos += UUID_BYTES;
- }
-
- session_starter_helper(
- temp_session_id,
- other_participant_id,
- IM_SESSION_CONFERENCE_START);
-
- gMessageSystem->addBinaryDataFast(
- _PREHASH_BinaryBucket,
- bucket,
- bucket_size);
-
- gAgent.sendReliableMessage();
-
- delete[] bucket;
-}
-
-class LLStartConferenceChatResponder : public LLHTTPClient::Responder
-{
-public:
- LLStartConferenceChatResponder(
- const LLUUID& temp_session_id,
- const LLUUID& creator_id,
- const LLUUID& other_participant_id,
- const LLSD& agents_to_invite)
- {
- mTempSessionID = temp_session_id;
- mCreatorID = creator_id;
- mOtherParticipantID = other_participant_id;
- mAgents = agents_to_invite;
- }
-
- virtual void error(U32 statusNum, const std::string& reason)
- {
- //try an "old school" way.
- if ( statusNum == 400 )
- {
- start_deprecated_conference_chat(
- mTempSessionID,
- mCreatorID,
- mOtherParticipantID,
- mAgents);
- }
-
- //else throw an error back to the client?
- //in theory we should have just have these error strings
- //etc. set up in this file as opposed to the IMMgr,
- //but the error string were unneeded here previously
- //and it is not worth the effort switching over all
- //the possible different language translations
- }
-
-private:
- LLUUID mTempSessionID;
- LLUUID mCreatorID;
- LLUUID mOtherParticipantID;
-
- LLSD mAgents;
-};
-
-// Returns true if any messages were sent, false otherwise.
-// Is sort of equivalent to "does the server need to do anything?"
-bool send_start_session_messages(
- const LLUUID& temp_session_id,
- const LLUUID& other_participant_id,
- const LLDynamicArray<LLUUID>& ids,
- EInstantMessage dialog)
-{
- if ( dialog == IM_SESSION_GROUP_START )
- {
- session_starter_helper(
- temp_session_id,
- other_participant_id,
- dialog);
-
- switch(dialog)
- {
- case IM_SESSION_GROUP_START:
- gMessageSystem->addBinaryDataFast(
- _PREHASH_BinaryBucket,
- EMPTY_BINARY_BUCKET,
- EMPTY_BINARY_BUCKET_SIZE);
- break;
- default:
- break;
- }
- gAgent.sendReliableMessage();
-
- return true;
- }
- else if ( dialog == IM_SESSION_CONFERENCE_START )
- {
- LLSD agents;
- for (int i = 0; i < (S32) ids.size(); i++)
- {
- agents.append(ids.get(i));
- }
- //we have a new way of starting conference calls now
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- std::string url = region->getCapability(
- "ChatSessionRequest");
- LLSD data;
- data["method"] = "start conference";
- data["session-id"] = temp_session_id;
-
- data["params"] = agents;
-
- LLHTTPClient::post(
- url,
- data,
- new LLStartConferenceChatResponder(
- temp_session_id,
- gAgent.getID(),
- other_participant_id,
- data["params"]));
- }
- else
- {
- start_deprecated_conference_chat(
- temp_session_id,
- gAgent.getID(),
- other_participant_id,
- agents);
- }
- }
-
- return false;
-}
class LLVoiceCallCapResponder : public LLHTTPClient::Responder
{
@@ -587,7 +411,6 @@ LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
}
}
-
void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
{
sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
@@ -622,6 +445,21 @@ void LLVoiceChannel::setState(EState state)
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()
@@ -693,6 +531,15 @@ void LLVoiceChannelGroup::activate()
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
}
}
@@ -814,6 +661,9 @@ void LLVoiceChannelGroup::handleError(EStatusType status)
void LLVoiceChannelGroup::setState(EState state)
{
+ // HACK: Open/close the call window if needed.
+ toggleCallWindowIfNeeded(state);
+
switch(state)
{
case STATE_RINGING:
@@ -999,6 +849,9 @@ void LLVoiceChannelP2P::activate()
// 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);
}
}
@@ -1056,6 +909,9 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
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)
@@ -1071,57 +927,28 @@ void LLVoiceChannelP2P::setState(EState state)
//
// LLFloaterIMPanel
//
-LLFloaterIMPanel::LLFloaterIMPanel(
- const std::string& session_label,
- const LLUUID& session_id,
- const LLUUID& other_participant_id,
- EInstantMessage dialog) :
- LLFloater(session_label, LLRect(), session_label),
- mInputEditor(NULL),
- mHistoryEditor(NULL),
- mSessionUUID(session_id),
- mVoiceChannel(NULL),
- mSessionInitialized(FALSE),
- mSessionStartMsgPos(0),
- mOtherParticipantUUID(other_participant_id),
- mDialog(dialog),
- mTyping(FALSE),
- mOtherTyping(FALSE),
- mTypingLineStartIndex(0),
- mSentTypingState(TRUE),
- mNumUnreadMessages(0),
- mShowSpeakersOnConnect(TRUE),
- mAutoConnect(FALSE),
- mTextIMPossible(TRUE),
- mProfileButtonEnabled(TRUE),
- mCallBackEnabled(TRUE),
- mSpeakers(NULL),
- mSpeakerPanel(NULL),
- mFirstKeystrokeTimer(),
- mLastKeystrokeTimer()
-{
- init(session_label);
-}
-LLFloaterIMPanel::LLFloaterIMPanel(
- const std::string& session_label,
- const LLUUID& session_id,
- const LLUUID& other_participant_id,
- const LLDynamicArray<LLUUID>& ids,
- EInstantMessage dialog) :
- LLFloater(session_label, LLRect(), session_label),
+LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label,
+ const LLUUID& session_id,
+ const LLUUID& other_participant_id,
+ const std::vector<LLUUID>& ids,
+ EInstantMessage dialog)
+: LLFloater(session_id),
mInputEditor(NULL),
mHistoryEditor(NULL),
mSessionUUID(session_id),
+ mSessionLabel(session_label),
mVoiceChannel(NULL),
mSessionInitialized(FALSE),
mSessionStartMsgPos(0),
mOtherParticipantUUID(other_participant_id),
mDialog(dialog),
+ mSessionInitialTargetIDs(ids),
mTyping(FALSE),
mOtherTyping(FALSE),
mTypingLineStartIndex(0),
mSentTypingState(TRUE),
+ mNumUnreadMessages(0),
mShowSpeakersOnConnect(TRUE),
mAutoConnect(FALSE),
mTextIMPossible(TRUE),
@@ -1132,15 +959,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(
mFirstKeystrokeTimer(),
mLastKeystrokeTimer()
{
- mSessionInitialTargetIDs = ids;
- init(session_label);
-}
-
-
-void LLFloaterIMPanel::init(const std::string& session_label)
-{
- mSessionLabel = session_label;
-
std::string xml_filename;
switch(mDialog)
{
@@ -1188,11 +1006,10 @@ void LLFloaterIMPanel::init(const std::string& session_label)
}
mSpeakers = new LLIMSpeakerMgr(mVoiceChannel);
+ // All participants will be added to the list of people we've recently interacted with.
+ mSpeakers->addListener(&LLRecentPeople::instance(), "add");
- LLUICtrlFactory::getInstance()->buildFloater(this,
- xml_filename,
- &getFactoryMap(),
- FALSE);
+ LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL);
setTitle(mSessionLabel);
mInputEditor->setMaxTextLength(1023);
@@ -1208,7 +1025,7 @@ void LLFloaterIMPanel::init(const std::string& session_label)
if ( !mSessionInitialized )
{
- if ( !send_start_session_messages(
+ if ( !LLIMModel::instance().sendStartSession(
mSessionUUID,
mOtherParticipantUUID,
mSessionInitialTargetIDs,
@@ -1230,7 +1047,7 @@ void LLFloaterIMPanel::init(const std::string& session_label)
addHistoryLine(
session_start,
- gSavedSettings.getColor4("SystemChatColor"),
+ LLUIColorTable::instance().getColor("SystemChatColor"),
false);
}
}
@@ -1275,67 +1092,62 @@ LLFloaterIMPanel::~LLFloaterIMPanel()
BOOL LLFloaterIMPanel::postBuild()
{
- requires<LLLineEditor>("chat_editor");
- requires<LLTextEditor>("im_history");
-
- if (checkRequirements())
- {
- mInputEditor = getChild<LLLineEditor>("chat_editor");
- mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this );
- mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this );
- mInputEditor->setKeystrokeCallback( onInputEditorKeystroke );
- mInputEditor->setCommitCallback( onCommitChat );
- mInputEditor->setCallbackUserData(this);
- mInputEditor->setCommitOnFocusLost( FALSE );
- mInputEditor->setRevertOnEsc( FALSE );
- mInputEditor->setReplaceNewlinesWithSpaces( FALSE );
+ mCloseSignal.connect(boost::bind(&LLFloaterIMPanel::onClose, this));
+
+ mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2));
+
+ mInputEditor = getChild<LLLineEditor>("chat_editor");
+ mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this );
+ mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this );
+ mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this );
+ mInputEditor->setCommitCallback( onCommitChat, this );
+ mInputEditor->setCommitOnFocusLost( FALSE );
+ mInputEditor->setRevertOnEsc( FALSE );
+ mInputEditor->setReplaceNewlinesWithSpaces( FALSE );
- childSetAction("profile_callee_btn", onClickProfile, this);
- childSetAction("group_info_btn", onClickGroupInfo, this);
+ childSetAction("profile_callee_btn", onClickProfile, this);
+ childSetAction("group_info_btn", onClickGroupInfo, this);
- childSetAction("start_call_btn", onClickStartCall, this);
- childSetAction("end_call_btn", onClickEndCall, this);
- childSetAction("send_btn", onClickSend, this);
- childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this);
+ childSetAction("start_call_btn", onClickStartCall, this);
+ childSetAction("end_call_btn", onClickEndCall, this);
+ childSetAction("send_btn", onClickSend, this);
+ childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this);
- childSetAction("moderator_kick_speaker", onKickSpeaker, this);
- //LLButton* close_btn = getChild<LLButton>("close_btn");
- //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this);
+ childSetAction("moderator_kick_speaker", onKickSpeaker, this);
+ //LLButton* close_btn = getChild<LLButton>("close_btn");
+ //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this);
- mHistoryEditor = getChild<LLViewerTextEditor>("im_history");
- mHistoryEditor->setParseHTML(TRUE);
- mHistoryEditor->setParseHighlights(TRUE);
+ mHistoryEditor = getChild<LLViewerTextEditor>("im_history");
+ mHistoryEditor->setParseHTML(TRUE);
+ mHistoryEditor->setParseHighlights(TRUE);
- if ( IM_SESSION_GROUP_START == mDialog )
- {
- childSetEnabled("profile_btn", FALSE);
- }
-
- if(!mProfileButtonEnabled)
- {
- childSetEnabled("profile_callee_btn", FALSE);
- }
-
- sTitleString = getString("title_string");
- sTypingStartString = getString("typing_start_string");
- sSessionStartString = getString("session_start_string");
+ if ( IM_SESSION_GROUP_START == mDialog )
+ {
+ childSetEnabled("profile_btn", FALSE);
+ }
+
+ if(!mProfileButtonEnabled)
+ {
+ childSetEnabled("profile_callee_btn", FALSE);
+ }
- if (mSpeakerPanel)
- {
- mSpeakerPanel->refreshSpeakers();
- }
+ sTitleString = getString("title_string");
+ sTypingStartString = getString("typing_start_string");
+ sSessionStartString = getString("session_start_string");
- if (mDialog == IM_NOTHING_SPECIAL)
- {
- childSetAction("mute_btn", onClickMuteVoice, this);
- childSetCommitCallback("speaker_volume", onVolumeChange, this);
- }
+ if (mSpeakerPanel)
+ {
+ mSpeakerPanel->refreshSpeakers();
+ }
- setDefaultBtn("send_btn");
- return TRUE;
+ if (mDialog == IM_NOTHING_SPECIAL)
+ {
+ childSetAction("mute_btn", onClickMuteVoice, this);
+ childSetCommitCallback("speaker_volume", onVolumeChange, this);
}
- return FALSE;
+ setDefaultBtn("send_btn");
+ return TRUE;
}
void* LLFloaterIMPanel::createSpeakersPanel(void* data)
@@ -1479,7 +1291,7 @@ private:
LLUUID mSessionID;
};
-BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
+BOOL LLFloaterIMPanel::inviteToSession(const std::vector<LLUUID>& ids)
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
@@ -1487,7 +1299,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
return FALSE;
}
- S32 count = ids.count();
+ S32 count = ids.size();
if( isInviteAllowed() && (count > 0) )
{
@@ -1500,7 +1312,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
data["params"] = LLSD::emptyArray();
for (int i = 0; i < count; i++)
{
- data["params"].append(ids.get(i));
+ data["params"].append(ids[i]);
}
data["method"] = "invite";
@@ -1551,34 +1363,41 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
prepend_newline = false;
}
+ std::string separator_string(": ");
+
// 'name' is a sender name that we want to hotlink so that clicking on it opens a profile.
if (!name.empty()) // If name exists, then add it to the front of the message.
{
// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
if (name == SYSTEM_FROM)
{
- mHistoryEditor->appendColoredText(name,false,prepend_newline,color);
+ mHistoryEditor->appendColoredText(name + separator_string, false, prepend_newline, color);
}
else
{
// Convert the name to a hotlink and add to message.
- const LLStyleSP &source_style = LLStyleMap::instance().lookupAgent(source);
- mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style);
+ mHistoryEditor->appendStyledText(name + separator_string, false, prepend_newline, LLStyleMap::instance().lookupAgent(source));
}
prepend_newline = false;
}
mHistoryEditor->appendColoredText(utf8msg, false, prepend_newline, color);
-
- if (log_to_file
- && gSavedPerAccountSettings.getBOOL("LogInstantMessages") )
+ S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions");
+ if (log_to_file && (im_log_option!=LOG_CHAT))
{
std::string histstr;
- if (gSavedPerAccountSettings.getBOOL("IMLogTimestamp"))
- histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + name + utf8msg;
+ if (gSavedPerAccountSettings.getBOOL("LogTimestamp"))
+ histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + name + separator_string + utf8msg;
else
- histstr = name + utf8msg;
+ histstr = name + separator_string + utf8msg;
- LLLogChat::saveHistory(getTitle(),histstr);
+ if(im_log_option==LOG_BOTH_TOGETHER)
+ {
+ LLLogChat::saveHistory(std::string("chat"),histstr);
+ }
+ else
+ {
+ LLLogChat::saveHistory(getTitle(),histstr);
+ }
}
if (!isInVisibleChain())
@@ -1594,24 +1413,6 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
}
-void LLFloaterIMPanel::setVisible(BOOL b)
-{
- LLPanel::setVisible(b);
-
- LLMultiFloater* hostp = getHost();
- if( b && hostp )
- {
- hostp->setFloaterFlashing(this, FALSE);
-
- /* Don't change containing floater title - leave it "Instant Message" JC
- LLUIString title = sTitleString;
- title.setArg("[NAME]", mSessionLabel);
- hostp->setTitle( title );
- */
- }
-}
-
-
void LLFloaterIMPanel::setInputFocus( BOOL b )
{
mInputEditor->setFocus( b );
@@ -1629,7 +1430,6 @@ void LLFloaterIMPanel::selectNone()
mInputEditor->deselect();
}
-
BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask )
{
BOOL handled = FALSE;
@@ -1637,24 +1437,11 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask )
{
sendMsg();
handled = TRUE;
-
- // Close talk panels on hitting return
- // but not shift-return or control-return
- if ( !gSavedSettings.getBOOL("PinTalkViewOpen") && !(mask & MASK_CONTROL) && !(mask & MASK_SHIFT) )
- {
- gIMMgr->toggle(NULL);
- }
}
else if ( KEY_ESCAPE == key )
{
handled = TRUE;
gFocusMgr.setKeyboardFocus(NULL);
-
- // Close talk panel with escape
- if( !gSavedSettings.getBOOL("PinTalkViewOpen") )
- {
- gIMMgr->toggle(NULL);
- }
}
// May need to call base class LLPanel::handleKeyHere if not handled
@@ -1705,8 +1492,8 @@ BOOL LLFloaterIMPanel::dropCallingCard(LLInventoryItem* item, BOOL drop)
{
if(drop)
{
- LLDynamicArray<LLUUID> ids;
- ids.put(item->getCreatorUUID());
+ std::vector<LLUUID> ids;
+ ids.push_back(item->getCreatorUUID());
inviteToSession(ids);
}
}
@@ -1738,10 +1525,11 @@ BOOL LLFloaterIMPanel::dropCategory(LLInventoryCategory* category, BOOL drop)
}
else if(drop)
{
- LLDynamicArray<LLUUID> ids;
+ std::vector<LLUUID> ids;
+ ids.reserve(count);
for(S32 i = 0; i < count; ++i)
{
- ids.put(items.get(i)->getCreatorUUID());
+ ids.push_back(items.get(i)->getCreatorUUID());
}
inviteToSession(ids);
}
@@ -1771,9 +1559,9 @@ void LLFloaterIMPanel::onClickProfile( void* userdata )
// Bring up the Profile window
LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
- if (self->mOtherParticipantUUID.notNull())
+ if (self->getOtherParticipantID().notNull())
{
- LLFloaterAvatarInfo::showFromDirectory(self->getOtherParticipantID());
+ LLAvatarActions::showProfile(self->getOtherParticipantID());
}
}
@@ -1783,7 +1571,8 @@ void LLFloaterIMPanel::onClickGroupInfo( void* userdata )
// Bring up the Profile window
LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
- LLFloaterGroupInfo::showFromUUID(self->mSessionUUID);
+ LLGroupActions::show(self->mSessionUUID);
+
}
// static
@@ -1792,7 +1581,7 @@ void LLFloaterIMPanel::onClickClose( void* userdata )
LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
if(self)
{
- self->close();
+ self->closeFloater();
}
}
@@ -1864,108 +1653,29 @@ void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller, void* userda
}
}
-void LLFloaterIMPanel::onClose(bool app_quitting)
+void LLFloaterIMPanel::onClose()
{
setTyping(FALSE);
- if(mSessionUUID.notNull())
- {
- std::string name;
- gAgent.buildFullname(name);
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- mOtherParticipantUUID,
- name,
- LLStringUtil::null,
- IM_ONLINE,
- IM_SESSION_LEAVE,
- mSessionUUID);
- gAgent.sendReliableMessage();
- }
+ LLIMModel::instance().sendLeaveSession(mSessionUUID, mOtherParticipantUUID);
+
gIMMgr->removeSession(mSessionUUID);
- destroy();
+ // *HACK hide the voice floater
+ LLFloaterReg::hideInstance("voice_call", mSessionUUID);
}
-void LLFloaterIMPanel::onVisibilityChange(BOOL new_visibility)
+void LLFloaterIMPanel::onVisibilityChange(const LLSD& new_visibility)
{
- if (new_visibility)
+ if (new_visibility.asBoolean())
{
mNumUnreadMessages = 0;
}
-}
-
-void deliver_message(const std::string& utf8_text,
- const LLUUID& im_session_id,
- const LLUUID& other_participant_id,
- EInstantMessage dialog)
-{
- std::string name;
- bool sent = false;
- gAgent.buildFullname(name);
-
- const LLRelationship* info = NULL;
- info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
-
- U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
-
- if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
- {
- // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice.
- sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);
- }
- if(!sent)
- {
- // Send message normally.
-
- // default to IM_SESSION_SEND unless it's nothing special - in
- // which case it's probably an IM to everyone.
- U8 new_dialog = dialog;
-
- if ( dialog != IM_NOTHING_SPECIAL )
- {
- new_dialog = IM_SESSION_SEND;
- }
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- other_participant_id,
- name.c_str(),
- utf8_text.c_str(),
- offline,
- (EInstantMessage)new_dialog,
- im_session_id);
- gAgent.sendReliableMessage();
- }
-
- // If there is a mute list and this is not a group chat...
- if ( LLMuteList::getInstance() )
- {
- // ... the target should not be in our mute list for some message types.
- // Auto-remove them if present.
- switch( dialog )
- {
- case IM_NOTHING_SPECIAL:
- case IM_GROUP_INVITATION:
- case IM_INVENTORY_OFFERED:
- case IM_SESSION_INVITE:
- case IM_SESSION_P2P_INVITE:
- case IM_SESSION_CONFERENCE_START:
- case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing.
- case IM_LURE_USER:
- case IM_GODLIKE_LURE_USER:
- case IM_FRIENDSHIP_OFFERED:
- LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM);
- break;
- default: ; // do nothing
- }
- }
+ if (new_visibility.asBoolean() && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED)
+ LLFloaterReg::showInstance("voice_call", mSessionUUID);
+ else
+ LLFloaterReg::hideInstance("voice_call", mSessionUUID);
}
void LLFloaterIMPanel::sendMsg()
@@ -1989,40 +1699,11 @@ void LLFloaterIMPanel::sendMsg()
if ( mSessionInitialized )
{
- deliver_message(utf8_text,
+ LLIMModel::sendMessage(utf8_text,
mSessionUUID,
mOtherParticipantUUID,
mDialog);
- // local echo
- if((mDialog == IM_NOTHING_SPECIAL) &&
- (mOtherParticipantUUID.notNull()))
- {
- std::string history_echo;
- gAgent.buildFullname(history_echo);
-
- // Look for IRC-style emotes here.
- std::string prefix = utf8_text.substr(0, 4);
- if (prefix == "/me " || prefix == "/me'")
- {
- utf8_text.replace(0,3,"");
- }
- else
- {
- history_echo += ": ";
- }
- history_echo += utf8_text;
-
- BOOL other_was_typing = mOtherTyping;
-
- addHistoryLine(history_echo, gSavedSettings.getColor("IMChatColor"), true, gAgent.getID());
-
- if (other_was_typing)
- {
- addTypingIndicator(mOtherTypingName);
- }
-
- }
}
else
{
@@ -2095,7 +1776,7 @@ void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id)
iter != mQueuedMsgsForInit.endArray();
++iter)
{
- deliver_message(
+ LLIMModel::sendMessage(
iter->asString(),
mSessionUUID,
mOtherParticipantUUID,
@@ -2146,23 +1827,10 @@ void LLFloaterIMPanel::sendTypingState(BOOL typing)
// much network traffic. Only send in person-to-person IMs.
if (mDialog != IM_NOTHING_SPECIAL) return;
- std::string name;
- gAgent.buildFullname(name);
-
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- mOtherParticipantUUID,
- name,
- std::string("typing"),
- IM_ONLINE,
- (typing ? IM_TYPING_START : IM_TYPING_STOP),
- mSessionUUID);
- gAgent.sendReliableMessage();
+ LLIMModel::instance().sendTypingState(mSessionUUID, mOtherParticipantUUID, typing);
}
+
void LLFloaterIMPanel::processIMTyping(const LLIMInfo* im_info, BOOL typing)
{
if (typing)
@@ -2186,7 +1854,7 @@ void LLFloaterIMPanel::addTypingIndicator(const std::string &name)
mTypingLineStartIndex = mHistoryEditor->getWText().length();
LLUIString typing_start = sTypingStartString;
typing_start.setArg("[NAME]", name);
- addHistoryLine(typing_start, gSavedSettings.getColor4("SystemChatColor"), false);
+ addHistoryLine(typing_start, LLUIColorTable::instance().getColor("SystemChatColor"), false);
mOtherTypingName = name;
mOtherTyping = TRUE;
}
@@ -2217,21 +1885,21 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
{
LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata;
std::string message = line;
-
+ S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions");
switch (type)
{
case LLLogChat::LOG_EMPTY:
// add warning log enabled message
- if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
+ if (im_log_option!=LOG_CHAT)
{
- message = LLFloaterChat::getInstance()->getString("IM_logging_string");
+ message = LLTrans::getString("IM_logging_string");
}
break;
case LLLogChat::LOG_END:
// add log end message
- if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
+ if (im_log_option!=LOG_CHAT)
{
- message = LLFloaterChat::getInstance()->getString("IM_logging_string");
+ message = LLTrans::getString("IM_logging_string");
}
break;
case LLLogChat::LOG_LINE:
@@ -2243,7 +1911,7 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
}
//self->addHistoryLine(line, LLColor4::grey, FALSE);
- self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey);
+ self->mHistoryEditor->appendColoredText(message, false, true, LLUIColorTable::instance().getColor("ChatHistoryTextColor"));
}
void LLFloaterIMPanel::showSessionStartError(
@@ -2325,9 +1993,340 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const
LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(
session_id);
- if ( floaterp ) floaterp->close(FALSE);
+ if ( floaterp ) floaterp->closeFloater(FALSE);
}
return false;
}
+
+
+LLIMFloater::LLIMFloater(const LLUUID& session_id)
+ : LLFloater(session_id),
+ mControlPanel(NULL),
+ mSessionID(session_id),
+ mLastMessageIndex(-1),
+ mLastFromName(),
+ mDialog(IM_NOTHING_SPECIAL),
+ mHistoryEditor(NULL),
+ mInputEditor(NULL),
+ mPositioned(false)
+{
+ LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL);
+ if(session)
+ {
+ mDialog = session->mType;
+ }
+
+ if (mDialog == IM_NOTHING_SPECIAL)
+ {
+ mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this);
+ }
+ else
+ {
+ mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this);
+ }
+// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im_session.xml");
+}
+
+/* static */
+void LLIMFloater::newIMCallback(const LLSD& data){
+
+ if (data["num_unread"].asInteger() > 0)
+ {
+ LLUUID session_id = data["session_id"].asUUID();
+
+ LLIMFloater* floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
+ if (floater == NULL)
+ {
+ llwarns << "new_im_callback for non-existent session_id " << session_id << llendl;
+ return;
+ }
+
+ // update if visible, otherwise will be updated when opened
+ if (floater->getVisible())
+ {
+ floater->updateMessages();
+ }
+ }
+}
+
+void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata )
+{
+ LLIMFloater* self = (LLIMFloater*) userdata;
+ self->sendMsg();
+}
+
+void LLIMFloater::sendMsg()
+{
+ if (!gAgent.isGodlike()
+ && (mDialog == IM_NOTHING_SPECIAL)
+ && mOtherParticipantUUID.isNull())
+ {
+ llinfos << "Cannot send IM to everyone unless you're a god." << llendl;
+ return;
+ }
+
+ if (mInputEditor)
+ {
+ LLWString text = mInputEditor->getConvertedText();
+ if(!text.empty())
+ {
+ // Truncate and convert to UTF8 for transport
+ std::string utf8_text = wstring_to_utf8str(text);
+ utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1);
+
+ LLIMModel::sendMessage(utf8_text,
+ mSessionID,
+ mOtherParticipantUUID,
+ mDialog);
+
+ mInputEditor->setText(LLStringUtil::null);
+
+ updateMessages();
+ }
+ }
+}
+
+
+
+LLIMFloater::~LLIMFloater()
+{
+}
+
+//virtual
+BOOL LLIMFloater::postBuild()
+{
+ LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL);
+ if(session)
+ {
+ mOtherParticipantUUID = session->mOtherParticipantID;
+ mControlPanel->setID(session->mOtherParticipantID);
+ }
+
+ LLButton* slide_left = getChild<LLButton>("slide_left_btn");
+ slide_left->setVisible(mControlPanel->getVisible());
+ slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this));
+
+ LLButton* slide_right = getChild<LLButton>("slide_right_btn");
+ slide_right->setVisible(!mControlPanel->getVisible());
+ slide_right->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this));
+
+ mInputEditor = getChild<LLLineEditor>("chat_editor");
+ mInputEditor->setMaxTextLength(1023);
+ // enable line history support for instant message bar
+ mInputEditor->setEnableLineHistory(TRUE);
+
+ mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this );
+ mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this );
+ mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this );
+ mInputEditor->setCommitOnFocusLost( FALSE );
+ mInputEditor->setRevertOnEsc( FALSE );
+ mInputEditor->setReplaceNewlinesWithSpaces( FALSE );
+
+ childSetCommitCallback("chat_editor", onSendMsg, this);
+
+ mHistoryEditor = getChild<LLViewerTextEditor>("im_text");
+
+ setTitle(LLIMModel::instance().getName(mSessionID));
+ setDocked(true);
+
+ mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png");
+
+ return TRUE;
+}
+
+
+
+// static
+void* LLIMFloater::createPanelIMControl(void* userdata)
+{
+ LLIMFloater *self = (LLIMFloater*)userdata;
+ self->mControlPanel = new LLPanelIMControlPanel();
+ self->mControlPanel->setXMLFilename("panel_im_control_panel.xml");
+ return self->mControlPanel;
+}
+
+
+// static
+void* LLIMFloater::createPanelGroupControl(void* userdata)
+{
+ LLIMFloater *self = (LLIMFloater*)userdata;
+ self->mControlPanel = new LLPanelGroupControlPanel();
+ self->mControlPanel->setXMLFilename("panel_group_control_panel.xml");
+ return self->mControlPanel;
+}
+
+
+const U32 UNDOCK_LEAP_HEIGHT = 12;
+const U32 DOCK_ICON_HEIGHT = 6;
+
+//virtual
+void LLIMFloater::onFocusLost()
+{
+ // spec says close if docked to bottom tray and user has clicked away
+ // (hence we are no longer focused)
+ if (isDocked())
+ {
+ LLIMFloater* floater = LLFloaterReg::getTypedInstance<LLIMFloater>("impanel", mSessionID);
+ if (floater)
+ {
+ floater->setVisible(false);
+ }
+ }
+}
+
+
+
+//virtual
+void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
+{
+ LLFloater::setDocked(docked);
+
+ if (!docked && pop_on_undock)
+ {
+ // visually pop up a little bit to emphasize the undocking
+ translate(0, UNDOCK_LEAP_HEIGHT);
+ }
+}
+
+void LLIMFloater::onSlide()
+{
+ LLPanel* im_control_panel = getChild<LLPanel>("panel_im_control_panel");
+ im_control_panel->setVisible(!im_control_panel->getVisible());
+
+ getChild<LLButton>("slide_left_btn")->setVisible(im_control_panel->getVisible());
+ getChild<LLButton>("slide_right_btn")->setVisible(!im_control_panel->getVisible());
+}
+
+//static
+LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
+{
+ //hide all
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
+ iter != inst_list.end(); ++iter)
+ {
+ LLIMFloater* floater = dynamic_cast<LLIMFloater*>(*iter);
+ if (floater && floater->isDocked())
+ {
+ floater->setVisible(false);
+ }
+ }
+
+ LLIMFloater* floater = LLFloaterReg::showTypedInstance<LLIMFloater>("impanel", session_id);
+
+ floater->updateMessages();
+ floater->mInputEditor->setFocus(TRUE);
+ return floater;
+}
+
+//static
+bool LLIMFloater::toggle(const LLUUID& session_id)
+{
+ LLIMFloater* floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
+ if (floater && floater->getVisible())
+ {
+ // clicking on chiclet to close floater just hides it to maintain existing
+ // scroll/text entry state
+ floater->setVisible(false);
+ return false;
+ }
+ else
+ {
+ // ensure the list of messages is updated when floater is made visible
+ show(session_id);
+ // update number of unread notifications in the SysWell
+ LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications();
+ return true;
+ }
+}
+
+void LLIMFloater::updateMessages()
+{
+ std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1);
+
+ if (messages.size())
+ {
+ LLUIColor divider_color = LLUIColorTable::instance().getColor("LtGray_50");
+ LLUIColor chat_color = LLUIColorTable::instance().getColor("IMChatColor");
+
+ std::ostringstream message;
+ std::list<LLSD>::const_reverse_iterator iter = messages.rbegin();
+ std::list<LLSD>::const_reverse_iterator iter_end = messages.rend();
+ for (; iter != iter_end; ++iter)
+ {
+ LLSD msg = *iter;
+
+ const bool prepend_newline = true;
+ std::string from = msg["from"].asString();
+ if (mLastFromName != from)
+ {
+ message << from << " ----- " << msg["time"].asString();
+ mHistoryEditor->appendColoredText(message.str(), false,
+ prepend_newline, divider_color);
+ message.str("");
+ mLastFromName = from;
+ }
+
+ message << msg["message"].asString();
+ mHistoryEditor->appendColoredText(message.str(), false,
+ prepend_newline, chat_color);
+ message.str("");
+
+ mLastMessageIndex = msg["index"].asInteger();
+ }
+
+ mHistoryEditor->setCursorAndScrollToEnd();
+ }
+}
+
+// static
+void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata )
+{
+ LLIMFloater* self= (LLIMFloater*) userdata;
+ self->mHistoryEditor->setCursorAndScrollToEnd();
+}
+
+// static
+void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)
+{
+ LLIMFloater* self = (LLIMFloater*) userdata;
+ self->setTyping(FALSE);
+}
+
+// static
+void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata)
+{
+ LLIMFloater* self = (LLIMFloater*)userdata;
+ std::string text = self->mInputEditor->getText();
+ if (!text.empty())
+ {
+ self->setTyping(TRUE);
+ }
+ else
+ {
+ // Deleting all text counts as stopping typing.
+ self->setTyping(FALSE);
+ }
+}
+
+
+//just a stub for now
+void LLIMFloater::setTyping(BOOL typing)
+{
+}
+void LLIMFloater::draw()
+{
+ //if we are docked, make sure we've been positioned by the chiclet
+ if (!isDocked() || mPositioned)
+ {
+ LLFloater::draw();
+
+ if (isDocked())
+ {
+ mDockTongue->draw( (getRect().getWidth()/2) - mDockTongue->getWidth()/2, -mDockTongue->getHeight());
+ }
+ }
+}
+