Files
SingularityViewer/indra/newview/llfloaterchat.cpp
Lirusaito 820b4ea358 Optionally, remove chatbar from local chat floater.
FloaterChatBarlessRect keeps the size of this separate, for those who want to switch by mood.
ShowLocalChatFloaterBar toggles this.
Show local chat bar in floater entry added to Adv. Chat prefs.
floater_chat_history_barless.xml added for this.
2013-01-08 12:16:51 -05:00

739 lines
21 KiB
C++

/**
* @file llfloaterchat.cpp
* @brief LLFloaterChat class implementation
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-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$
*/
/**
* Actually the "Chat History" floater.
* Should be llfloaterchathistory, not llfloaterchat.
*/
#include "llviewerprecompiledheaders.h"
#include "llfloaterchat.h"
#include "llfloateractivespeakers.h"
#include "llfloaterscriptdebug.h"
#include "llchat.h"
#include "llfontgl.h"
#include "llrect.h"
#include "llerror.h"
#include "llstring.h"
#include "message.h"
// project include
#include "llagent.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llconsole.h"
#include "llfloaterchatterbox.h"
#include "llfloatermute.h"
#include "llkeyboard.h"
//#include "lllineeditor.h"
#include "llmutelist.h"
//#include "llresizehandle.h"
#include "llchatbar.h"
#include "llstatusbar.h"
#include "llviewertexteditor.h"
#include "llviewergesture.h" // for triggering gestures
#include "llviewermessage.h"
#include "llviewerwindow.h"
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llchatbar.h"
#include "lllogchat.h"
#include "lltexteditor.h"
#include "lltextparser.h"
#include "llfloaterhtml.h"
#include "llweb.h"
#include "llstylemap.h"
#include "ascentkeyword.h"
// linden library includes
#include "llaudioengine.h"
#include "llchat.h"
#include "llfontgl.h"
#include "llrect.h"
#include "llerror.h"
#include "llstring.h"
#include "llwindow.h"
#include "message.h"
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]
//
// Global statics
//
LLColor4 get_text_color(const LLChat& chat);
//
// Member Functions
//
LLFloaterChat::LLFloaterChat(const LLSD& seed)
: LLFloater(std::string("chat floater"), std::string("FloaterChatRect"), LLStringUtil::null,
RESIZE_YES, 440, 100, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES),
mPanel(NULL)
{
mFactoryMap["chat_panel"] = LLCallbackMap(createChatPanel, NULL);
mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, NULL);
// do not automatically open singleton floaters (as result of getInstance())
BOOL no_open = FALSE;
bool show_bar = gSavedSettings.getBOOL("ShowLocalChatFloaterBar");
LLUICtrlFactory::getInstance()->buildFloater(this, (show_bar ? "floater_chat_history.xml" : "floater_chat_history_barless.xml"), &getFactoryMap(), no_open);
childSetCommitCallback("show mutes",onClickToggleShowMute,this); //show mutes
childSetCommitCallback("translate chat",onClickToggleTranslateChat,this);
childSetValue("translate chat", gSavedSettings.getBOOL("TranslateChat"));
childSetVisible("Chat History Editor with mute",FALSE);
childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this);
childSetAction("chat_history_open", onClickChatHistoryOpen, this);
setDefaultBtn("Chat");
}
LLFloaterChat::~LLFloaterChat()
{
// Children all cleaned up by default view destructor.
}
void LLFloaterChat::setVisible(BOOL visible)
{
LLFloater::setVisible( visible );
gSavedSettings.setBOOL("ShowChatHistory", visible);
}
void LLFloaterChat::draw()
{
// enable say and shout only when text available
mToggleActiveSpeakersBtn->setValue(mPanel->getVisible());
LLChatBar* chat_barp = mChatPanel;
if (chat_barp)
{
chat_barp->refresh();
}
mPanel->refreshSpeakers();
LLFloater::draw();
}
BOOL LLFloaterChat::postBuild()
{
mPanel = (LLPanelActiveSpeakers*)getChild<LLPanel>("active_speakers_panel");
LLChatBar* chat_barp = getChild<LLChatBar>("chat_panel", TRUE);
if (chat_barp)
{
chat_barp->setGestureCombo(getChild<LLComboBox>( "Gesture"));
}
mToggleActiveSpeakersBtn.connect(this,"toggle_active_speakers_btn");
mChatPanel.connect(this,"chat_panel");
return TRUE;
}
// public virtual
void LLFloaterChat::onClose(bool app_quitting)
{
if (!app_quitting)
{
gSavedSettings.setBOOL("ShowChatHistory", FALSE);
}
setVisible(FALSE);
}
void LLFloaterChat::handleVisibilityChange(BOOL new_visibility)
{
// Hide the chat overlay when our history is visible.
updateConsoleVisibility();
// stop chat history tab from flashing when it appears
if (new_visibility)
{
LLFloaterChatterBox::getInstance()->setFloaterFlashing(this, FALSE);
}
LLFloater::handleVisibilityChange(new_visibility);
}
void LLFloaterChat::setMinimized(BOOL minimized)
{
LLFloater::setMinimized(minimized);
updateConsoleVisibility();
}
void LLFloaterChat::updateConsoleVisibility()
{
// determine whether we should show console due to not being visible
gConsole->setVisible( !isInVisibleChain() // are we not in part of UI being drawn?
|| isMinimized() // are we minimized?
|| (getHost() && getHost()->isMinimized() )); // are we hosted in a minimized floater?
}
void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& color)
{
std::string line = chat.mText;
bool prepend_newline = true;
if (gSavedSettings.getBOOL("ChatShowTimestamps"))
{
edit->appendTime(prepend_newline);
prepend_newline = false;
}
// If the msg is from an agent (not yourself though),
// extract out the sender name and replace it with the hotlinked name.
if (chat.mSourceType == CHAT_SOURCE_AGENT &&
// chat.mFromID != LLUUID::null)
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e)
chat.mFromID != LLUUID::null &&
(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
// [/RLVa:KB]
{
chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str());
}
if(chat.mSourceType == CHAT_SOURCE_OBJECT && !chat.mFromName.length())
{
chat.mFromName = "(no name)";
line = chat.mFromName + line;
}
// If the chat line has an associated url, link it up to the name.
if (!chat.mURL.empty()
&& (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0))
{
std::string start_line = line.substr(0, chat.mFromName.length() + 1);
line = line.substr(chat.mFromName.length() + 1);
const LLStyleSP &sourceStyle = LLStyleMap::instance().lookup(chat.mFromID,chat.mURL);
edit->appendStyledText(start_line, false, prepend_newline, sourceStyle);
prepend_newline = false;
}
edit->appendColoredText(line, false, prepend_newline, color);
}
void log_chat_text(const LLChat& chat)
{
std::string histstr;
if (gSavedPerAccountSettings.getBOOL("LogChatTimestamp"))
histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + chat.mText;
else
histstr = chat.mText;
LLLogChat::saveHistory(std::string("chat"),histstr);
}
// static
void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file)
{
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
if (rlv_handler_t::isEnabled())
{
// TODO-RLVa: we might cast too broad a net by filtering here, needs testing
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != chat.mSourceType) )
{
LLChat& rlvChat = const_cast<LLChat&>(chat);
RlvUtil::filterLocation(rlvChat.mText);
rlvChat.mRlvLocFiltered = TRUE;
}
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) )
{
// NOTE: this will also filter inventory accepted/declined text in the chat history
LLChat& rlvChat = const_cast<LLChat&>(chat);
if (CHAT_SOURCE_AGENT != chat.mSourceType)
{
// Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup)
RlvUtil::filterNames(rlvChat.mText);
}
rlvChat.mRlvNamesFiltered = TRUE;
}
}
// [/RLVa:KB]
if ( gSavedPerAccountSettings.getBOOL("LogChat") && log_to_file)
{
log_chat_text(chat);
}
LLColor4 color = get_text_color(chat);
if (!log_to_file) color = LLColor4::grey; //Recap from log file.
if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)
{
LLFloaterScriptDebug::addScriptLine(chat.mText,
chat.mFromName,
color,
chat.mFromID);
if (!gSavedSettings.getBOOL("ScriptErrorsAsChat"))
{
return;
}
}
// could flash the chat button in the status bar here. JC
LLFloaterChat* chat_floater = LLFloaterChat::getInstance(LLSD());
LLViewerTextEditor* history_editor = chat_floater->getChild<LLViewerTextEditor>("Chat History Editor");
LLViewerTextEditor* history_editor_with_mute = chat_floater->getChild<LLViewerTextEditor>("Chat History Editor with mute");
history_editor->setParseHTML(TRUE);
history_editor_with_mute->setParseHTML(TRUE);
history_editor->setParseHighlights(TRUE);
history_editor_with_mute->setParseHighlights(TRUE);
if (!chat.mMuted)
{
add_timestamped_line(history_editor, chat, color);
add_timestamped_line(history_editor_with_mute, chat, color);
}
else
{
static LLCachedControl<bool> color_muted_chat("ColorMutedChat");
// desaturate muted chat
LLColor4 muted_color = lerp(color, color_muted_chat ? gSavedSettings.getColor4("AscentMutedColor") : LLColor4::grey, 0.5f);
add_timestamped_line(history_editor_with_mute, chat, muted_color);
}
// add objects as transient speakers that can be muted
if (chat.mSourceType == CHAT_SOURCE_OBJECT)
{
chat_floater->mPanel->setSpeaker(chat.mFromID, chat.mFromName, LLSpeaker::STATUS_NOT_IN_CHANNEL, LLSpeaker::SPEAKER_OBJECT);
}
// start tab flashing on incoming text from other users (ignoring system text, etc)
if (!chat_floater->isInVisibleChain() && chat.mSourceType == CHAT_SOURCE_AGENT)
{
LLFloaterChatterBox::getInstance()->setFloaterFlashing(chat_floater, TRUE);
}
}
// static
void LLFloaterChat::setHistoryCursorAndScrollToEnd()
{
LLViewerTextEditor* history_editor = LLFloaterChat::getInstance(LLSD())->getChild<LLViewerTextEditor>("Chat History Editor");
LLViewerTextEditor* history_editor_with_mute = LLFloaterChat::getInstance(LLSD())->getChild<LLViewerTextEditor>("Chat History Editor with mute");
if (history_editor)
{
history_editor->setCursorAndScrollToEnd();
}
if (history_editor_with_mute)
{
history_editor_with_mute->setCursorAndScrollToEnd();
}
}
//static
void LLFloaterChat::onClickMute(void *data)
{
LLFloaterChat* self = (LLFloaterChat*)data;
LLComboBox* chatter_combo = self->getChild<LLComboBox>("chatter combobox");
const std::string& name = chatter_combo->getSimple();
LLUUID id = chatter_combo->getCurrentID();
if (name.empty()) return;
LLMute mute(id);
mute.setFromDisplayName(name);
LLMuteList::getInstance()->add(mute);
LLFloaterMute::showInstance();
}
//static
void LLFloaterChat::onClickToggleShowMute(LLUICtrl* caller, void *data)
{
LLFloaterChat* floater = (LLFloaterChat*)data;
//LLCheckBoxCtrl*
BOOL show_mute = floater->getChild<LLCheckBoxCtrl>("show mutes")->get();
LLViewerTextEditor* history_editor = floater->getChild<LLViewerTextEditor>("Chat History Editor");
LLViewerTextEditor* history_editor_with_mute = floater->getChild<LLViewerTextEditor>("Chat History Editor with mute");
if (!history_editor || !history_editor_with_mute)
return;
//BOOL show_mute = floater->mShowMuteCheckBox->get();
if (show_mute)
{
history_editor->setVisible(FALSE);
history_editor_with_mute->setVisible(TRUE);
history_editor_with_mute->setCursorAndScrollToEnd();
}
else
{
history_editor->setVisible(TRUE);
history_editor_with_mute->setVisible(FALSE);
history_editor->setCursorAndScrollToEnd();
}
}
// Update the "TranslateChat" pref after "translate chat" checkbox is toggled in
// the "Local Chat" floater.
//static
void LLFloaterChat::onClickToggleTranslateChat(LLUICtrl* caller, void *data)
{
LLFloaterChat* floater = (LLFloaterChat*)data;
BOOL translate_chat = floater->getChild<LLCheckBoxCtrl>("translate chat")->get();
gSavedSettings.setBOOL("TranslateChat", translate_chat);
}
// Update the "translate chat" checkbox after the "TranslateChat" pref is set in
// some other place (e.g. prefs dialog).
//static
void LLFloaterChat::updateSettings()
{
BOOL translate_chat = gSavedSettings.getBOOL("TranslateChat");
LLFloaterChat::getInstance(LLSD())->getChild<LLCheckBoxCtrl>("translate chat")->set(translate_chat);
}
// Put a line of chat in all the right places
void LLFloaterChat::addChat(const LLChat& chat,
BOOL from_instant_message,
BOOL local_agent)
{
LLColor4 text_color = get_text_color(chat);
BOOL invisible_script_debug_chat =
chat.mChatType == CHAT_TYPE_DEBUG_MSG
&& !gSavedSettings.getBOOL("ScriptErrorsAsChat");
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
if (rlv_handler_t::isEnabled())
{
// TODO-RLVa: we might cast too broad a net by filtering here, needs testing
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != chat.mSourceType) )
{
LLChat& rlvChat = const_cast<LLChat&>(chat);
if (!from_instant_message)
RlvUtil::filterLocation(rlvChat.mText);
rlvChat.mRlvLocFiltered = TRUE;
}
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) )
{
LLChat& rlvChat = const_cast<LLChat&>(chat);
if ( (!from_instant_message) && (CHAT_SOURCE_AGENT != chat.mSourceType) )
{
// Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup)
RlvUtil::filterNames(rlvChat.mText);
}
rlvChat.mRlvNamesFiltered = TRUE;
}
}
// [/RLVa:KB]
if (!invisible_script_debug_chat
&& !chat.mMuted
&& gConsole
&& !local_agent)
{
if (chat.mSourceType == CHAT_SOURCE_SYSTEM)
{
text_color = gSavedSettings.getColor("SystemChatColor");
}
else if(from_instant_message)
{
text_color = gSavedSettings.getColor("IMChatColor");
}
// We display anything if it's not an IM. If it's an IM, check pref...
if ( !from_instant_message || gSavedSettings.getBOOL("IMInChatConsole") )
{
gConsole->addConsoleLine(chat.mText, text_color);
}
}
if(from_instant_message && gSavedPerAccountSettings.getBOOL("LogChatIM"))
log_chat_text(chat);
if(from_instant_message && gSavedSettings.getBOOL("IMInChatHistory"))
addChatHistory(chat,false);
triggerAlerts(chat.mText);
if(!from_instant_message)
addChatHistory(chat);
}
// Moved from lltextparser.cpp to break llui/llaudio library dependency.
//static
void LLFloaterChat::triggerAlerts(const std::string& text)
{
// Cannot instantiate LLTextParser before logging in.
if (gDirUtilp->getLindenUserDir(true).empty())
return;
LLTextParser* parser = LLTextParser::getInstance();
// bool spoken=FALSE;
for (S32 i=0;i<parser->mHighlights.size();i++)
{
LLSD& highlight = parser->mHighlights[i];
if (parser->findPattern(text,highlight) >= 0 )
{
if(gAudiop)
{
if ((std::string)highlight["sound_lluuid"] != LLUUID::null.asString())
{
gAudiop->triggerSound(highlight["sound_lluuid"].asUUID(),
gAgent.getID(),
1.f,
LLAudioEngine::AUDIO_TYPE_UI,
gAgent.getPositionGlobal() );
}
/*
if (!spoken)
{
LLTextToSpeech* text_to_speech = NULL;
text_to_speech = LLTextToSpeech::getInstance();
spoken = text_to_speech->speak((LLString)highlight["voice"],text);
}
*/
}
if (highlight["flash"])
{
LLWindow* viewer_window = gViewerWindow->getWindow();
if (viewer_window && viewer_window->getMinimized())
{
viewer_window->flashIcon(5.f);
}
}
}
}
}
LLColor4 get_text_color(const LLChat& chat)
{
LLColor4 text_color;
if(chat.mMuted)
{
static LLCachedControl<bool> color_muted_chat("ColorMutedChat");
if (color_muted_chat)
text_color = gSavedSettings.getColor4("AscentMutedColor");
else
text_color.setVec(0.8f, 0.8f, 0.8f, 1.f);
}
else
{
switch(chat.mSourceType)
{
case CHAT_SOURCE_SYSTEM:
text_color = gSavedSettings.getColor4("SystemChatColor");
break;
case CHAT_SOURCE_AGENT:
if (chat.mFromID.isNull())
{
text_color = gSavedSettings.getColor4("SystemChatColor");
}
else
{
if(gAgent.getID() == chat.mFromID)
{
text_color = gSavedSettings.getColor4("UserChatColor");
}
else
{
static LLCachedControl<bool> color_linden_chat("ColorLindenChat");
if (color_linden_chat && LLMuteList::getInstance()->isLinden(chat.mFromName))
{
text_color = gSavedSettings.getColor4("AscentLindenColor");
}
else if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
{
static LLCachedControl<bool> color_friend_chat("ColorFriendChat");
static LLCachedControl<bool> color_eo_chat("ColorEstateOwnerChat");
if (color_friend_chat && LLAvatarTracker::instance().isBuddy(chat.mFromID))
{
text_color = gSavedSettings.getColor4("AscentFriendColor");
}
else if (color_eo_chat)
{
LLViewerRegion* parent_estate = gAgent.getRegion();
if (parent_estate && parent_estate->isAlive() && chat.mFromID == parent_estate->getOwner())
text_color = gSavedSettings.getColor4("AscentEstateOwnerColor");
else
text_color = gSavedSettings.getColor4("AgentChatColor");
}
else
text_color = gSavedSettings.getColor4("AgentChatColor");
}
else
{
text_color = gSavedSettings.getColor4("AgentChatColor");
}
}
}
break;
case CHAT_SOURCE_OBJECT:
if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)
{
text_color = gSavedSettings.getColor4("ScriptErrorColor");
}
else if ( chat.mChatType == CHAT_TYPE_OWNER )
{
text_color = gSavedSettings.getColor4("llOwnerSayChatColor");
}
else
{
text_color = gSavedSettings.getColor4("ObjectChatColor");
}
break;
default:
text_color.setToWhite();
}
if (!chat.mPosAgent.isExactlyZero())
{
LLVector3 pos_agent = gAgent.getPositionAgent();
F32 distance = dist_vec(pos_agent, chat.mPosAgent);
if (distance > gAgent.getNearChatRadius())
{
// diminish far-off chat
text_color.mV[VALPHA] = 0.8f;
}
}
}
static const LLCachedControl<bool> mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false);
static const LLCachedControl<LLColor4> mKeywordsColor(gSavedPerAccountSettings, "KeywordsColor", LLColor4(1.f, 1.f, 1.f, 1.f));
if ((gAgent.getID() != chat.mFromID) && (chat.mSourceType != CHAT_SOURCE_SYSTEM))
{
if (mKeywordsChangeColor)
{
std::string shortmsg(chat.mText);
shortmsg.erase(0, chat.mFromName.length());
if (AscentKeyword::hasKeyword(shortmsg, 1))
{
text_color = mKeywordsColor;
}
}
}
return text_color;
}
//static
void LLFloaterChat::loadHistory()
{
LLLogChat::loadHistory(std::string("chat"), &chatFromLogFile, (void *)LLFloaterChat::getInstance(LLSD()));
}
//static
void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type , std::string line, void* userdata)
{
switch (type)
{
case LLLogChat::LOG_EMPTY:
case LLLogChat::LOG_END:
// *TODO: nice message from XML file here
break;
case LLLogChat::LOG_LINE:
{
LLChat chat;
chat.mText = line;
addChatHistory(chat, FALSE);
}
break;
default:
// nothing
break;
}
}
//static
void* LLFloaterChat::createSpeakersPanel(void* data)
{
return new LLPanelActiveSpeakers(LLLocalSpeakerMgr::getInstance(), TRUE);
}
//static
void* LLFloaterChat::createChatPanel(void* data)
{
LLChatBar* chatp = new LLChatBar();
return chatp;
}
// static
void LLFloaterChat::onClickToggleActiveSpeakers(void* userdata)
{
LLFloaterChat* self = (LLFloaterChat*)userdata;
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
self->childSetVisible("active_speakers_panel",
(!self->childIsVisible("active_speakers_panel")) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) );
// [/RLVa:KB]
//self->childSetVisible("active_speakers_panel", !self->childIsVisible("active_speakers_panel"));
}
// static
void LLFloaterChat::onClickChatHistoryOpen(void* userdata)
{
char command[256];
sprintf(command, "\"%s%s%s\"", gDirUtilp->getPerAccountChatLogsDir().c_str(), gDirUtilp->getDirDelimiter().c_str(), "chat.txt");
gViewerWindow->getWindow()->ShellEx(command);
llinfos << command << llendl;
}
//static
bool LLFloaterChat::visible(LLFloater* instance, const LLSD& key)
{
return VisibilityPolicy<LLFloater>::visible(instance, key);
}
//static
void LLFloaterChat::show(LLFloater* instance, const LLSD& key)
{
VisibilityPolicy<LLFloater>::show(instance, key);
}
//static
void LLFloaterChat::hide(LLFloater* instance, const LLSD& key)
{
if(instance->getHost())
{
LLFloaterChatterBox::hideInstance();
}
else
{
VisibilityPolicy<LLFloater>::hide(instance, key);
}
}