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.cpp657
1 files changed, 315 insertions, 342 deletions
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 6acd174fc3..4ae188977e 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,26 @@
#include "llagent.h"
#include "llbutton.h"
+#include "llbottomtray.h"
#include "llcallingcard.h"
#include "llchat.h"
+#include "llchiclet.h"
#include "llconsole.h"
#include "llfloater.h"
#include "llfloatercall.h"
#include "llfloatergroupinfo.h"
-#include "llfriendactions.h"
+#include "llavataractions.h"
#include "llimview.h"
#include "llinventory.h"
#include "llinventorymodel.h"
-#include "llinventoryview.h"
-#include "llfloateractivespeakers.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"
@@ -101,190 +106,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 std::vector<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[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
{
@@ -627,13 +449,17 @@ void LLVoiceChannel::setState(EState state)
void LLVoiceChannel::toggleCallWindowIfNeeded(EState state)
{
if (state == STATE_CONNECTED)
- LLFloaterCall::openInstance(mSessionID);
+ {
+ 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)
- LLFloaterCall::closeInstance(mSessionID);
+ {
+ LLFloaterReg::hideInstance("voice_call", mSessionID);
+ }
}
//static
@@ -1184,7 +1010,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label,
// 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, FALSE);
+ LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL);
setTitle(mSessionLabel);
mInputEditor->setMaxTextLength(1023);
@@ -1200,7 +1026,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label,
if ( !mSessionInitialized )
{
- if ( !send_start_session_messages(
+ if ( !LLIMModel::instance().sendStartSession(
mSessionUUID,
mOtherParticipantUUID,
mSessionInitialTargetIDs,
@@ -1222,7 +1048,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label,
addHistoryLine(
session_start,
- gSavedSkinSettings.getColor4("SystemChatColor"),
+ LLUIColorTable::instance().getColor("SystemChatColor"),
false);
}
}
@@ -1267,6 +1093,10 @@ LLFloaterIMPanel::~LLFloaterIMPanel()
BOOL LLFloaterIMPanel::postBuild()
{
+ mCloseSignal.connect(boost::bind(&LLFloaterIMPanel::onClose, this));
+
+ mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2));
+
requires<LLLineEditor>("chat_editor");
requires<LLTextEditor>("im_history");
@@ -1542,34 +1372,42 @@ 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, source_style);
}
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())
@@ -1585,24 +1423,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 );
@@ -1620,7 +1440,6 @@ void LLFloaterIMPanel::selectNone()
mInputEditor->deselect();
}
-
BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask )
{
BOOL handled = FALSE;
@@ -1752,7 +1571,7 @@ void LLFloaterIMPanel::onClickProfile( void* userdata )
if (self->getOtherParticipantID().notNull())
{
- LLFriendActions::showProfile(self->getOtherParticipantID());
+ LLAvatarActions::showProfile(self->getOtherParticipantID());
}
}
@@ -1843,118 +1662,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);
// *HACK hide the voice floater
- LLFloaterCall::toggleInstanceVisibility(FALSE, mSessionUUID);
-
- destroy();
+ 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;
}
-
- LLFloaterCall::toggleInstanceVisibility(
- new_visibility && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED,
- mSessionUUID);
-}
-
-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
- }
- }
-
- // Add the recipient to the recent people list.
- LLRecentPeople::instance().add(other_participant_id);
+ if (new_visibility.asBoolean() && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED)
+ LLFloaterReg::showInstance("voice_call", mSessionUUID);
+ else
+ LLFloaterReg::hideInstance("voice_call", mSessionUUID);
}
void LLFloaterIMPanel::sendMsg()
@@ -1978,7 +1708,7 @@ void LLFloaterIMPanel::sendMsg()
if ( mSessionInitialized )
{
- deliver_message(utf8_text,
+ LLIMModel::sendMessage(utf8_text,
mSessionUUID,
mOtherParticipantUUID,
mDialog);
@@ -2004,7 +1734,7 @@ void LLFloaterIMPanel::sendMsg()
BOOL other_was_typing = mOtherTyping;
- addHistoryLine(history_echo, gSavedSkinSettings.getColor("IMChatColor"), true, gAgent.getID());
+ addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID());
if (other_was_typing)
{
@@ -2084,7 +1814,7 @@ void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id)
iter != mQueuedMsgsForInit.endArray();
++iter)
{
- deliver_message(
+ LLIMModel::sendMessage(
iter->asString(),
mSessionUUID,
mOtherParticipantUUID,
@@ -2135,23 +1865,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)
@@ -2175,7 +1892,7 @@ void LLFloaterIMPanel::addTypingIndicator(const std::string &name)
mTypingLineStartIndex = mHistoryEditor->getWText().length();
LLUIString typing_start = sTypingStartString;
typing_start.setArg("[NAME]", name);
- addHistoryLine(typing_start, gSavedSkinSettings.getColor4("SystemChatColor"), false);
+ addHistoryLine(typing_start, LLUIColorTable::instance().getColor("SystemChatColor"), false);
mOtherTypingName = name;
mOtherTyping = TRUE;
}
@@ -2206,19 +1923,19 @@ 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 = 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 = LLTrans::getString("IM_logging_string");
}
@@ -2232,7 +1949,7 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
}
//self->addHistoryLine(line, LLColor4::grey, FALSE);
- self->mHistoryEditor->appendColoredText(message, false, true, gSavedSkinSettings.getColor4("ChatHistoryTextColor"));
+ self->mHistoryEditor->appendColoredText(message, false, true, LLUIColorTable::instance().getColor("ChatHistoryTextColor"));
}
void LLFloaterIMPanel::showSessionStartError(
@@ -2318,5 +2035,261 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const
}
return false;
}
+
+
+LLIMFloater::LLIMFloater(const LLUUID& session_id)
+ : LLFloater(session_id),
+ mSessionID(session_id),
+ mLastMessageIndex(-1),
+ mDialog(IM_NOTHING_SPECIAL),
+ mHistoryEditor(NULL),
+ mInputEditor(NULL),
+ mPositioned(false)
+{
+// 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()
+{
+ LLPanelIMControlPanel* im_control_panel = getChild<LLPanelIMControlPanel>("panel_im_control_panel");
+
+ LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL);
+ if(session)
+ {
+ mOtherParticipantUUID = session->mOtherParticipantID;
+ im_control_panel->setAvatarId(session->mOtherParticipantID);
+ mDialog = session->mType;
+ }
+
+ LLButton* slide_left = getChild<LLButton>("slide_left_btn");
+ slide_left->setVisible(im_control_panel->getVisible());
+ slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this));
+
+ LLButton* slide_right = getChild<LLButton>("slide_right_btn");
+ slide_right->setVisible(!im_control_panel->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", true, false);
+
+ setTitle(LLIMModel::instance().getName(mSessionID));
+ setDocked(true);
+
+ mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png");
+
+ return TRUE;
+}
+
+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())
+ {
+ // app not quitting
+ closeFloater(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->setVisible(false);
+ }
+ }
+
+ LLIMFloater* floater = LLFloaterReg::showTypedInstance<LLIMFloater>("impanel", session_id);
+
+ floater->updateMessages();
+ floater->mInputEditor->setFocus(TRUE);
+ return floater;
+}
+
+void LLIMFloater::updateMessages()
+{
+
+ std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1);
+
+ if (messages.size())
+ {
+ 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;
+
+ message << msg["from"].asString() << " : " << msg["time"].asString() << "\n " << msg["message"].asString() << "\n";
+
+ mLastMessageIndex = msg["index"].asInteger();
+ }
+
+ mHistoryEditor->appendText(message.str(), false, false);
+ 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());
+ }
+ }
+}