diff options
-rw-r--r-- | indra/llui/llfolderview.cpp | 2 | ||||
-rwxr-xr-x | indra/llui/llfolderviewitem.cpp | 32 | ||||
-rwxr-xr-x | indra/llui/llfolderviewitem.h | 2 | ||||
-rw-r--r-- | indra/llui/llfolderviewmodel.h | 7 | ||||
-rwxr-xr-x | indra/newview/llconversationview.cpp | 31 | ||||
-rwxr-xr-x | indra/newview/llconversationview.h | 1 | ||||
-rw-r--r-- | indra/newview/llimconversation.cpp | 193 | ||||
-rw-r--r-- | indra/newview/llimconversation.h | 24 | ||||
-rw-r--r-- | indra/newview/llimfloater.cpp | 57 | ||||
-rw-r--r-- | indra/newview/llimfloater.h | 4 | ||||
-rw-r--r-- | indra/newview/llimfloatercontainer.cpp | 157 | ||||
-rw-r--r-- | indra/newview/llimfloatercontainer.h | 3 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_im_session.xml | 20 | ||||
-rwxr-xr-x | indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml | 2 |
14 files changed, 375 insertions, 160 deletions
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index c31a832141..a33ffc4240 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -566,7 +566,7 @@ void LLFolderView::sanitizeSelection() parent_folder; parent_folder = parent_folder->getParentFolder()) { - if (parent_folder->getViewModelItem()->potentiallyVisible()) + if (parent_folder->getViewModelItem() && parent_folder->getViewModelItem()->potentiallyVisible()) { // give initial selection to first ancestor folder that potentially passes the filter if (!new_selection) diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 7c63cad1b7..c5231c4f08 100755 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -169,7 +169,6 @@ BOOL LLFolderViewItem::postBuild() // Destroys the object LLFolderViewItem::~LLFolderViewItem( void ) { - delete mViewModelItem; mViewModelItem = NULL; } @@ -473,8 +472,9 @@ void LLFolderViewItem::rename(const std::string& new_name) const std::string& LLFolderViewItem::getName( void ) const { - return getViewModelItem()->getName(); - } + static const std::string noName(""); + return getViewModelItem() ? getViewModelItem()->getName() : noName; +} // LLView functionality BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) @@ -1563,7 +1563,7 @@ BOOL LLFolderViewFolder::isRemovable() void LLFolderViewFolder::addItem(LLFolderViewItem* item) { if (item->getParentFolder()) -{ + { item->getParentFolder()->extractItem(item); } item->setParentFolder(this); @@ -1574,7 +1574,13 @@ void LLFolderViewFolder::addItem(LLFolderViewItem* item) item->setVisible(FALSE); addChild(item); - getViewModelItem()->addChild(item->getViewModelItem()); + + // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it + // Note: this happens when models are created before views or shared between views + if (!item->getViewModelItem()->hasParent()) + { + getViewModelItem()->addChild(item->getViewModelItem()); + } //TODO RN - make sort bubble up as long as parent Folder doesn't have anything matching sort criteria //// Traverse parent folders and update creation date and resort, if necessary @@ -1593,11 +1599,11 @@ void LLFolderViewFolder::addItem(LLFolderViewItem* item) // this is an internal method used for adding items to folders. void LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) - { +{ if (folder->mParentFolder) - { + { folder->mParentFolder->extractItem(folder); - } + } folder->mParentFolder = this; mFolders.push_back(folder); folder->setOrigin(0, 0); @@ -1607,9 +1613,15 @@ void LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) //folder->requestArrange(); //requestSort(); - addChild( folder ); - getViewModelItem()->addChild(folder->getViewModelItem()); + addChild(folder); + + // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it + // Note: this happens when models are created before views or shared between views + if (!folder->getViewModelItem()->hasParent()) + { + getViewModelItem()->addChild(folder->getViewModelItem()); } +} void LLFolderViewFolder::requestArrange() { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 7cbe70fb8b..7e37e06064 100755 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -87,7 +87,7 @@ protected: bool mLabelWidthDirty; S32 mLabelPaddingRight; LLFolderViewFolder* mParentFolder; - LLFolderViewModelItem* mViewModelItem; + LLPointer<LLFolderViewModelItem> mViewModelItem; LLFontGL::StyleFlags mLabelStyle; std::string mLabelSuffix; LLUIImagePtr mIcon, diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index c6030c9b71..7019857c0f 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -129,10 +129,11 @@ public: // This is am abstract base class that users of the folderview classes // would use to bridge the folder view with the underlying data -class LLFolderViewModelItem +class LLFolderViewModelItem : public LLRefCount { public: - virtual ~LLFolderViewModelItem( void ) {}; + LLFolderViewModelItem() { } + virtual ~LLFolderViewModelItem() { } virtual void update() {} //called when drawing virtual const std::string& getName() const = 0; @@ -201,6 +202,7 @@ public: virtual S32 getSortVersion() = 0; virtual void setSortVersion(S32 version) = 0; virtual void setParent(LLFolderViewModelItem* parent) = 0; + virtual bool hasParent() = 0; protected: @@ -331,6 +333,7 @@ public: protected: virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } + virtual bool hasParent() { return mParent != NULL; } S32 mSortVersion; bool mPassedFilter; diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index de0c65e24f..81212a9141 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -234,9 +234,9 @@ void LLConversationViewSession::toggleOpen() void LLConversationViewSession::selectItem() { - - LLConversationItem* item = dynamic_cast<LLConversationItem*>(mViewModelItem); - LLFloater* session_floater = LLIMConversation::getConversation(item->getUUID()); + LLFolderViewModelItem* item = mViewModelItem; + LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID(); + LLFloater* session_floater = LLIMConversation::getConversation(session_uuid); LLMultiFloater* host_floater = session_floater->getHost(); if (host_floater == mContainer) @@ -250,7 +250,7 @@ void LLConversationViewSession::selectItem() // Set the focus on the selected floater session_floater->setFocus(TRUE); // Store the active session - LLIMFloaterContainer::getInstance()->setSelectedSession(item->getUUID()); + LLIMFloaterContainer::getInstance()->setSelectedSession(session_uuid); LLFolderViewItem::selectItem(); @@ -272,8 +272,9 @@ 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 - LLConversationItem* item = dynamic_cast<LLConversationItem*>(mViewModelItem); - LLFloater* session_floater = LLIMConversation::getConversation(item->getUUID()); + LLFolderViewModelItem* item = mViewModelItem; + LLUUID session_uuid = dynamic_cast<LLConversationItem*>(item)->getUUID(); + LLFloater* session_floater = LLIMConversation::getConversation(session_uuid); if (session_floater && !session_floater->getHost() && !session_floater->isMinimized()) { @@ -431,6 +432,22 @@ void LLConversationViewParticipant::draw() 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); + + return arranged; +} + void LLConversationViewParticipant::selectItem() { LLConversationItem* vmi = this->getParentFolder() ? static_cast<LLConversationItem*>(this->getParentFolder()->getViewModelItem()) : NULL; @@ -506,7 +523,7 @@ void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask) S32 LLConversationViewParticipant::getLabelXPos() { - return mAvatarIcon->getRect().mRight + mIconPad; + return getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad; } // static diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 4d77a4ade0..d50e527007 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -131,6 +131,7 @@ protected: void initFromParams(const Params& params); BOOL postBuild(); /*virtual*/ void draw(); + /*virtual*/ S32 arrange(S32* width, S32* height); void onInfoBtnClick(); diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp index b687e18cae..920666ef90 100644 --- a/indra/newview/llimconversation.cpp +++ b/indra/newview/llimconversation.cpp @@ -49,7 +49,8 @@ LLIMConversation::LLIMConversation(const LLSD& session_id) , mTearOffBtn(NULL) , mCloseBtn(NULL) , mSessionID(session_id.asUUID()) - , mParticipantList(NULL) +// , mParticipantList(NULL) + , mConversationsRoot(NULL) , mChatHistory(NULL) , mInputEditor(NULL) , mInputEditorTopPad(0) @@ -73,11 +74,13 @@ LLIMConversation::LLIMConversation(const LLSD& session_id) LLIMConversation::~LLIMConversation() { + /* if (mParticipantList) { delete mParticipantList; mParticipantList = NULL; } + */ delete mRefreshTimer; } @@ -176,11 +179,39 @@ BOOL LLIMConversation::postBuild() mExpandCollapseBtn = getChild<LLButton>("expand_collapse_btn"); mExpandCollapseBtn->setClickedCallback(boost::bind(&LLIMConversation::onSlide, this)); - mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel"); - mTearOffBtn = getChild<LLButton>("tear_off_btn"); mTearOffBtn->setCommitCallback(boost::bind(&LLIMConversation::onTearOffClicked, this)); + mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel"); + + // Create a root view folder for all participants + LLConversationItem* base_item = new LLConversationItem(mConversationViewModel); + LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>()); + p.rect = LLRect(0, 0, getRect().getWidth(), 0); + p.parent_panel = mParticipantListPanel; + p.listener = base_item; + p.view_model = &mConversationViewModel; + p.root = NULL; + p.use_ellipses = true; + mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p); + mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // Add a scroller for the folder (participant) view + LLRect scroller_view_rect = mParticipantListPanel->getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams<LLFolderViewScrollContainer>()); + scroller_params.rect(scroller_view_rect); + LLScrollContainer* scroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params); + scroller->setFollowsAll(); + + // Insert that scroller into the panel widgets hierarchy and folder view + mParticipantListPanel->addChild(scroller); + scroller->addChild(mConversationsRoot); + mConversationsRoot->setScrollContainer(scroller); + mConversationsRoot->setFollowsAll(); + mConversationsRoot->addChild(mConversationsRoot->mStatusTextBox); + + mChatHistory = getChild<LLChatHistory>("chat_history"); mInputEditor = getChild<LLChatEntry>("chat_editor"); @@ -193,7 +224,7 @@ BOOL LLIMConversation::postBuild() setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE); - buildParticipantList(); + buildConversationViewParticipant(); updateHeaderAndToolbar(); @@ -216,15 +247,20 @@ BOOL LLIMConversation::postBuild() return result; } +LLParticipantList* LLIMConversation::getParticipantList() +{ + return dynamic_cast<LLParticipantList*>(LLIMFloaterContainer::getInstance()->getSessionModel(mSessionID)); +} + void LLIMConversation::draw() { LLTransientDockableFloater::draw(); if (mRefreshTimer->hasExpired()) { - if (mParticipantList) + if (getParticipantList()) { - mParticipantList->update(); + getParticipantList()->update(); } refresh(); @@ -314,30 +350,144 @@ void LLIMConversation::appendMessage(const LLChat& chat, const LLSD &args) } -void LLIMConversation::buildParticipantList() +void LLIMConversation::buildConversationViewParticipant() +{ + // Clear the widget list since we are rebuilding afresh from the model + conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); + while (widget_it != mConversationsWidgets.end()) + { + removeConversationViewParticipant(widget_it->first); + // Iterators are invalidated by erase so we need to pick begin again + widget_it = mConversationsWidgets.begin(); + } + + // Get the model list + LLParticipantList* item = getParticipantList(); + if (!item) + { + // Nothing to do if the model list is empty + return; + } + + // Create the participants widgets now + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); + while (current_participant_model != end_participant_model) + { + LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); + addConversationViewParticipant(participant_model); + current_participant_model++; + } +} + +void LLIMConversation::addConversationViewParticipant(LLConversationItem* participant_model) { - if (mIsNearbyChat) + // Check if the model already has an associated view + LLUUID uuid = participant_model->getUUID(); + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); + + // If not already present, create the participant view and attach it to the root, otherwise, just refresh it + if (widget) { - LLLocalSpeakerMgr* speaker_manager = LLLocalSpeakerMgr::getInstance(); - mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), mConversationViewModel, true, false); + updateConversationViewParticipant(uuid); // overkill? } else { - LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID); - // for group and ad-hoc chat we need to include agent into list - if(!mIsP2PChat && mSessionID.notNull() && speaker_manager) + LLConversationViewParticipant* participant_view = createConversationViewParticipant(participant_model); + mConversationsWidgets[uuid] = participant_view; + participant_view->addToFolder(mConversationsRoot); + participant_view->setVisible(TRUE); + refreshConversation(); + } +} + +void LLIMConversation::removeConversationViewParticipant(const LLUUID& participant_id) +{ + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); + if (widget) + { + mConversationsRoot->extractItem(widget); + delete widget; + mConversationsWidgets.erase(participant_id); + refreshConversation(); + } +} + +void LLIMConversation::updateConversationViewParticipant(const LLUUID& participant_id) +{ + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); + if (widget) + { + widget->refresh(); + refreshConversation(); + } +} + +void LLIMConversation::refreshConversation() +{ + // Debug : Check that all participant models do have a view (debug consistency check) + /* + LLParticipantList* item = getParticipantList(); + llinfos << "Merov debug : Start consistency check" << llendl; + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); + while (current_participant_model != end_participant_model) + { + LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); + if (participant_model != NULL) + { + LLUUID uuid = participant_model->getUUID(); + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); + if (!widget) + { + llinfos << "Merov debug : Consistency error! Couldn't find widget for " << participant_model->getName() << llendl; + } + else + { + llinfos << "Merov debug : Consistency check pass for " << participant_model->getName() << llendl; + } + } + else { - 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"), mConversationViewModel, true, false); + llinfos << "Merov debug : Consistency check, skip non participant child" << llendl; } + current_participant_model++; } - updateHeaderAndToolbar(); + llinfos << "Merov debug : End consistency check" << llendl; + */ + + conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); + while (widget_it != mConversationsWidgets.end()) + { + widget_it->second->refresh(); + widget_it->second->setVisible(TRUE); + ++widget_it; + } + mConversationViewModel.requestSortAll(); + mConversationsRoot->arrangeAll(); + mConversationsRoot->update(); +} + +// Copied from LLIMFloaterContainer::createConversationViewParticipant(). Refactor opportunity! +LLConversationViewParticipant* LLIMConversation::createConversationViewParticipant(LLConversationItem* item) +{ + LLRect panel_rect = mParticipantListPanel->getRect(); + + LLConversationViewParticipant::Params params; + params.name = item->getDisplayName(); + params.root = mConversationsRoot; + params.listener = item; + params.rect = LLRect (0, 24, panel_rect.getWidth(), 0); // *TODO: use conversation_view_participant.xml itemHeight value in lieu of 24 + params.tool_tip = params.name; + params.participant_id = item->getUUID(); + + return LLUICtrlFactory::create<LLConversationViewParticipant>(params); } void LLIMConversation::onSortMenuItemClicked(const LLSD& userdata) { // TODO: Check this code when sort order menu will be added. (EM) - if (!mParticipantList) + if (!getParticipantList()) { return; } @@ -346,7 +496,7 @@ void LLIMConversation::onSortMenuItemClicked(const LLSD& userdata) if (chosen_item == "sort_name") { - mParticipantList->setSortOrder(LLParticipantList::E_SORT_BY_NAME); + getParticipantList()->setSortOrder(LLParticipantList::E_SORT_BY_NAME); } } @@ -407,6 +557,12 @@ void LLIMConversation::hideOrShowTitle() floater_contents->setShape(contents_rect); } +void LLIMConversation::updateSessionName(const std::string& name) +{ + llinfos << "Merov debug : updateSessionName, name = " << name << llendl; + mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + name); +} + void LLIMConversation::hideAllStandardButtons() { for (S32 i = 0; i < BUTTON_COUNT; i++) @@ -565,6 +721,7 @@ void LLIMConversation::onTearOffClicked() initRectControl(); LLFloater::onClickTearOff(this); updateHeaderAndToolbar(); + refreshConversation(); } // static diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h index bff4cb4a31..cb306c4d8d 100644 --- a/indra/newview/llimconversation.h +++ b/indra/newview/llimconversation.h @@ -35,6 +35,7 @@ #include "lleventtimer.h" #include "llimview.h" #include "llconversationmodel.h" +#include "llconversationview.h" class LLPanelChatControlPanel; class LLChatEntry; @@ -79,6 +80,13 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); /*virtual*/ void setVisible(BOOL visible); + + // Handle the left hand participant list widgets + void addConversationViewParticipant(LLConversationItem* item); + void removeConversationViewParticipant(const LLUUID& participant_id); + void updateConversationViewParticipant(const LLUUID& participant_id); + void refreshConversation(); + void buildConversationViewParticipant(); protected: @@ -98,7 +106,6 @@ protected: // refresh a visual state of the Call button void updateCallBtnState(bool callIsActive); - void buildParticipantList(); void onSortMenuItemClicked(const LLSD& userdata); void hideOrShowTitle(); // toggle the floater's drag handle @@ -107,6 +114,9 @@ protected: /// Update floater header and toolbar buttons when hosted/torn off state is toggled. void updateHeaderAndToolbar(); + // Update the input field help text and other places that need the session name + virtual void updateSessionName(const std::string& name); + // set the enable/disable state for the Call button virtual void enableDisableCallBtn(); @@ -124,10 +134,16 @@ protected: LLIMModel::LLIMSession* mSession; - LLLayoutPanel* mParticipantListPanel; - LLParticipantList* mParticipantList; - LLUUID mSessionID; + // Participants list: model and view + LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item); + + LLUUID mSessionID; + LLLayoutPanel* mParticipantListPanel; // add the widgets to that see mConversationsListPanel + //LLParticipantList* mParticipantList; get this from the mConversationsItems for the moment + LLParticipantList* getParticipantList(); + conversations_widgets_map mConversationsWidgets; LLConversationViewModel mConversationViewModel; + LLFolderView* mConversationsRoot; LLChatHistory* mChatHistory; LLChatEntry* mInputEditor; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 3545b8ff18..607cdbd265 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -243,7 +243,6 @@ void LLIMFloater::initIMSession(const LLUUID& session_id) { mIsP2PChat = mSession->isP2PSessionType(); mSessionInitialized = mSession->mSessionInitialized; - mDialog = mSession->mType; } } @@ -281,7 +280,7 @@ void LLIMFloater::initIMFloater() else { std::string session_name(LLIMModel::instance().getName(mSessionID)); - updateSessionName(session_name, session_name); + updateSessionName(session_name); // For ad hoc conferences we should update the title with participants names. if ((IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID)) @@ -292,6 +291,8 @@ void LLIMFloater::initIMFloater() mParticipantsListRefreshConnection.disconnect(); } + // CHUI-441: We shouldn't have any avatar_list anymore... see floater_im_session.xml + // *TODO: Track and delete if not necessary anymore LLAvatarList* avatar_list = getChild<LLAvatarList>("speakers_list"); mParticipantsListRefreshConnection = avatar_list->setRefreshCompleteCallback( boost::bind(&LLIMFloater::onParticipantsListChanged, this, _1)); @@ -525,20 +526,21 @@ void LLIMFloater::onVoiceChannelStateChanged( updateCallBtnState(callIsActive); } -void LLIMFloater::updateSessionName(const std::string& ui_title, - const std::string& ui_label) +void LLIMFloater::updateSessionName(const std::string& name) { - mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + ui_label); - setTitle(ui_title); + LLIMConversation::updateSessionName(name); + setTitle(name); } void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { - // Use display name only for labels, as the extended name will be in the - // floater title + // Use display name for label + updateSessionName(av_name.mDisplayName); + + // Overwrite the floater title with the extended name std::string ui_title = av_name.getCompleteName(); - updateSessionName(ui_title, av_name.mDisplayName); + setTitle(ui_title); mTypingStart.setArg("[NAME]", ui_title); } @@ -550,35 +552,45 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl) return; } - bool all_names_resolved = true; std::vector<LLSD> participants_uuids; uuid_vec_t temp_uuids; // uuids vector for building the added participants' names string + LLUUID unfound_id; avatar_list->getValues(participants_uuids); - // Check whether we have all participants names in LLAvatarNameCache + // Check participants names in LLAvatarNameCache for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it) { const LLUUID& id = it->asUUID(); - temp_uuids.push_back(id); LLAvatarName av_name; if (!LLAvatarNameCache::get(id, &av_name)) { - 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; + // Keep the first not found avatar id + if (unfound_id.isNull()) + { + unfound_id = id; + } } + else + { + // Add the participant to the list of existing names + temp_uuids.push_back(id); + } } - if (all_names_resolved) + if (temp_uuids.size() != 0) { + // Build the session name and update it std::string ui_title; LLAvatarActions::buildResidentsString(temp_uuids, ui_title); - updateSessionName(ui_title, ui_title); + updateSessionName(ui_title); + } + + if (unfound_id.notNull()) + { + // If a name is not found in cache, request it and continue the process recursively + // until all ids are resolved into names. + LLAvatarNameCache::get(unfound_id, boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list)); } } @@ -784,8 +796,7 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id) if (mSessionID != im_session_id) { initIMSession(im_session_id); - - buildParticipantList(); + buildConversationViewParticipant(); } initIMFloater(); diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 6c69ed3462..39210546fb 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -138,8 +138,8 @@ private: /*virtual*/ void onClickCloseBtn(); - // Update the window title, input field help text, etc. - void updateSessionName(const std::string& ui_title, const std::string& ui_label); + // Update the window title and input field help text + /*virtual*/ void updateSessionName(const std::string& name); // For display name lookups for IM window titles void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index f85aa9a353..72e0f90f8c 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -98,8 +98,8 @@ LLIMFloaterContainer::~LLIMFloaterContainer() void LLIMFloaterContainer::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { - LLIMConversation::addToHost(session_id); addConversationListItem(session_id); + LLIMConversation::addToHost(session_id); } void LLIMFloaterContainer::sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) @@ -109,12 +109,13 @@ void LLIMFloaterContainer::sessionActivated(const LLUUID& session_id, const std: void LLIMFloaterContainer::sessionVoiceOrIMStarted(const LLUUID& session_id) { - LLIMConversation::addToHost(session_id); addConversationListItem(session_id); + LLIMConversation::addToHost(session_id); } void LLIMFloaterContainer::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) { + // CHUI-441 : We should do this *without* delete and recreate addConversationListItem(new_session_id, removeConversationListItem(old_session_id)); } @@ -384,7 +385,7 @@ bool LLIMFloaterContainer::onConversationModelEvent(const LLSD& event) // For debug only //std::ostringstream llsd_value; //llsd_value << LLSDOStreamer<LLSDNotationFormatter>(event) << std::endl; - //llinfos << "Merov debug : onConversationModelEvent, event = " << llsd_value.str() << llendl; + //llinfos << "LLIMFloaterContainer::onConversationModelEvent, event = " << llsd_value.str() << llendl; // end debug // Note: In conversations, the model is not responsible for creating the view, which is a good thing. This means that @@ -398,16 +399,18 @@ bool LLIMFloaterContainer::onConversationModelEvent(const LLSD& event) LLUUID session_id = event.get("session_uuid").asUUID(); LLUUID participant_id = event.get("participant_uuid").asUUID(); - LLConversationViewSession* session_view = dynamic_cast<LLConversationViewSession*>(mConversationsWidgets[session_id]); + LLConversationViewSession* session_view = dynamic_cast<LLConversationViewSession*>(get_ptr_in_map(mConversationsWidgets,session_id)); if (!session_view) { - // We skip events that are not associated to a session + // We skip events that are not associated with a session return false; } LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id); + LLIMConversation *conversation_floater = (session_id.isNull() ? (LLIMConversation*)(LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat")) : (LLIMConversation*)(LLIMFloater::findInstance(session_id))); if (type == "remove_participant") { + // Remove a participant view from the hierarchical conversation list if (participant_view) { session_view->extractItem(participant_view); @@ -415,35 +418,49 @@ bool LLIMFloaterContainer::onConversationModelEvent(const LLSD& event) session_view->refresh(); mConversationsRoot->arrangeAll(); } + // Remove a participant view from the conversation floater + if (conversation_floater) + { + conversation_floater->removeConversationViewParticipant(participant_id); + } } else if (type == "add_participant") { - if (!participant_view) + LLConversationItemSession* session_model = dynamic_cast<LLConversationItemSession*>(get_ptr_in_map(mConversationsItems,session_id)); + LLConversationItemParticipant* participant_model = (session_model ? session_model->findParticipant(participant_id) : NULL); + // Add a participant view to the hierarchical conversation list + if (!participant_view && session_model && participant_model) { - LLConversationItemSession* session_model = dynamic_cast<LLConversationItemSession*>(mConversationsItems[session_id]); - if (session_model) - { - LLConversationItemParticipant* participant_model = session_model->findParticipant(participant_id); - if (participant_model) - { - participant_view = createConversationViewParticipant(participant_model); - participant_view->addToFolder(session_view); - participant_view->setVisible(TRUE); - } - } - + participant_view = createConversationViewParticipant(participant_model); + participant_view->addToFolder(session_view); + participant_view->setVisible(TRUE); + } + // Add a participant view to the conversation floater + if (conversation_floater && participant_model) + { + conversation_floater->addConversationViewParticipant(participant_model); } } else if (type == "update_participant") { + // Update the participant view in the hierarchical conversation list if (participant_view) { participant_view->refresh(); } + // Update the participant view in the conversation floater + if (conversation_floater) + { + conversation_floater->updateConversationViewParticipant(participant_id); + } } else if (type == "update_session") { session_view->refresh(); + if (conversation_floater) + { + conversation_floater->refreshConversation(); + } } mConversationViewModel.requestSortAll(); @@ -1074,10 +1091,10 @@ void LLIMFloaterContainer::showConversation(const LLUUID& session_id) selectConversation(session_id); } -//Will select only the conversation item +// Will select only the conversation item void LLIMFloaterContainer::selectConversation(const LLUUID& session_id) { - LLFolderViewItem* widget = mConversationsWidgets[session_id]; + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,session_id); if (widget) { (widget->getRoot())->setSelection(widget, FALSE, FALSE); @@ -1087,63 +1104,55 @@ void LLIMFloaterContainer::selectConversation(const LLUUID& session_id) void LLIMFloaterContainer::setTimeNow(const LLUUID& session_id, const LLUUID& participant_id) { - conversations_items_map::iterator item_it = mConversationsItems.find(session_id); - if (item_it != mConversationsItems.end()) + LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(get_ptr_in_map(mConversationsItems,session_id)); + if (item) { - LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(item_it->second); - if (item) - { - item->setTimeNow(participant_id); - mConversationViewModel.requestSortAll(); - mConversationsRoot->arrangeAll(); - } + item->setTimeNow(participant_id); + mConversationViewModel.requestSortAll(); + mConversationsRoot->arrangeAll(); } } void LLIMFloaterContainer::setNearbyDistances() { - // Get the nearby chat session: that's the one with uuid nul in mConversationsItems - conversations_items_map::iterator item_it = mConversationsItems.find(LLUUID()); - if (item_it != mConversationsItems.end()) - { - LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(item_it->second); - if (item) + // Get the nearby chat session: that's the one with uuid nul + LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(get_ptr_in_map(mConversationsItems,LLUUID())); + if (item) + { + // Get the positions of the nearby avatars and their ids + std::vector<LLVector3d> positions; + uuid_vec_t avatar_ids; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + // Get the position of the agent + const LLVector3d& me_pos = gAgent.getPositionGlobal(); + // For each nearby avatar, compute and update the distance + int avatar_count = positions.size(); + for (int i = 0; i < avatar_count; i++) { - // Get the positions of the nearby avatars and their ids - std::vector<LLVector3d> positions; - uuid_vec_t avatar_ids; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); - // Get the position of the agent - const LLVector3d& me_pos = gAgent.getPositionGlobal(); - // For each nearby avatar, compute and update the distance - int avatar_count = positions.size(); - for (int i = 0; i < avatar_count; i++) - { - F64 dist = dist_vec_squared(positions[i], me_pos); - item->setDistance(avatar_ids[i],dist); - } - // Also does it for the agent itself - item->setDistance(gAgent.getID(),0.0f); - // Request resort - mConversationViewModel.requestSortAll(); - mConversationsRoot->arrangeAll(); + F64 dist = dist_vec_squared(positions[i], me_pos); + item->setDistance(avatar_ids[i],dist); } + // Also does it for the agent itself + item->setDistance(gAgent.getID(),0.0f); + // Request resort + mConversationViewModel.requestSortAll(); + mConversationsRoot->arrangeAll(); } } -void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWidgetSelected /*= false*/) +LLConversationItem* LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWidgetSelected /*= false*/) { bool is_nearby_chat = uuid.isNull(); - //Stores the display name for the conversation line item + // Stores the display name for the conversation line item std::string display_name = is_nearby_chat ? LLTrans::getString("NearbyChatLabel") : LLIMModel::instance().getName(uuid); - // Check if the item is not already in the list, exit if it is and has the same name and uuid (nothing to do) + // Check if the item is not already in the list, exit (nothing to do) // Note: this happens often, when reattaching a torn off conversation for instance conversations_items_map::iterator item_it = mConversationsItems.find(uuid); if (item_it != mConversationsItems.end()) { - return; + return item_it->second; } // Remove the conversation item that might exist already: it'll be recreated anew further down anyway @@ -1160,7 +1169,7 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWi if (!item) { llwarns << "Couldn't create conversation session item : " << display_name << llendl; - return; + return NULL; } item->renameItem(display_name); item->updateParticipantName(NULL); @@ -1186,6 +1195,12 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWi participant_view->addToFolder(widget); current_participant_model++; } + // Do that too for the conversation dialog + LLIMConversation *conversation_floater = (uuid.isNull() ? (LLIMConversation*)(LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat")) : (LLIMConversation*)(LLIMFloater::findInstance(uuid))); + if (conversation_floater) + { + conversation_floater->buildConversationViewParticipant(); + } // set the widget to minimized mode if conversations pane is collapsed widget->toggleMinimizedMode(mConversationsPane->isCollapsed()); @@ -1197,7 +1212,7 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWi mConversationsRoot->scrollToShowSelection(); } - return; + return item; } bool LLIMFloaterContainer::removeConversationListItem(const LLUUID& uuid, bool change_focus) @@ -1207,20 +1222,16 @@ bool LLIMFloaterContainer::removeConversationListItem(const LLUUID& uuid, bool c // the widget will also delete its listener bool isWidgetSelected = false; LLFolderViewItem* new_selection = NULL; - conversations_widgets_map::iterator widget_it = mConversationsWidgets.find(uuid); - if (widget_it != mConversationsWidgets.end()) + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); + if (widget) { - LLFolderViewItem* widget = widget_it->second; - if (widget) + isWidgetSelected = widget->isSelected(); + new_selection = mConversationsRoot->getNextFromChild(widget); + if(new_selection == NULL) { - isWidgetSelected = widget->isSelected(); - new_selection = mConversationsRoot->getNextFromChild(widget); - if(new_selection == NULL) - { - new_selection = mConversationsRoot->getPreviousFromChild(widget); - } - widget->destroyView(); + new_selection = mConversationsRoot->getPreviousFromChild(widget); } + widget->destroyView(); } // Suppress the conversation items and widgets from their respective maps @@ -1262,9 +1273,6 @@ LLConversationViewParticipant* LLIMFloaterContainer::createConversationViewParti LLRect panel_rect = mConversationsListPanel->getRect(); params.name = item->getDisplayName(); - //params.icon = bridge->getIcon(); - //params.icon_open = bridge->getOpenIcon(); - //params.creation_date = bridge->getCreationDate(); params.root = mConversationsRoot; params.listener = item; @@ -1272,7 +1280,8 @@ LLConversationViewParticipant* LLIMFloaterContainer::createConversationViewParti params.rect = LLRect (0, 24, panel_rect.getWidth(), 0); params.tool_tip = params.name; params.participant_id = item->getUUID(); - + params.folder_indentation = 42; + return LLUICtrlFactory::create<LLConversationViewParticipant>(params); } diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index 05ea94019b..a6f8677e46 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -91,6 +91,7 @@ public: LLConversationViewModel& getRootViewModel() { return mConversationViewModel; } LLUUID getSelectedSession() { return mSelectedSession; } void setSelectedSession(LLUUID sessionID) { mSelectedSession = sessionID; } + LLConversationItem* getSessionModel(const LLUUID& session_id) { return get_ptr_in_map(mConversationsItems,session_id); } private: typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t; @@ -151,7 +152,7 @@ private: // Conversation list implementation public: bool removeConversationListItem(const LLUUID& uuid, bool change_focus = true); - void addConversationListItem(const LLUUID& uuid, bool isWidgetSelected = false); + LLConversationItem* addConversationListItem(const LLUUID& uuid, bool isWidgetSelected = false); void setTimeNow(const LLUUID& session_id, const LLUUID& participant_id); void setNearbyDistances(); diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 2b542595c5..a889eb7933 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -14,7 +14,7 @@ width="394" can_resize="true" can_tear_off="false" - min_width="250" + min_width="340" min_height="190" positioning="relative"> <floater.string name="call_btn_start">Conv_toolbar_open_call</floater.string> @@ -157,19 +157,8 @@ min_width="115" width="150" height="310" - auto_resize="false"> - <avatar_list - color="DkGray2" - follows="all" - height="310" - ignore_online_status="true" - layout="topleft" - name="speakers_list" - opaque="false" - show_info_btn="true" - show_profile_btn="false" - show_speaking_indicator="false" - width="150" /> + user_resize="true" + auto_resize="true"> </layout_panel> <layout_panel default_tab_group="3" @@ -183,7 +172,8 @@ user_resize="true" auto_resize="true" visible="true" - name="left_part_holder"> + name="left_part_holder" + min_width="225"> <panel name="trnsAndChat_panel" follows="all" diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml index 0024decd4c..b83d9122f7 100755 --- a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml +++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <conversation_view_participant folder_arrow_image="Folder_Arrow" - folder_indentation="0" item_height="24" item_top_pad="0" selection_image="Rounded_Square" @@ -20,7 +19,6 @@ height="20" default_icon_name="Generic_Person" layout="topleft" - left="50" top="2" width="20" /> <info_button |