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
Seth ProductEngine 2012-06-26 01:38:59 +03:00
parent a7831406ab
commit 0cfea7b406
9 changed files with 151 additions and 82 deletions

View File

@ -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()

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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.
};

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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