summaryrefslogtreecommitdiff
path: root/indra/newview/llimfloater.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llimfloater.cpp')
-rw-r--r--indra/newview/llimfloater.cpp416
1 files changed, 416 insertions, 0 deletions
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
new file mode 100644
index 0000000000..29102feb64
--- /dev/null
+++ b/indra/newview/llimfloater.cpp
@@ -0,0 +1,416 @@
+/**
+ * @file llimfloater.cpp
+ * @brief LLIMFloater class definition
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llimfloater.h"
+
+#include "llagent.h"
+#include "llappviewer.h"
+#include "llbutton.h"
+#include "llbottomtray.h"
+#include "llchannelmanager.h"
+#include "llchiclet.h"
+#include "llfloaterreg.h"
+#include "llimview.h"
+#include "lllineeditor.h"
+#include "llpanelimcontrolpanel.h"
+#include "llscreenchannel.h"
+#include "lltrans.h"
+#include "llviewertexteditor.h"
+#include "llviewerwindow.h"
+
+
+
+LLIMFloater::LLIMFloater(const LLUUID& session_id)
+ : LLDockableFloater(NULL, 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");
+
+ gFocusMgr.addFocusChangeCallback(boost::bind(&LLIMFloater::focusChangeCallback, this));
+
+ mCloseSignal.connect(boost::bind(&LLIMFloater::onClose, this));
+}
+
+void LLIMFloater::onClose()
+{
+ LLIMModel::instance().sendLeaveSession(mSessionID, mOtherParticipantUUID);
+ gIMMgr->removeSession(mSessionID);
+}
+
+/* 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");
+ mHistoryEditor->setParseHTML(TRUE);
+
+ setTitle(LLIMModel::instance().getName(mSessionID));
+ setDocked(true);
+
+ return LLDockableFloater::postBuild();
+}
+
+
+
+// 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;
+}
+
+
+
+void LLIMFloater::focusChangeCallback()
+{
+ // hide docked floater if user clicked inside in-world area
+ if (isDocked() && gFocusMgr.getKeyboardFocus() == NULL)
+ {
+ setVisible(false);
+ }
+}
+
+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);
+
+ if (floater->getDockControl() == NULL)
+ {
+ LLChiclet* chiclet =
+ LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(
+ session_id);
+ if (chiclet == NULL)
+ {
+ llerror("Dock chiclet for LLIMFloater doesn't exists", 0);
+ }
+ else
+ {
+ LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
+ }
+
+ floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(),
+ LLDockControl::TOP, boost::bind(&LLIMFloater::getEnabledRect, floater, _1)));
+ }
+
+ return floater;
+}
+
+void LLIMFloater::getEnabledRect(LLRect& rect)
+{
+ rect = gViewerWindow->getWorldViewRect();
+}
+
+void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
+{
+ // update notification channel state
+ LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ LLDockableFloater::setDocked(docked, pop_on_undock);
+
+ // update notification channel state
+ if(channel)
+ {
+ channel->updateShowToastsState();
+ }
+}
+
+void LLIMFloater::setVisible(BOOL visible)
+{
+ LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ LLDockableFloater::setVisible(visible);
+
+ // update notification channel state
+ if(channel)
+ {
+ channel->updateShowToastsState();
+ }
+}
+
+//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);
+ std::string agent_name;
+
+ gCacheName->getFullName(gAgentID, agent_name);
+
+ 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 (from == agent_name)
+ from = LLTrans::getString("You");
+ 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;
+
+ //in disconnected state IM input editor should be disabled
+ self->mInputEditor->setEnabled(!gDisconnected);
+
+ 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)
+{
+}
+