phoenix-firestorm/indra/newview/llconversationview.cpp

885 lines
28 KiB
C++

/**
* @file llconversationview.cpp
* @brief Implementation of conversations list widgets and views
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llconversationview.h"
#include <boost/bind.hpp>
#include "llagentdata.h"
#include "llavataractions.h"
#include "llconversationmodel.h"
#include "llfloaterimsession.h"
#include "llfloaterimnearbychat.h"
#include "llfloaterimsessiontab.h"
#include "llfloaterimcontainer.h"
#include "llfloaterreg.h"
#include "llgroupiconctrl.h"
#include "lluictrlfactory.h"
#include "lltoolbarview.h"
//
// Implementation of conversations list session widgets
//
static LLDefaultChildRegistry::Register<LLConversationViewSession> r_conversation_view_session("conversation_view_session");
const LLColor4U DEFAULT_WHITE(255, 255, 255);
class LLNearbyVoiceClientStatusObserver : public LLVoiceClientStatusObserver
{
public:
LLNearbyVoiceClientStatusObserver(LLConversationViewSession* conv)
: conversation(conv)
{}
virtual void onChange(EStatusType status, const std::string &channelURI, bool proximal)
{
conversation->showVoiceIndicator(conversation
&& status != STATUS_JOINING
&& status != STATUS_LEFT_CHANNEL
&& LLVoiceClient::getInstance()->voiceEnabled()
&& LLVoiceClient::getInstance()->isVoiceWorking());
}
private:
LLConversationViewSession* conversation;
};
LLConversationViewSession::Params::Params() :
container()
{}
LLConversationViewSession::LLConversationViewSession(const LLConversationViewSession::Params& p):
LLFolderViewFolder(p),
mContainer(p.container),
mItemPanel(NULL),
mCallIconLayoutPanel(NULL),
mSessionTitle(NULL),
mSpeakingIndicator(NULL),
mVoiceClientObserver(NULL),
mCollapsedMode(false),
mHasArrow(true),
mIsInActiveVoiceChannel(false),
mFlashStateOn(false),
mFlashStarted(false)
{
mFlashTimer = new LLFlashTimer();
mAreChildrenInited = true; // inventory only
}
LLConversationViewSession::~LLConversationViewSession()
{
mActiveVoiceChannelConnection.disconnect();
if (mVoiceClientObserver)
{
if (LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
}
delete mVoiceClientObserver;
}
mFlashTimer->unset();
}
void LLConversationViewSession::destroyView()
{
// Chat can create and parent models(listeners) to session's model before creating
// coresponding views, such participant's models normally will wait for idle cycles
// but since we are deleting session and won't be processing any more events, make
// sure unowned LLConversationItemParticipant models are removed as well.
LLConversationItemSession* vmi = dynamic_cast<LLConversationItemSession*>(getViewModelItem());
// CONV_SESSION_1_ON_1 stores participants as two models that belong to views independent
// from session (nasty! These views are widgets in LLFloaterIMSessionTab, see buildConversationViewParticipant)
if (vmi && vmi->getType() != LLConversationItem::CONV_SESSION_1_ON_1)
{
// Destroy existing views
while (!mItems.empty())
{
LLFolderViewItem *itemp = mItems.back();
mItems.pop_back();
LLFolderViewModelItem* item_vmi = itemp->getViewModelItem();
if (item_vmi) // supposed to exist
{
// unparent to remove from child list
vmi->removeChild(item_vmi);
}
itemp->destroyView();
}
// Not needed in scope of sessions, but just in case
while (!mFolders.empty())
{
LLFolderViewFolder *folderp = mFolders.back();
mFolders.pop_back();
LLFolderViewModelItem* folder_vmi = folderp->getViewModelItem();
if (folder_vmi)
{
vmi->removeChild(folder_vmi);
}
folderp->destroyView();
}
// Now everything that is left in model(listener) is not owned by views,
// only by sessions, deparent so it won't point to soon to be dead model
vmi->clearAndDeparentModels();
}
LLFolderViewFolder::destroyView();
}
void LLConversationViewSession::setFlashState(bool flash_state)
{
if (flash_state && !mFlashStateOn)
{
// flash chat toolbar button if scrolled out of sight (because flashing will not be visible)
if (mContainer->isScrolledOutOfSight(this))
{
gToolBarView->flashCommand(LLCommandId("chat"), true);
}
}
mFlashStateOn = flash_state;
mFlashStarted = false;
mFlashTimer->stopFlashing();
}
void LLConversationViewSession::setHighlightState(bool hihglight_state)
{
mFlashStateOn = hihglight_state;
mFlashStarted = true;
mFlashTimer->stopFlashing();
}
void LLConversationViewSession::startFlashing()
{
// Need to start flashing only when "Conversations" is opened or brought on top
if (isInVisibleChain()
&& mFlashStateOn
&& !mFlashStarted
&& ! LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")->isMinimized() )
{
mFlashStarted = true;
mFlashTimer->startFlashing();
}
}
bool LLConversationViewSession::isHighlightAllowed()
{
return mFlashStateOn || mIsSelected;
}
bool LLConversationViewSession::isHighlightActive()
{
return (mFlashStateOn ? (mFlashTimer->isFlashingInProgress() ? mFlashTimer->isCurrentlyHighlighted() : true) : mIsCurSelection);
}
BOOL LLConversationViewSession::postBuild()
{
LLFolderViewItem::postBuild();
mItemPanel = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>("panel_conversation_list_item.xml", NULL, LLPanel::child_registry_t::instance());
addChild(mItemPanel);
mCallIconLayoutPanel = mItemPanel->getChild<LLPanel>("call_icon_panel");
mSessionTitle = mItemPanel->getChild<LLTextBox>("conversation_title");
mActiveVoiceChannelConnection = LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLConversationViewSession::onCurrentVoiceSessionChanged, this, _1));
mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
if (vmi)
{
switch(vmi->getType())
{
case LLConversationItem::CONV_PARTICIPANT:
case LLConversationItem::CONV_SESSION_1_ON_1:
{
LLIMModel::LLIMSession* session= LLIMModel::instance().findIMSession(vmi->getUUID());
if (session)
{
LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon");
icon->setVisible(true);
icon->setValue(session->mOtherParticipantID);
mSpeakingIndicator->setSpeakerId(session->mOtherParticipantID, session->mSessionID, true);
mHasArrow = false;
}
break;
}
case LLConversationItem::CONV_SESSION_AD_HOC:
{
LLGroupIconCtrl* icon = mItemPanel->getChild<LLGroupIconCtrl>("group_icon");
icon->setVisible(true);
mSpeakingIndicator->setSpeakerId(gAgentID, vmi->getUUID(), true);
break;
}
case LLConversationItem::CONV_SESSION_GROUP:
{
LLGroupIconCtrl* icon = mItemPanel->getChild<LLGroupIconCtrl>("group_icon");
icon->setVisible(true);
icon->setValue(vmi->getUUID());
mSpeakingIndicator->setSpeakerId(gAgentID, vmi->getUUID(), true);
break;
}
case LLConversationItem::CONV_SESSION_NEARBY:
{
LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("nearby_chat_icon");
icon->setVisible(true);
mSpeakingIndicator->setSpeakerId(gAgentID, LLUUID::null, true);
mIsInActiveVoiceChannel = true;
if(LLVoiceClient::instanceExists())
{
if (mVoiceClientObserver)
{
LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
delete mVoiceClientObserver;
}
mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this);
LLVoiceClient::getInstance()->addObserver(mVoiceClientObserver);
}
break;
}
default:
break;
}
refresh(); // requires vmi
}
return TRUE;
}
void LLConversationViewSession::draw()
{
getViewModelItem()->update();
const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
// Indicate that flash can start (moot operation if already started, done or not flashing)
startFlashing();
// draw highlight for selected items
drawHighlight(show_context, true, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
// Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap.
bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this) || isOpen();
// Todo/fix this: arrange hides children 'out of bonds', session 'slowly' adjusts container size, unhides children
// this process repeats until children fit
for (folders_t::iterator iter = mFolders.begin();
iter != mFolders.end();)
{
folders_t::iterator fit = iter++;
(*fit)->setVisible(draw_children);
}
for (items_t::iterator iter = mItems.begin();
iter != mItems.end();)
{
items_t::iterator iit = iter++;
(*iit)->setVisible(draw_children);
}
// we don't draw the open folder arrow in minimized mode
if (mHasArrow && !mCollapsedMode)
{
// update the rotation angle of open folder arrow
updateLabelRotation();
drawOpenFolderArrow(default_params, sFgColor);
}
LLView::draw();
}
BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )
{
//Will try to select a child node and then itself (if a child was not selected)
BOOL result = LLFolderViewFolder::handleMouseDown(x, y, mask);
//This node (conversation) was selected and a child (participant) was not
if(result && getRoot())
{
if(getRoot()->getCurSelectedItem() == this)
{
LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem());
LLUUID session_id = item? item->getUUID() : LLUUID();
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
if (im_container->isConversationsPaneCollapsed() && im_container->getSelectedSession() == session_id)
{
im_container->collapseMessagesPane(!im_container->isMessagesPaneCollapsed());
}
else
{
im_container->collapseMessagesPane(false);
}
}
selectConversationItem();
}
return result;
}
BOOL LLConversationViewSession::handleMouseUp( S32 x, S32 y, MASK mask )
{
BOOL result = LLFolderViewFolder::handleMouseUp(x, y, mask);
LLFloater* volume_floater = LLFloaterReg::findInstance("floater_voice_volume");
LLFloater* chat_volume_floater = LLFloaterReg::findInstance("chat_voice");
if (result
&& getRoot() && (getRoot()->getCurSelectedItem() == this)
&& !(volume_floater && volume_floater->isShown() && volume_floater->hasFocus())
&& !(chat_volume_floater && chat_volume_floater->isShown() && chat_volume_floater->hasFocus()))
{
LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem());
LLUUID session_id = item? item->getUUID() : LLUUID();
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
if(session_floater && !session_floater->hasFocus())
{
session_floater->setFocus(true);
}
}
return result;
}
BOOL LLConversationViewSession::handleRightMouseDown( S32 x, S32 y, MASK mask )
{
BOOL result = LLFolderViewFolder::handleRightMouseDown(x, y, mask);
if(result)
{
selectConversationItem();
}
return result;
}
void LLConversationViewSession::selectConversationItem()
{
if(getRoot()->getCurSelectedItem() == this)
{
LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem());
LLUUID session_id = item? item->getUUID() : LLUUID();
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
im_container->flashConversationItemWidget(session_id,false);
im_container->selectConversationPair(session_id, false);
}
}
// virtual
S32 LLConversationViewSession::arrange(S32* width, S32* height)
{
//LLFolderViewFolder::arrange computes value for getIndentation() function below
S32 arranged = LLFolderViewFolder::arrange(width, height);
S32 h_pad = mHasArrow ? getIndentation() + mArrowSize : getIndentation();
LLRect rect(mCollapsedMode ? getLocalRect().mLeft : h_pad,
getLocalRect().mTop,
getLocalRect().mRight,
getLocalRect().mTop - getItemHeight());
mItemPanel->setShape(rect);
return arranged;
}
// virtual
void LLConversationViewSession::toggleOpen()
{
// conversations should not be opened while in minimized mode
if (!mCollapsedMode)
{
LLFolderViewFolder::toggleOpen();
// do item's selection when opened
if (LLFolderViewFolder::isOpen())
{
getParentFolder()->setSelection(this, true);
}
mContainer->reSelectConversation();
}
}
void LLConversationViewSession::toggleCollapsedMode(bool is_collapsed)
{
mCollapsedMode = is_collapsed;
// hide the layout stack which contains all item's child widgets
// except for the icon which we display in minimized mode
getChild<LLView>("conversation_item_stack")->setVisible(!mCollapsedMode);
S32 h_pad = mHasArrow ? getIndentation() + mArrowSize : getIndentation();
mItemPanel->translate(mCollapsedMode ? -h_pad : h_pad, 0);
}
void LLConversationViewSession::setVisibleIfDetached(BOOL visible)
{
// Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized
// Note: minimized dockable floaters are brought to front hence unminimized when made visible and we don't want that here
LLFloater* session_floater = getSessionFloater();
if (session_floater && session_floater->isDetachedAndNotMinimized())
{
session_floater->setVisible(visible);
}
}
LLFloater* LLConversationViewSession::getSessionFloater()
{
LLFolderViewModelItem* item = mViewModelItem;
LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID();
return LLFloaterIMSessionTab::getConversation(session_uuid);
}
LLConversationViewParticipant* LLConversationViewSession::findParticipant(const LLUUID& participant_id)
{
// This is *not* a general tree parsing algorithm. We search only in the mItems list
// assuming there is no mFolders which makes sense for sessions (sessions don't contain
// sessions).
LLConversationViewParticipant* participant = NULL;
items_t::const_iterator iter;
for (iter = getItemsBegin(); iter != getItemsEnd(); iter++)
{
participant = dynamic_cast<LLConversationViewParticipant*>(*iter);
if (participant->hasSameValue(participant_id))
{
break;
}
}
return (iter == getItemsEnd() ? NULL : participant);
}
void LLConversationViewSession::showVoiceIndicator(bool visible)
{
mCallIconLayoutPanel->setVisible(visible && LLVoiceChannel::getCurrentVoiceChannel()->getSessionID().isNull());
requestArrange();
}
void LLConversationViewSession::refresh()
{
// Refresh the session view from its model data
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
if (vmi)
{
vmi->resetRefresh();
if (mSessionTitle)
{
if (!highlightFriendTitle(vmi))
{
LLStyle::Params title_style;
title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
mSessionTitle->setText(vmi->getDisplayName(), title_style);
}
}
}
// Update all speaking indicators
LLSpeakingIndicatorManager::updateSpeakingIndicators();
// we should show indicator for specified voice session only if this is current channel. EXT-5562.
if (mSpeakingIndicator)
{
mSpeakingIndicator->setIsActiveChannel(mIsInActiveVoiceChannel);
mSpeakingIndicator->setShowParticipantsSpeaking(mIsInActiveVoiceChannel);
}
LLConversationViewParticipant* participant = NULL;
items_t::const_iterator iter;
for (iter = getItemsBegin(); iter != getItemsEnd(); iter++)
{
participant = dynamic_cast<LLConversationViewParticipant*>(*iter);
if (participant)
{
participant->allowSpeakingIndicator(mIsInActiveVoiceChannel);
}
}
requestArrange();
if (vmi)
{
// Do the regular upstream refresh
LLFolderViewFolder::refresh();
}
}
void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id)
{
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
if (vmi)
{
bool old_value = mIsInActiveVoiceChannel;
mIsInActiveVoiceChannel = vmi->getUUID() == session_id;
mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel);
if (old_value != mIsInActiveVoiceChannel)
{
refresh();
}
}
}
bool LLConversationViewSession::highlightFriendTitle(LLConversationItem* vmi)
{
if(vmi->getType() == LLConversationItem::CONV_PARTICIPANT || vmi->getType() == LLConversationItem::CONV_SESSION_1_ON_1)
{
LLIMModel::LLIMSession* session= LLIMModel::instance().findIMSession(vmi->getUUID());
if (session && LLAvatarActions::isFriend(session->mOtherParticipantID))
{
LLStyle::Params title_style;
title_style.color = LLUIColorTable::instance().getColor("ConversationFriendColor");
mSessionTitle->setText(vmi->getDisplayName(), title_style);
return true;
}
}
return false;
}
//
// Implementation of conversations list participant (avatar) widgets
//
static LLDefaultChildRegistry::Register<LLConversationViewParticipant> r("conversation_view_participant");
bool LLConversationViewParticipant::sStaticInitialized = false;
S32 LLConversationViewParticipant::sChildrenWidths[LLConversationViewParticipant::ALIC_COUNT];
LLConversationViewParticipant::Params::Params() :
container(),
participant_id(),
avatar_icon("avatar_icon"),
info_button("info_button"),
output_monitor("output_monitor")
{}
LLConversationViewParticipant::LLConversationViewParticipant( const LLConversationViewParticipant::Params& p ):
LLFolderViewItem(p),
mAvatarIcon(NULL),
mInfoBtn(NULL),
mSpeakingIndicator(NULL),
mUUID(p.participant_id)
{
}
LLConversationViewParticipant::~LLConversationViewParticipant()
{
mActiveVoiceChannelConnection.disconnect();
}
void LLConversationViewParticipant::initFromParams(const LLConversationViewParticipant::Params& params)
{
LLAvatarIconCtrl::Params avatar_icon_params(params.avatar_icon());
applyXUILayout(avatar_icon_params, this);
LLAvatarIconCtrl * avatarIcon = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_icon_params);
addChild(avatarIcon);
LLButton::Params info_button_params(params.info_button());
applyXUILayout(info_button_params, this);
LLButton * button = LLUICtrlFactory::create<LLButton>(info_button_params);
addChild(button);
LLOutputMonitorCtrl::Params output_monitor_params(params.output_monitor());
applyXUILayout(output_monitor_params, this);
LLOutputMonitorCtrl * outputMonitor = LLUICtrlFactory::create<LLOutputMonitorCtrl>(output_monitor_params);
addChild(outputMonitor);
}
BOOL LLConversationViewParticipant::postBuild()
{
mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
mInfoBtn = getChild<LLButton>("info_btn");
mInfoBtn->setClickedCallback(boost::bind(&LLConversationViewParticipant::onInfoBtnClick, this));
mInfoBtn->setVisible(false);
mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");
if (!sStaticInitialized)
{
// Remember children widths including their padding from the next sibling,
// so that we can hide and show them again later.
initChildrenWidths(this);
sStaticInitialized = true;
}
updateChildren();
if (getViewModelItem())
{
LLFolderViewItem::postBuild();
refresh();
}
return TRUE;
}
void LLConversationViewParticipant::draw()
{
static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
static LLUIColor sFgDisabledColor = LLUIColorTable::instance().getColor("MenuItemDisabledColor", DEFAULT_WHITE);
static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
static LLUIColor sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
const LLFontGL* font = getLabelFontForStyle(mLabelStyle);
F32 right_x = 0;
F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad;
F32 text_left = (F32)getLabelXPos();
LLColor4 color;
LLLocalSpeakerMgr *speakerMgr = LLLocalSpeakerMgr::getInstance();
if (speakerMgr && speakerMgr->isSpeakerToBeRemoved(mUUID))
{
color = sFgDisabledColor;
}
else
{
if (LLAvatarActions::isFriend(mUUID))
{
color = LLUIColorTable::instance().getColor("ConversationFriendColor");
}
else
{
color = mIsSelected ? sHighlightFgColor : sFgColor;
}
}
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
if (participant_model)
{
mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
}
drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
drawLabel(font, text_left, y, color, right_x);
LLView::draw();
}
// virtual
S32 LLConversationViewParticipant::arrange(S32* width, S32* height)
{
//Need to call arrange first since it computes value used in getIndentation()
S32 arranged = LLFolderViewItem::arrange(width, height);
//Adjusts the avatar icon based upon the indentation
LLRect avatarRect(getIndentation(),
mAvatarIcon->getRect().mTop,
getIndentation() + mAvatarIcon->getRect().getWidth(),
mAvatarIcon->getRect().mBottom);
mAvatarIcon->setShape(avatarRect);
//Since dimensions changed, adjust the children (info button, speaker indicator)
updateChildren();
return arranged;
}
// virtual
void LLConversationViewParticipant::refresh()
{
// Refresh the participant view from its model data
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
if (participant_model)
{
participant_model->resetRefresh();
// *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
// Do the regular upstream refresh
LLFolderViewItem::refresh();
}
}
void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)
{
// Add the item to the folder (conversation)
LLFolderViewItem::addToFolder(folder);
// Retrieve the folder (conversation) UUID, which is also the speaker session UUID
LLFolderViewFolder *prnt = getParentFolder();
if (prnt)
{
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(prnt->getViewModelItem());
if (vmi)
{
addToSession(vmi->getUUID());
}
LLConversationViewSession* session = dynamic_cast<LLConversationViewSession*>(prnt);
if (session)
{
allowSpeakingIndicator(session->isInActiveVoiceChannel());
}
}
}
void LLConversationViewParticipant::addToSession(const LLUUID& session_id)
{
//Allows speaking icon image to be loaded based on mUUID
mAvatarIcon->setValue(mUUID);
//Allows the speaker indicator to be activated based on the user and conversation
mSpeakingIndicator->setSpeakerId(mUUID, session_id);
}
void LLConversationViewParticipant::onInfoBtnClick()
{
LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", mUUID));
}
BOOL LLConversationViewParticipant::handleMouseDown( S32 x, S32 y, MASK mask )
{
BOOL result = LLFolderViewItem::handleMouseDown(x, y, mask);
if(result && getRoot())
{
if(getRoot()->getCurSelectedItem() == this)
{
LLConversationItem* vmi = getParentFolder() ? dynamic_cast<LLConversationItem*>(getParentFolder()->getViewModelItem()) : NULL;
LLUUID session_id = vmi? vmi->getUUID() : LLUUID();
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
im_container->setSelectedSession(session_id);
im_container->flashConversationItemWidget(session_id,false);
im_container->selectFloater(session_floater);
im_container->collapseMessagesPane(false);
}
}
return result;
}
void LLConversationViewParticipant::onMouseEnter(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(true);
updateChildren();
LLFolderViewItem::onMouseEnter(x, y, mask);
}
void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(false);
updateChildren();
LLFolderViewItem::onMouseLeave(x, y, mask);
}
S32 LLConversationViewParticipant::getLabelXPos()
{
return getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad;
}
// static
void LLConversationViewParticipant::initChildrenWidths(LLConversationViewParticipant* self)
{
//speaking indicator width + padding
S32 speaking_indicator_width = self->getRect().getWidth() - self->mSpeakingIndicator->getRect().mLeft;
//info btn width + padding
S32 info_btn_width = self->mSpeakingIndicator->getRect().mLeft - self->mInfoBtn->getRect().mLeft;
S32 index = ALIC_COUNT;
sChildrenWidths[--index] = info_btn_width;
sChildrenWidths[--index] = speaking_indicator_width;
llassert(index == 0);
}
void LLConversationViewParticipant::updateChildren()
{
mLabelPaddingRight = DEFAULT_LABEL_PADDING_RIGHT;
LLView* control;
S32 ctrl_width;
LLRect controlRect;
//Cycles through controls starting from right to left
for (S32 i = 0; i < ALIC_COUNT; ++i)
{
control = getItemChildView((EAvatarListItemChildIndex)i);
// skip invisible views
if (!control->getVisible()) continue;
//Get current pos/dimensions
controlRect = control->getRect();
ctrl_width = sChildrenWidths[i]; // including space between current & left controls
// accumulate the amount of space taken by the controls
mLabelPaddingRight += ctrl_width;
//Reposition visible controls in case adjacent controls to the right are hidden.
controlRect.setLeftTopAndSize(
getLocalRect().getWidth() - mLabelPaddingRight,
controlRect.mTop,
controlRect.getWidth(),
controlRect.getHeight());
//Sets the new position
control->setShape(controlRect);
}
}
LLView* LLConversationViewParticipant::getItemChildView(EAvatarListItemChildIndex child_view_index)
{
LLView* child_view = NULL;
switch (child_view_index)
{
case ALIC_SPEAKER_INDICATOR:
child_view = mSpeakingIndicator;
break;
case ALIC_INFO_BUTTON:
child_view = mInfoBtn;
break;
default:
LL_WARNS("AvatarItemReshape") << "Unexpected child view index is passed: " << child_view_index << LL_ENDL;
llassert(0);
break;
// leave child_view untouched
}
return child_view;
}
void LLConversationViewParticipant::allowSpeakingIndicator(bool val)
{
mSpeakingIndicator->setIsActiveChannel(val);
}
// EOF