CHUI-147 FIX Added updating conference participants in IM floater title
- The title is updated with the data from participants list widget in IM floater. - Creating the participants list is fixed for the case of starting the ad hoc session when the session id changes upon initialization (see LLIMConversation::buildParticipantList()). - LLEventTimer replaced with simple LLTimer to avoid crashes in LLEventTimer::tick(). - Moved the build_residents_string() code to LLAvatarActions::buildResidentsString() to use it in LLIMFloater::onParticipantsListChanged().master
parent
a7831406ab
commit
0cfea7b406
|
|
@ -529,23 +529,6 @@ namespace action_give_inventory
|
|||
return acceptable;
|
||||
}
|
||||
|
||||
static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
|
||||
{
|
||||
llassert(avatar_names.size() > 0);
|
||||
|
||||
const std::string& separator = LLTrans::getString("words_separator");
|
||||
for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
|
||||
{
|
||||
LLAvatarName av_name = *it;
|
||||
residents_string.append(av_name.mDisplayName);
|
||||
if (++it == avatar_names.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
residents_string.append(separator);
|
||||
}
|
||||
}
|
||||
|
||||
static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
|
||||
{
|
||||
llassert(inventory_selected_uuids.size() > 0);
|
||||
|
|
@ -675,7 +658,7 @@ namespace action_give_inventory
|
|||
}
|
||||
|
||||
std::string residents;
|
||||
build_residents_string(avatar_names, residents);
|
||||
LLAvatarActions::buildResidentsString(avatar_names, residents);
|
||||
|
||||
std::string items;
|
||||
build_items_string(inventory_selected_uuids, items);
|
||||
|
|
@ -706,7 +689,23 @@ namespace action_give_inventory
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
|
||||
{
|
||||
llassert(avatar_names.size() > 0);
|
||||
|
||||
const std::string& separator = LLTrans::getString("words_separator");
|
||||
for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
|
||||
{
|
||||
LLAvatarName av_name = *it;
|
||||
residents_string.append(av_name.mDisplayName);
|
||||
if (++it == avatar_names.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
residents_string.append(separator);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class LLAvatarName;
|
||||
class LLInventoryPanel;
|
||||
class LLFloater;
|
||||
|
||||
|
|
@ -208,6 +209,14 @@ public:
|
|||
*/
|
||||
static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL);
|
||||
|
||||
/**
|
||||
* Builds a string of residents' display names separated by "words_separator" string.
|
||||
*
|
||||
* @param avatar_names - a vector of given avatar names from which resulting string is built
|
||||
* @param residents_string - the resulting string
|
||||
*/
|
||||
static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string);
|
||||
|
||||
static std::set<LLUUID> getInventorySelectedUUIDs();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ const F32 REFRESH_INTERVAL = 0.2f;
|
|||
|
||||
LLIMConversation::LLIMConversation(const LLUUID& session_id)
|
||||
: LLTransientDockableFloater(NULL, true, session_id)
|
||||
, LLEventTimer(REFRESH_INTERVAL)
|
||||
, mIsP2PChat(false)
|
||||
, mExpandCollapseBtn(NULL)
|
||||
, mTearOffBtn(NULL)
|
||||
|
|
@ -52,6 +51,7 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id)
|
|||
, mChatHistory(NULL)
|
||||
, mInputEditor(NULL)
|
||||
, mInputEditorTopPad(0)
|
||||
, mRefreshTimer(new LLTimer())
|
||||
{
|
||||
mCommitCallbackRegistrar.add("IMSession.Menu.Action",
|
||||
boost::bind(&LLIMConversation::onIMSessionMenuItemClicked, this, _2));
|
||||
|
|
@ -67,6 +67,10 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id)
|
|||
boost::bind(&LLIMConversation::onIMShowModesMenuItemCheck, this, _2));
|
||||
mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.Enable",
|
||||
boost::bind(&LLIMConversation::onIMShowModesMenuItemEnable, this, _2));
|
||||
|
||||
// Zero expiry time is set only once to allow initial update.
|
||||
mRefreshTimer->setTimerExpirySec(0);
|
||||
mRefreshTimer->start();
|
||||
}
|
||||
|
||||
LLIMConversation::~LLIMConversation()
|
||||
|
|
@ -76,6 +80,8 @@ LLIMConversation::~LLIMConversation()
|
|||
delete mParticipantList;
|
||||
mParticipantList = NULL;
|
||||
}
|
||||
|
||||
delete mRefreshTimer;
|
||||
}
|
||||
|
||||
BOOL LLIMConversation::postBuild()
|
||||
|
|
@ -120,19 +126,22 @@ BOOL LLIMConversation::postBuild()
|
|||
|
||||
}
|
||||
|
||||
BOOL LLIMConversation::tick()
|
||||
void LLIMConversation::draw()
|
||||
{
|
||||
// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
|
||||
// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
|
||||
if (isDead()) return false;
|
||||
LLTransientDockableFloater::draw();
|
||||
|
||||
// Need to resort the participant list if it's in sort by recent speaker order.
|
||||
if (mParticipantList)
|
||||
if (mRefreshTimer->hasExpired())
|
||||
{
|
||||
mParticipantList->update();
|
||||
}
|
||||
if (mParticipantList)
|
||||
{
|
||||
mParticipantList->update();
|
||||
}
|
||||
|
||||
return false;
|
||||
refresh();
|
||||
|
||||
// Restart the refresh timer
|
||||
mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
void LLIMConversation::buildParticipantList()
|
||||
|
|
@ -144,10 +153,11 @@ void LLIMConversation::buildParticipantList()
|
|||
}
|
||||
else
|
||||
{
|
||||
LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
|
||||
// for group and ad-hoc chat we need to include agent into list
|
||||
if(!mIsP2PChat && !mParticipantList && mSessionID.notNull())
|
||||
if(!mIsP2PChat && mSessionID.notNull() && speaker_manager)
|
||||
{
|
||||
LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
|
||||
delete mParticipantList; // remove the old list and create a new one if the session id has changed
|
||||
mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ class LLChatHistory;
|
|||
|
||||
class LLIMConversation
|
||||
: public LLTransientDockableFloater
|
||||
, public LLEventTimer
|
||||
{
|
||||
|
||||
public:
|
||||
|
|
@ -65,6 +64,7 @@ public:
|
|||
/*virtual*/ void onOpen(const LLSD& key);
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void draw();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -89,8 +89,6 @@ protected:
|
|||
void buildParticipantList();
|
||||
void onSortMenuItemClicked(const LLSD& userdata);
|
||||
|
||||
/*virtual*/ BOOL tick();
|
||||
|
||||
bool mIsNearbyChat;
|
||||
bool mIsP2PChat;
|
||||
|
||||
|
|
@ -103,6 +101,9 @@ protected:
|
|||
LLButton* mCloseBtn;
|
||||
|
||||
private:
|
||||
/// Refreshes the floater at a constant rate.
|
||||
virtual void refresh() = 0;
|
||||
|
||||
/// Update floater header and toolbar buttons when hosted/torn off state is toggled.
|
||||
void updateHeaderAndToolbar();
|
||||
|
||||
|
|
@ -113,10 +114,11 @@ private:
|
|||
*/
|
||||
void reshapeChatHistory();
|
||||
|
||||
|
||||
LLChatHistory* mChatHistory;
|
||||
LLChatEntry* mInputEditor;
|
||||
int mInputEditorTopPad; // padding between input field and chat history
|
||||
|
||||
LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,18 @@ void LLIMFloater::onFocusReceived()
|
|||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLIMFloater::refresh()
|
||||
{
|
||||
if (mMeTyping)
|
||||
{
|
||||
// Time out if user hasn't typed for a while.
|
||||
if (mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS)
|
||||
{
|
||||
setTyping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLIMFloater::newIMCallback(const LLSD& data)
|
||||
|
|
@ -188,6 +200,7 @@ void LLIMFloater::sendMsg()
|
|||
|
||||
LLIMFloater::~LLIMFloater()
|
||||
{
|
||||
mParticipantsListRefreshConnection.disconnect();
|
||||
mVoiceChannelStateChangeConnection.disconnect();
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
|
|
@ -225,6 +238,8 @@ void LLIMFloater::initIMFloater()
|
|||
|
||||
boundVoiceChannel();
|
||||
|
||||
mTypingStart = LLTrans::getString("IM_typing_start_string");
|
||||
|
||||
// Show control panel in torn off floaters only.
|
||||
mParticipantListPanel->setVisible(!getHost() && gSavedSettings.getBOOL("IMShowControlPanel"));
|
||||
|
||||
|
|
@ -246,6 +261,20 @@ void LLIMFloater::initIMFloater()
|
|||
{
|
||||
std::string session_name(LLIMModel::instance().getName(mSessionID));
|
||||
updateSessionName(session_name, session_name);
|
||||
|
||||
// For ad hoc conferences we should update the title with participants names.
|
||||
if ((IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID))
|
||||
|| mDialog == IM_SESSION_CONFERENCE_START)
|
||||
{
|
||||
if (mParticipantsListRefreshConnection.connected())
|
||||
{
|
||||
mParticipantsListRefreshConnection.disconnect();
|
||||
}
|
||||
|
||||
LLAvatarList* avatar_list = getChild<LLAvatarList>("speakers_list");
|
||||
mParticipantsListRefreshConnection = avatar_list->setRefreshCompleteCallback(
|
||||
boost::bind(&LLIMFloater::onParticipantsListChanged, this, _1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,8 +302,6 @@ BOOL LLIMFloater::postBuild()
|
|||
|
||||
setDocked(true);
|
||||
|
||||
mTypingStart = LLTrans::getString("IM_typing_start_string");
|
||||
|
||||
LLButton* add_btn = getChild<LLButton>("add_btn");
|
||||
|
||||
// Allow to add chat participants depending on the session type
|
||||
|
|
@ -341,7 +368,9 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids)
|
|||
for (uuid_vec_t::const_iterator id = uuids.begin();
|
||||
id != uuids.end(); ++id)
|
||||
{
|
||||
if (*id == mOtherParticipantUUID)
|
||||
// Skip this check for ad hoc conferences,
|
||||
// conference participants should be listed in mSession->mInitialTargetIDs.
|
||||
if (mIsP2PChat && *id == mOtherParticipantUUID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -411,11 +440,6 @@ void LLIMFloater::onCallButtonClicked()
|
|||
}
|
||||
}
|
||||
|
||||
/*void LLIMFloater::onOpenVoiceControlsClicked()
|
||||
{
|
||||
LLFloaterReg::showInstance("voice_controls");
|
||||
}*/
|
||||
|
||||
void LLIMFloater::onChange(EStatusType status, const std::string &channelURI, bool proximal)
|
||||
{
|
||||
if(status != STATUS_JOINING && status != STATUS_LEFT_CHANNEL)
|
||||
|
|
@ -448,28 +472,55 @@ void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id,
|
|||
mTypingStart.setArg("[NAME]", ui_title);
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLIMFloater::tick()
|
||||
void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
|
||||
{
|
||||
// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
|
||||
// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
|
||||
if (isDead())
|
||||
LLAvatarList* avatar_list = dynamic_cast<LLAvatarList*>(ctrl);
|
||||
if (!avatar_list)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL parents_retcode = LLIMConversation::tick();
|
||||
bool all_names_resolved = true;
|
||||
std::vector<LLSD> participants_uuids;
|
||||
|
||||
if ( mMeTyping )
|
||||
avatar_list->getValues(participants_uuids);
|
||||
|
||||
// Check whether we have all participants names in LLAvatarNameCache
|
||||
for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it)
|
||||
{
|
||||
// Time out if user hasn't typed for a while.
|
||||
if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS )
|
||||
const LLUUID& id = it->asUUID();
|
||||
LLAvatarName av_name;
|
||||
if (!LLAvatarNameCache::get(id, &av_name))
|
||||
{
|
||||
setTyping(false);
|
||||
all_names_resolved = false;
|
||||
|
||||
// If a name is not found in cache, request it and continue the process recursively
|
||||
// until all ids are resolved into names.
|
||||
LLAvatarNameCache::get(id,
|
||||
boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return parents_retcode;
|
||||
if (all_names_resolved)
|
||||
{
|
||||
std::vector<LLAvatarName> avatar_names;
|
||||
std::vector<LLSD>::const_iterator it = participants_uuids.begin();
|
||||
for (; it != participants_uuids.end(); ++it)
|
||||
{
|
||||
const LLUUID& id = it->asUUID();
|
||||
LLAvatarName av_name;
|
||||
if (LLAvatarNameCache::get(id, &av_name))
|
||||
{
|
||||
avatar_names.push_back(av_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ui_title;
|
||||
LLAvatarActions::buildResidentsString(avatar_names, ui_title);
|
||||
|
||||
updateSessionName(ui_title, ui_title);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
@ -737,8 +788,6 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
|
|||
{
|
||||
initIMSession(im_session_id);
|
||||
|
||||
boundVoiceChannel();
|
||||
|
||||
buildParticipantList();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ public:
|
|||
/*virtual*/ void setVisible(BOOL visible);
|
||||
/*virtual*/ BOOL getVisible();
|
||||
// Check typing timeout timer.
|
||||
/*virtual*/ BOOL tick();
|
||||
|
||||
static LLIMFloater* findInstance(const LLUUID& session_id);
|
||||
static LLIMFloater* getInstance(const LLUUID& session_id);
|
||||
|
|
@ -131,12 +130,18 @@ private:
|
|||
/* virtual */ void onFocusLost();
|
||||
/* virtual */ void onFocusReceived();
|
||||
|
||||
/*virtual*/ void refresh();
|
||||
|
||||
// Update the window title, input field help text, etc.
|
||||
void updateSessionName(const std::string& ui_title, const std::string& ui_label);
|
||||
|
||||
// For display name lookups for IM window titles
|
||||
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
|
||||
|
||||
/// Updates the list of ad hoc conference participants
|
||||
/// in an IM floater title.
|
||||
void onParticipantsListChanged(LLUICtrl* ctrl);
|
||||
|
||||
bool dropPerson(LLUUID* person_id, bool drop);
|
||||
|
||||
BOOL isInviteAllowed() const;
|
||||
|
|
@ -193,6 +198,8 @@ private:
|
|||
|
||||
// connection to voice channel state change signal
|
||||
boost::signals2::connection mVoiceChannelStateChangeConnection;
|
||||
|
||||
boost::signals2::connection mParticipantsListRefreshConnection;
|
||||
};
|
||||
|
||||
#endif // LL_IMFLOATER_H
|
||||
|
|
|
|||
|
|
@ -186,6 +186,21 @@ BOOL LLNearbyChat::postBuild()
|
|||
return LLIMConversation::postBuild();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLNearbyChat::refresh()
|
||||
{
|
||||
displaySpeakingIndicator();
|
||||
updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
|
||||
|
||||
// *HACK: Update transparency type depending on whether our children have focus.
|
||||
// This is needed because this floater is chrome and thus cannot accept focus, so
|
||||
// the transparency type setting code from LLFloater::setFocus() isn't reached.
|
||||
if (getTransparencyType() != TT_DEFAULT)
|
||||
{
|
||||
setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLNearbyChat::onNearbySpeakers()
|
||||
{
|
||||
LLSD param;
|
||||
|
|
@ -389,27 +404,6 @@ void LLNearbyChat::showHistory()
|
|||
storeRectControl();
|
||||
}
|
||||
|
||||
|
||||
BOOL LLNearbyChat::tick()
|
||||
{
|
||||
// This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
|
||||
// via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
|
||||
if (isDead()) return false;
|
||||
|
||||
displaySpeakingIndicator();
|
||||
updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
|
||||
|
||||
// *HACK: Update transparency type depending on whether our children have focus.
|
||||
// This is needed because this floater is chrome and thus cannot accept focus, so
|
||||
// the transparency type setting code from LLFloater::setFocus() isn't reached.
|
||||
if (getTransparencyType() != TT_DEFAULT)
|
||||
{
|
||||
setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
|
||||
}
|
||||
|
||||
return LLIMConversation::tick();
|
||||
}
|
||||
|
||||
std::string LLNearbyChat::getCurrentChat()
|
||||
{
|
||||
return mChatBox ? mChatBox->getText() : LLStringUtil::null;
|
||||
|
|
|
|||
|
|
@ -73,8 +73,6 @@ public:
|
|||
|
||||
LLChatEntry* getChatBox() { return mChatBox; }
|
||||
|
||||
//virtual void draw();
|
||||
|
||||
std::string getCurrentChat();
|
||||
|
||||
virtual BOOL handleKeyHere( KEY key, MASK mask );
|
||||
|
|
@ -119,8 +117,6 @@ protected:
|
|||
|
||||
S32 mExpandedHeight;
|
||||
|
||||
/*virtual*/ BOOL tick();
|
||||
|
||||
private:
|
||||
|
||||
void getAllowedRect (LLRect& rect);
|
||||
|
|
@ -128,6 +124,8 @@ private:
|
|||
void appendMessage(const LLChat& chat, const LLSD &args = 0);
|
||||
void onNearbySpeakers ();
|
||||
|
||||
/*virtual*/ void refresh();
|
||||
|
||||
LLHandle<LLView> mPopupMenuHandle;
|
||||
std::vector<LLChat> mMessageArchive;
|
||||
LLChatHistory* mChatHistory;
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ void LLParticipantList::update()
|
|||
{
|
||||
mSpeakerMgr->update(true);
|
||||
|
||||
// Need to resort the participant list if it's in sort by recent speaker order.
|
||||
if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder() && !isHovered())
|
||||
{
|
||||
// Resort avatar list
|
||||
|
|
|
|||
Loading…
Reference in New Issue