diff --git a/doc/contributions.txt b/doc/contributions.txt index 10c935f9bb..32dd3c1a2e 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -744,6 +744,7 @@ Marc Claridge Marc2 Sands Marianne McCann Marine Kelley + CHUIBUG-134 STORM-281 MartinRJ Fayray STORM-1844 diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index a28acade61..c4f36cabd0 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -598,6 +598,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch if(!fgi) { fgi = mFontFreetype->getGlyphInfo(wch); + + if (NULL == fgi) + { + return 0; + } } // account for glyphs that run beyond the starting point for the next glyphs diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 87f81e05ee..c8a8e9fcf7 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -597,11 +597,6 @@ bool LLGLManager::initGL() if (mGLVendor.substr(0,4) == "ATI ") { mGLVendorShort = "ATI"; - //BOOL mobile = FALSE; - //if (mGLRenderer.find("MOBILITY") != std::string::npos) - //{ - // mobile = TRUE; - //} mIsATI = TRUE; #if LL_WINDOWS && !LL_MESA_HEADLESS @@ -1489,9 +1484,7 @@ void assert_glerror() void clear_glerror() { - // Create or update texture to be used with this data - //GLenum error; - //error = glGetError(); + glGetError(); glGetError(); } diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index 8e9c6555c3..9e48dcde7e 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -169,6 +169,15 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { BOOL handled = FALSE; + // In the case of a chat entry, pressing RETURN when something is selected + // should NOT erase the selection (unlike a notecard, for example) + if (key == KEY_RETURN) + { + endOfDoc(); + startSelection(); + endSelection(); + } + LLTextEditor::handleSpecialKey(key, mask); switch(key) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 27dd7f5b32..09e27a264a 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1621,7 +1621,7 @@ void LLFloater::bringToFront( S32 x, S32 y ) // virtual -void LLFloater::setVisibleAndFrontmost(BOOL take_focus) +void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) { LLMultiFloater* hostp = getHost(); if (hostp) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index cb5bf28db3..4dba1e645f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -305,7 +305,7 @@ public: /*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override void setFrontmost(BOOL take_focus = TRUE); - virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE); + virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); // Defaults to false. virtual BOOL canSaveAs() const { return FALSE; } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index c20d863612..1cdddf0d5b 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -488,12 +488,12 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& { host->setMinimized(FALSE); instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->getVisible()) { instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); instance->setFocus(TRUE); } else @@ -506,16 +506,16 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& if (instance->isMinimized()) { instance->setMinimized(FALSE); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->isShown()) { instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->isFrontmost()) { - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else { diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index f8b84e39b5..5478e85e13 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -202,6 +202,14 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) LLLineEditor::~LLLineEditor() { mCommitOnFocusLost = FALSE; + + // Make sure no context menu linger around once the widget is deleted + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if (menu) + { + menu->hide(); + } + setContextMenu(NULL); // calls onCommit() while LLLineEditor still valid gFocusMgr.releaseFocusIfNeeded( this ); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 0c43a571b8..6f895ed939 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1483,16 +1483,22 @@ BOOL LLTabContainer::setTab(S32 which) for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { LLTabTuple* tuple = *iter; - if (!tuple) - continue; BOOL is_selected = ( tuple == selected_tuple ); - tuple->mButton->setUseEllipses(mUseTabEllipses); - tuple->mButton->setHAlign(mFontHalign); - tuple->mTabPanel->setVisible( is_selected ); -// tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. - tuple->mButton->setToggleState( is_selected ); - // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs - tuple->mButton->setTabStop( is_selected ); + + // Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list + if (tuple->mButton) + { + tuple->mButton->setUseEllipses(mUseTabEllipses); + tuple->mButton->setHAlign(mFontHalign); + tuple->mButton->setToggleState( is_selected ); + // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs + tuple->mButton->setTabStop( is_selected ); + } + if (tuple->mTabPanel) + { + tuple->mTabPanel->setVisible( is_selected ); + //tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. + } if (is_selected) { @@ -1563,8 +1569,7 @@ BOOL LLTabContainer::selectTabByName(const std::string& name) LLPanel* panel = getPanelByName(name); if (!panel) { - llwarns << "LLTabContainer::selectTabByName(" - << name << ") failed" << llendl; + llwarns << "LLTabContainer::selectTabByName(" << name << ") failed" << llendl; return FALSE; } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 49f0cb7dc8..409f1c7f10 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -359,7 +359,6 @@ void LLTextBase::drawSelectionBackground() S32 selection_left = llmin( mSelectionStart, mSelectionEnd ); S32 selection_right = llmax( mSelectionStart, mSelectionEnd ); - LLRect selection_rect = mVisibleTextRect; // Skip through the lines we aren't drawing. LLRect content_display_rect = getVisibleDocumentRect(); @@ -380,7 +379,7 @@ void LLTextBase::drawSelectionBackground() S32 segment_offset; getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset); - //LLRect selection_rect; + LLRect selection_rect; selection_rect.mLeft = line_iter->mRect.mLeft; selection_rect.mRight = line_iter->mRect.mLeft; selection_rect.mBottom = line_iter->mRect.mBottom; @@ -443,7 +442,7 @@ void LLTextBase::drawSelectionBackground() rect_it != selection_rects.end(); ++rect_it) { - //LLRect selection_rect = *rect_it; + LLRect selection_rect = *rect_it; selection_rect = *rect_it; selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); gl_rect_2d(selection_rect, selection_color); @@ -1087,7 +1086,14 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) { - mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + //Don't start triple click timer if user have clicked on scrollbar + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + if (x >= mVisibleTextRect.mLeft && x <= mVisibleTextRect.mRight + && y >= mVisibleTextRect.mBottom && y <= mVisibleTextRect.mTop) + { + mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleDoubleClick(x, y, mask)) { @@ -1912,6 +1918,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); + registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); @@ -2330,7 +2337,6 @@ const LLWString& LLTextBase::getWText() const S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line) const { // Figure out which line we're nearest to. - //LLRect visible_region = getVisibleDocumentRect(); LLRect doc_rect = mDocumentView->getRect(); S32 doc_y = local_y - doc_rect.mBottom; diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index fd872eca4b..f51aeaec13 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -24,7 +24,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - #include "linden_common.h" #include "llurlaction.h" @@ -32,6 +31,7 @@ #include "llwindow.h" #include "llurlregistry.h" + // global state for the callback functions LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback; LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback; @@ -158,16 +158,33 @@ void LLUrlAction::showProfile(std::string url) } } -void LLUrlAction::sendIM(std::string url) +std::string LLUrlAction::getUserID(std::string url) { LLURI uri(url); LLSD path_array = uri.pathArray(); + std::string id_str; if (path_array.size() == 4) { - std::string id_str = path_array.get(2).asString(); - if (LLUUID::validate(id_str)) - { - executeSLURL("secondlife:///app/agent/" + id_str + "/im"); - } + id_str = path_array.get(2).asString(); + } + return id_str; +} + +void LLUrlAction::sendIM(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/im"); } } + +void LLUrlAction::addFriend(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend"); + } +} + diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index f5f2ceba72..e31cd71a20 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -76,7 +76,9 @@ public: /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); + static std::string getUserID(std::string url); static void sendIM(std::string url); + static void addFriend(std::string url); /// specify the callbacks to enable this class's functionality typedef boost::function url_callback_t; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e1b86ae121..e3215aae70 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1584,6 +1584,28 @@ Value 0 + ChatLoadGroupMaxMembers + + Comment + Max number of active members we'll show up for an unresponsive group + Persist + 1 + Type + S32 + Value + 100 + + ChatLoadGroupTimeout + + Comment + Time we give the server to send group participants before we hit the server for group info (seconds) + Persist + 1 + Type + F32 + Value + 10.0 + ChatOnlineNotification Comment @@ -1694,17 +1716,6 @@ Value 131073 - NearbyChatIsNotTornOff - - Comment - saving torn-off state of the nearby chat between sessions - Persist - 1 - Type - Boolean - Value - 1 - CloseChatOnReturn Comment @@ -4314,6 +4325,17 @@ Boolean Value 1 + + IMShowContentPanel + + Comment + Show Toolbar and Body Panels + Persist + 1 + Type + Boolean + Value + 1 IgnoreAllNotifications diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 363713f2f4..ada374f892 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -281,6 +281,17 @@ Value 2 + NearbyChatIsNotTornOff + + Comment + saving torn-off state of the nearby chat between sessions + Persist + 1 + Type + Boolean + Value + 1 + ShowFavoritesOnLogin Comment diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index ce063a9887..b513a52ff7 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -193,7 +193,7 @@ static void on_avatar_name_cache_start_im(const LLUUID& agent_id, // static void LLAvatarActions::startIM(const LLUUID& id) { - if (id.isNull()) + if (id.isNull() || gAgent.getID() == id) return; LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_im, _1, _2)); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index c4f63d9256..53926c1fef 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -58,7 +58,7 @@ #include "llworld.h" #include "lluiconstants.h" #include "llstring.h" - +#include "llurlaction.h" #include "llviewercontrol.h" static LLDefaultChildRegistry::Register r("chat_history"); @@ -156,6 +156,17 @@ public: LLFloaterSidePanelContainer::showPanel("people", "panel_people", LLSD().with("people_panel_tab_name", "blocked_panel").with("blocked_to_select", getAvatarId())); } + else if (level == "map") + { + std::string url = "secondlife://" + mObjectData["slurl"].asString(); + LLUrlAction::showLocationOnMap(url); + } + else if (level == "teleport") + { + std::string url = "secondlife://" + mObjectData["slurl"].asString(); + LLUrlAction::teleportToLocation(url); + } + } void onAvatarIconContextMenuItemClicked(const LLSD& userdata) @@ -820,6 +831,15 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL body_message_params.font.style = "ITALIC"; } + if(chat.mChatType == CHAT_TYPE_WHISPER) + { + body_message_params.font.style = "ITALIC"; + } + else if(chat.mChatType == CHAT_TYPE_SHOUT) + { + body_message_params.font.style = "BOLD"; + } + bool message_from_log = chat.mChatStyle == CHAT_STYLE_HISTORY; // We graying out chat history by graying out messages that contains full date in a time string if (message_from_log) diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index e34130aff2..f50a19761a 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -427,14 +427,15 @@ LLChicletPanel::~LLChicletPanel() void LLChicletPanel::onMessageCountChanged(const LLSD& data) { - //LLUUID session_id = data["session_id"].asUUID(); - //S32 unread = data["participant_unread"].asInteger(); + // *TODO : we either suppress this method or return a value. Right now, it servers no purpose. + /* //LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); //if (im_floater && im_floater->getVisible() && im_floater->hasFocus()) //{ // unread = 0; //} + */ } void LLChicletPanel::objectChicletCallback(const LLSD& data) diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 4be169e267..7883e4cb89 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -28,9 +28,11 @@ #include "llagent.h" #include "llavatarnamecache.h" #include "llconversationlog.h" +#include "lldiriterator.h" #include "llnotificationsutil.h" #include "lltrans.h" +#include #include "boost/lexical_cast.hpp" const int CONVERSATION_LIFETIME = 30; // lifetime of LLConversation is 30 days by spec @@ -192,14 +194,17 @@ LLConversationLog::LLConversationLog() : mAvatarNameCacheConnection(), mLoggingEnabled(false) { - LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); - S32 log_mode = keep_log_ctrlp->getValue(); - keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); - if (log_mode > 0) + if(gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts")) { - loadFromFile(getFileName()); + LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); + S32 log_mode = keep_log_ctrlp->getValue(); + keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); + if (log_mode > 0) + { + loadFromFile(getFileName()); - enableLogging(log_mode); + enableLogging(log_mode); + } } } @@ -380,6 +385,36 @@ void LLConversationLog::cache() } } +void LLConversationLog::getListOfBackupLogs(std::vector& list_of_backup_logs) +{ + // get Users log directory + std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + dirname += gDirUtilp->getDirDelimiter(); + + // create search pattern + std::string pattern = "conversation.log.backup*"; + + LLDirIterator iter(dirname, pattern); + std::string filename; + while (iter.next(filename)) + { + list_of_backup_logs.push_back(gDirUtilp->add(dirname, filename)); + } +} + +void LLConversationLog::deleteBackupLogs() +{ + std::vector backup_logs; + getListOfBackupLogs(backup_logs); + + BOOST_FOREACH(const std::string& fullpath, backup_logs) + { + LLFile::remove(fullpath); + } +} + bool LLConversationLog::moveLog(const std::string &originDirectory, const std::string &targetDirectory) { @@ -575,5 +610,6 @@ void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD& mConversations.clear(); notifyObservers(); cache(); + deleteBackupLogs(); } } diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 58e698de25..265b1f0ef0 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -138,6 +138,8 @@ public: */ void cache(); bool moveLog(const std::string &originDirectory, const std::string &targetDirectory); + void getListOfBackupLogs(std::vector& list_of_backup_logs); + void deleteBackupLogs(); void onClearLog(); void onClearLogResponse(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 96b225b841..5ab108b39f 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -198,6 +198,8 @@ void LLConversationLogList::refresh() void LLConversationLogList::rebuildList() { + const LLConversation * selected_conversationp = getSelectedConversation(); + clear(); bool have_filter = !mNameFilter.empty(); @@ -214,7 +216,12 @@ void LLConversationLogList::rebuildList() addNewItem(&*iter); } - + + // try to restore selection of item + if (NULL != selected_conversationp) + { + selectItemByUUID(selected_conversationp->getSessionID()); + } bool logging_enabled = log_instance.getIsLoggingEnabled(); bool log_empty = log_instance.isLogEmpty(); @@ -238,8 +245,16 @@ void LLConversationLogList::rebuildList() void LLConversationLogList::onCustomAction(const LLSD& userdata) { + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp) + { + return; + } + const std::string command_name = userdata.asString(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_conversation_participant_id = selected_conversationp->getParticipantID(); + const LLUUID& selected_conversation_session_id = selected_conversationp->getSessionID(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); if ("im" == command_name) @@ -247,11 +262,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::startIM(selected_id); + LLAvatarActions::startIM(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::startIM(getSelectedConversation()->getSessionID()); + LLGroupActions::startIM(selected_conversation_session_id); break; default: @@ -263,11 +278,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::startCall(selected_id); + LLAvatarActions::startCall(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::startCall(getSelectedConversation()->getSessionID()); + LLGroupActions::startCall(selected_conversation_session_id); break; default: @@ -279,11 +294,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::showProfile(selected_id); + LLAvatarActions::showProfile(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::show(getSelectedConversation()->getSessionID()); + LLGroupActions::show(selected_conversation_session_id); break; default: @@ -292,52 +307,53 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) } else if ("chat_history" == command_name) { - const LLUUID& session_id = getSelectedConversation()->getSessionID(); - LLFloaterReg::showInstance("preview_conversation", session_id, true); + LLFloaterReg::showInstance("preview_conversation", selected_conversation_session_id, true); } else if ("offer_teleport" == command_name) { - LLAvatarActions::offerTeleport(selected_id); + LLAvatarActions::offerTeleport(selected_conversation_participant_id); } else if("add_friend" == command_name) { - if (!LLAvatarActions::isFriend(selected_id)) + if (!LLAvatarActions::isFriend(selected_conversation_participant_id)) { - LLAvatarActions::requestFriendshipDialog(selected_id); + LLAvatarActions::requestFriendshipDialog(selected_conversation_participant_id); } } else if("remove_friend" == command_name) { - if (LLAvatarActions::isFriend(selected_id)) + if (LLAvatarActions::isFriend(selected_conversation_participant_id)) { - LLAvatarActions::removeFriendDialog(selected_id); + LLAvatarActions::removeFriendDialog(selected_conversation_participant_id); } } else if ("invite_to_group" == command_name) { - LLAvatarActions::inviteToGroup(selected_id); + LLAvatarActions::inviteToGroup(selected_conversation_participant_id); } else if ("show_on_map" == command_name) { - LLAvatarActions::showOnMap(selected_id); + LLAvatarActions::showOnMap(selected_conversation_participant_id); } else if ("share" == command_name) { - LLAvatarActions::share(selected_id); + LLAvatarActions::share(selected_conversation_participant_id); } else if ("pay" == command_name) { - LLAvatarActions::pay(selected_id); + LLAvatarActions::pay(selected_conversation_participant_id); } else if ("block" == command_name) { - LLAvatarActions::toggleBlock(selected_id); + LLAvatarActions::toggleBlock(selected_conversation_participant_id); } } bool LLConversationLogList::isActionEnabled(const LLSD& userdata) { - if (numSelected() != 1) + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp || numSelected() > 1) { return false; } @@ -345,7 +361,7 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) const std::string command_name = userdata.asString(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == stype; bool is_group = LLIMModel::LLIMSession::GROUP_SESSION == stype; @@ -374,7 +390,7 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) { return is_p2p && LLAvatarActions::canOfferTeleport(selected_id); } - else if ("can_show_on_map") + else if ("can_show_on_map" == command_name) { return is_p2p && ((LLAvatarTracker::instance().isBuddyOnline(selected_id) && is_agent_mappable(selected_id)) || gAgent.isGodlike()); } @@ -384,9 +400,16 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) bool LLConversationLogList::isActionChecked(const LLSD& userdata) { + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp) + { + return false; + } + const std::string command_name = userdata.asString(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == getSelectedSessionType(); if ("is_blocked" == command_name) diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 009fce0a92..c74ce24872 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -139,6 +139,8 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32 items.push_back(std::string("remove_friend")); items.push_back(std::string("invite_to_group")); items.push_back(std::string("separator_invite_to_group")); + if (static_cast(mParent)->getType() == CONV_SESSION_NEARBY) + items.push_back(std::string("zoom_in")); items.push_back(std::string("map")); items.push_back(std::string("share")); items.push_back(std::string("pay")); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 74b348cd81..956abcd586 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -104,6 +104,15 @@ LLConversationViewSession::~LLConversationViewSession() 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(); @@ -115,12 +124,6 @@ void LLConversationViewSession::startFlashing() { mFlashStarted = true; mFlashTimer->startFlashing(); - - // flash chat toolbar button if scrolled out of sight (because flashing will not be visible) - if (mContainer->isScrolledOutOfSight(this)) - { - gToolBarView->flashCommand(LLCommandId("chat"), true); - } } } @@ -254,20 +257,38 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask ) //This node (conversation) was selected and a child (participant) was not if(result && getRoot()) { - if(getRoot()->getCurSelectedItem() == this) - { - LLConversationItem* item = dynamic_cast(getViewModelItem()); - LLUUID session_id = item? item->getUUID() : LLUUID(); - - LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance("im_container"); - im_container->flashConversationItemWidget(session_id,false); - im_container->selectConversationPair(session_id, false); - im_container->collapseMessagesPane(false); - } + selectConversationItem(); } + 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(getViewModelItem()); + LLUUID session_id = item? item->getUUID() : LLUUID(); + + LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance("im_container"); + im_container->flashConversationItemWidget(session_id,false); + im_container->selectConversationPair(session_id, false); + im_container->collapseMessagesPane(false); + } +} + // virtual S32 LLConversationViewSession::arrange(S32* width, S32* height) { diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 76d3d079ea..3eb2e63792 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -68,6 +68,7 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); /*virtual*/ S32 arrange(S32* width, S32* height); @@ -90,6 +91,7 @@ private: void onCurrentVoiceSessionChanged(const LLUUID& session_id); void startFlashing(); + void selectConversationItem(); LLPanel* mItemPanel; LLPanel* mCallIconLayoutPanel; diff --git a/indra/newview/lldelayedgestureerror.cpp b/indra/newview/lldelayedgestureerror.cpp index 80e7c9f1b2..ef1b644ad4 100644 --- a/indra/newview/lldelayedgestureerror.cpp +++ b/indra/newview/lldelayedgestureerror.cpp @@ -113,9 +113,11 @@ bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) } } - - LLNotificationsUtil::add(ent.mNotifyName, args); - + if(!LLApp::isQuitting()) + { + LLNotificationsUtil::add(ent.mNotifyName, args); + } + return true; } diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 22f35752bd..be20adeb8a 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -33,6 +33,7 @@ #include "lldir.h" #include "llerror.h" #include "llfloaterreg.h" +#include "llimview.h" #include "llnotifications.h" #include "llnotificationhandler.h" #include "llnotificationstorage.h" @@ -145,6 +146,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; + bool group_ad_hoc_toast_exists = false; + S32 toastSessionType; bool offerExists = false; for (LLSD::array_const_iterator notification_it = data.beginArray(); @@ -158,7 +161,20 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() if(notificationName == toastName) { - imToastExists = true; + toastSessionType = notification_params["payload"]["SESSION_TYPE"]; + if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) + { + imToastExists = true; + } + //Don't add group/ad-hoc messages to the notification system because + //this means the group/ad-hoc session has to be re-created + else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION + || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) + { + //Just allows opening the conversation log for group/ad-hoc messages upon startup + group_ad_hoc_toast_exists = true; + continue; + } } else if(notificationName == offerName) { @@ -197,7 +213,12 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() LLFloaterReg::showInstance("im_container"); } - if(imToastExists || offerExists) + if(group_ad_hoc_toast_exists) + { + LLFloaterReg::showInstance("conversation"); + } + + if(imToastExists || group_ad_hoc_toast_exists || offerExists) { make_ui_sound_deferred("UISndNewIncomingIMSession"); } diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index a0c386717b..5e0cd8ef78 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -53,6 +53,7 @@ #include "llcallbacklist.h" #include "llworld.h" #include "llsdserialize.h" +#include "llviewerobjectlist.h" // // LLFloaterIMContainer @@ -62,8 +63,7 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param mExpandCollapseBtn(NULL), mConversationsRoot(NULL), mConversationsEventStream("ConversationsEvents"), - mInitialized(false), - mIsFirstLaunch(false) + mInitialized(false) { mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2)); mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2)); @@ -114,6 +114,7 @@ void LLFloaterIMContainer::sessionAdded(const LLUUID& session_id, const std::str void LLFloaterIMContainer::sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { selectConversationPair(session_id, true); + collapseMessagesPane(false); } void LLFloaterIMContainer::sessionVoiceOrIMStarted(const LLUUID& session_id) @@ -225,10 +226,11 @@ BOOL LLFloaterIMContainer::postBuild() childSetAction("add_btn", boost::bind(&LLFloaterIMContainer::onAddButtonClicked, this)); collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed")); - collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed")); + collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed"), false); LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); mMicroChangedSignal = LLVoiceClient::getInstance()->MicroChangedCallback(boost::bind(&LLFloaterIMContainer::updateSpeakBtnState, this)); - if (! mMessagesPane->isCollapsed()) + + if (! mMessagesPane->isCollapsed() && ! mConversationsPane->isCollapsed()) { S32 conversations_panel_width = gSavedPerAccountSettings.getS32("ConversationsListPaneWidth"); LLRect conversations_panel_rect = mConversationsPane->getRect(); @@ -243,7 +245,6 @@ BOOL LLFloaterIMContainer::postBuild() mGeneralTitle = getTitle(); mInitialized = true; - mIsFirstLaunch = true; // Add callbacks: // We'll take care of view updates on idle @@ -278,12 +279,6 @@ void LLFloaterIMContainer::addFloater(LLFloater* floaterp, LLUUID session_id = floaterp->getKey(); - // Make sure the message panel is open when adding a floater or it stays mysteriously hidden - if (!mIsFirstLaunch) - { - collapseMessagesPane(false); - } - // Add the floater LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point); @@ -644,8 +639,6 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) return; } - mIsFirstLaunch = false; - // Save current width of panels before collapsing/expanding right pane. S32 conv_pane_width = mConversationsPane->getRect().getWidth(); S32 msg_pane_width = mMessagesPane->getRect().getWidth(); @@ -667,7 +660,7 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) // Make sure layout is updated before resizing conversation pane. mConversationsStack->updateLayout(); - updateState(collapse, gSavedPerAccountSettings.getS32("ConversationsMessagePaneWidth")); + reshapeFloaterAndSetResizeLimits(collapse, gSavedPerAccountSettings.getS32("ConversationsMessagePaneWidth")); if (!collapse) { @@ -676,7 +669,7 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) } } -void LLFloaterIMContainer::collapseConversationsPane(bool collapse) +void LLFloaterIMContainer::collapseConversationsPane(bool collapse, bool save_is_allowed /*=true*/) { if (mConversationsPane->isCollapsed() == collapse) { @@ -690,7 +683,7 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) // Save current width of Conversation panel before collapsing/expanding right pane. S32 conv_pane_width = mConversationsPane->getRect().getWidth(); - if (collapse) + if (collapse && save_is_allowed) { // Save the conversations pane width before collapsing it. gSavedPerAccountSettings.setS32("ConversationsListPaneWidth", conv_pane_width); @@ -700,10 +693,18 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) } mConversationsStack->collapsePanel(mConversationsPane, collapse); + if (!collapse) + { + // Make sure layout is updated before resizing conversation pane. + mConversationsStack->updateLayout(); + // Restore conversation's pane previous width. + mConversationsPane->setTargetDim(gSavedPerAccountSettings.getS32("ConversationsListPaneWidth")); + } - S32 delta_width = gSavedPerAccountSettings.getS32("ConversationsListPaneWidth") - mConversationsPane->getMinDim(); + S32 delta_width = + gSavedPerAccountSettings.getS32("ConversationsListPaneWidth") - mConversationsPane->getMinDim(); - updateState(collapse, delta_width); + reshapeFloaterAndSetResizeLimits(collapse, delta_width); for (conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); widget_it != mConversationsWidgets.end(); ++widget_it) @@ -723,21 +724,20 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) } } -void LLFloaterIMContainer::updateState(bool collapse, S32 delta_width) +void LLFloaterIMContainer::reshapeFloaterAndSetResizeLimits(bool collapse, S32 delta_width) { LLRect floater_rect = getRect(); floater_rect.mRight += ((collapse ? -1 : 1) * delta_width); // Set by_user = true so that reshaped rect is saved in user_settings. setShape(floater_rect, true); - updateResizeLimits(); - bool is_left_pane_expanded = !mConversationsPane->isCollapsed(); - bool is_right_pane_expanded = !mMessagesPane->isCollapsed(); + bool at_least_one_panel_is_expanded = + ! (mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed()); - setCanResize(is_left_pane_expanded || is_right_pane_expanded); - setCanMinimize(is_left_pane_expanded || is_right_pane_expanded); + setCanResize(at_least_one_panel_is_expanded); + setCanMinimize(at_least_one_panel_is_expanded); assignResizeLimits(); @@ -766,15 +766,9 @@ void LLFloaterIMContainer::assignResizeLimits() S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0; S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders; - if (is_conv_pane_expanded) - { - // Save the conversations pane width. - gSavedPerAccountSettings.setS32( - "ConversationsListPaneWidth", - mConversationsPane->getRect().getWidth()); - } - setResizeLimits(new_min_width, getMinHeight()); + + mConversationsStack->updateLayout(); } void LLFloaterIMContainer::onAddButtonClicked() @@ -1033,6 +1027,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec { LLAvatarActions::inviteToGroup(userID); } + else if ("zoom_in" == command) + { + handle_zoom_to_object(userID); + } else if ("map" == command) { LLAvatarActions::showOnMap(userID); @@ -1254,6 +1252,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v { return LLAvatarActions::canCall(); } + else if ("can_zoom_in" == item) + { + return is_single_select && gObjectList.findObject(single_id); + } else if ("can_show_on_map" == item) { return (is_single_select ? (LLAvatarTracker::instance().isBuddyOnline(single_id) && is_agent_mappable(single_id)) || gAgent.isGodlike() : false); @@ -1327,6 +1329,9 @@ void LLFloaterIMContainer::showConversation(const LLUUID& session_id) { setVisibleAndFrontmost(false); selectConversationPair(session_id, true); + + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id); + session_floater->restoreFloater(); } void LLFloaterIMContainer::clearAllFlashStates() @@ -1402,6 +1407,10 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool // Switch to the conversation floater that is being selected selectFloater(session_floater); } + else + { + showStub(true); + } } // Set the focus on the selected floater @@ -1412,7 +1421,7 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool session_floater->setMinimized(is_minimized); } } - + flashConversationItemWidget(session_id,false); return handled; } @@ -1880,6 +1889,9 @@ bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conve { llassert(conversation_item_widget != NULL); + // make sure the widget is actually in the right spot first + mConversationsRoot->arrange(NULL, NULL); + // check whether the widget is in the visible portion of the scroll container LLRect widget_rect; conversation_item_widget->localRectToOtherView(conversation_item_widget->getLocalRect(), &widget_rect, mConversationsRoot); @@ -1907,7 +1919,19 @@ BOOL LLFloaterIMContainer::handleKeyHere(KEY key, MASK mask ) return TRUE; } -bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next) +bool LLFloaterIMContainer::selectAdjacentConversation(bool focus_selected) +{ + bool selectedAdjacentConversation = selectNextorPreviousConversation(true, focus_selected); + + if(!selectedAdjacentConversation) + { + selectedAdjacentConversation = selectNextorPreviousConversation(false, focus_selected); + } + + return selectedAdjacentConversation; +} + +bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next, bool focus_selected) { if (mConversationsWidgets.size() > 1) { @@ -1928,12 +1952,7 @@ bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next) LLConversationItem* vmi = dynamic_cast(new_selection->getViewModelItem()); if (vmi) { - selectConversationPair(vmi->getUUID(), true); - LLFloater* floaterp = get_ptr_in_map(mSessions, getSelectedSession()); - if(floaterp && !floaterp->isTornOff()) - { - setFocus(TRUE); - } + selectConversationPair(vmi->getUUID(), true, focus_selected); return true; } } @@ -1957,11 +1976,6 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/) // Most of the time the user will never see this state. setMinimized(FALSE); - // Save the conversations pane width. - gSavedPerAccountSettings.setS32( - "ConversationsListPaneWidth", - mConversationsPane->getRect().getWidth()); - LLFloater::closeFloater(app_quitting); } diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index c84d4978ec..2cbc1e99f9 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -72,7 +72,8 @@ public: void selectNextConversationByID(const LLUUID& session_id); BOOL selectConversationPair(const LLUUID& session_id, bool select_widget, bool focus_floater = true); void clearAllFlashStates(); - bool selectNextorPreviousConversation(bool select_next); + bool selectAdjacentConversation(bool focus_selected); + bool selectNextorPreviousConversation(bool select_next, bool focus_selected = true); void expandConversation(); /*virtual*/ void tabClose(); @@ -128,9 +129,9 @@ private: void processParticipantsStyleUpdate(); void onSpeakButtonClicked(); - void collapseConversationsPane(bool collapse); + void collapseConversationsPane(bool collapse, bool save_is_allowed=true); - void updateState(bool collapse, S32 delta_width); + void reshapeFloaterAndSetResizeLimits(bool collapse, S32 delta_width); void onAddButtonClicked(); void onAvatarPicked(const uuid_vec_t& ids); @@ -173,7 +174,6 @@ private: LLLayoutStack* mConversationsStack; bool mInitialized; - bool mIsFirstLaunch; LLUUID mSelectedSession; std::string mGeneralTitle; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index dfaf4bbdd6..b287950c21 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -257,14 +257,25 @@ void LLFloaterIMNearbyChat::setVisible(BOOL visible) } } + +void LLFloaterIMNearbyChat::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) +{ + LLFloaterIMSessionTab::setVisibleAndFrontmost(take_focus, key); + + if(!isTornOff() && matchesKey(key)) + { + LLFloaterIMContainer::getInstance()->selectConversationPair(mSessionID, true, false); + } +} + // virtual void LLFloaterIMNearbyChat::onTearOffClicked() { LLFloaterIMSessionTab::onTearOffClicked(); // see CHUI-170: Save torn-off state of the nearby chat between sessions - BOOL in_the_multifloater = !isTornOff(); - gSavedSettings.setBOOL("NearbyChatIsNotTornOff", in_the_multifloater); + BOOL in_the_multifloater = (BOOL)getHost(); + gSavedPerAccountSettings.setBOOL("NearbyChatIsNotTornOff", in_the_multifloater); } @@ -279,6 +290,7 @@ void LLFloaterIMNearbyChat::onOpen(const LLSD& key) void LLFloaterIMNearbyChat::onClose(bool app_quitting) { // Override LLFloaterIMSessionTab::onClose() so that Nearby Chat is not removed from the conversation floater + LLFloaterIMSessionTab::restoreFloater(); onClickCloseBtn(); } @@ -286,8 +298,10 @@ void LLFloaterIMNearbyChat::onClose(bool app_quitting) void LLFloaterIMNearbyChat::onClickCloseBtn() { if (!isTornOff()) + { return; - onTearOffClicked(); + } + LLFloaterIMSessionTab::onTearOffClicked(); LLFloaterIMContainer *im_box = LLFloaterIMContainer::findInstance(); if (im_box) @@ -323,7 +337,7 @@ bool LLFloaterIMNearbyChat::isChatVisible() const if (im_box != NULL) { isVisible = - isChatMultiTab() && gSavedSettings.getBOOL("NearbyChatIsNotTornOff")? + isChatMultiTab() && gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff")? im_box->getVisible() && !im_box->isMinimized() : getVisible() && !isMinimized(); } @@ -334,6 +348,11 @@ bool LLFloaterIMNearbyChat::isChatVisible() const void LLFloaterIMNearbyChat::showHistory() { openFloater(); + if(!isMessagePaneExpanded()) + { + restoreFloater(); + setFocus(true); + } setResizeLimits(getMinWidth(), EXPANDED_MIN_HEIGHT); } @@ -406,6 +425,12 @@ BOOL LLFloaterIMNearbyChat::matchChatTypeTrigger(const std::string& in_str, std: void LLFloaterIMNearbyChat::onChatBoxKeystroke() { + LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); + if (im_box) + { + im_box->flashConversationItemWidget(mSessionID,false); + } + LLFirstUse::otherAvatarChatFirst(false); LLWString raw_text = mInputEditor->getWText(); @@ -714,7 +739,14 @@ void LLFloaterIMNearbyChat::startChat(const char* line) LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat"); if (nearby_chat) { - nearby_chat->show(); + if(!nearby_chat->isTornOff()) + { + nearby_chat->show(); + } + if(nearby_chat->isMinimized()) + { + nearby_chat->setMinimized(false); + } nearby_chat->setVisible(TRUE); nearby_chat->setFocus(TRUE); nearby_chat->mInputEditor->setFocus(TRUE); diff --git a/indra/newview/llfloaterimnearbychat.h b/indra/newview/llfloaterimnearbychat.h index 4ad37eb0c7..05b48cccb0 100644 --- a/indra/newview/llfloaterimnearbychat.h +++ b/indra/newview/llfloaterimnearbychat.h @@ -54,6 +54,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); /*virtual*/ void closeHostedFloater(); void loadHistory(); diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 8870d54cd2..7afcf288ce 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -559,12 +559,14 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("im_container"); - if( nearby_chat->hasFocus() + if(( nearby_chat->hasFocus() || im_box->hasFocus() || ( chat_msg.mSourceType == CHAT_SOURCE_AGENT && gSavedSettings.getBOOL("UseChatBubbles") ) || mChannel.isDead() - || !mChannel.get()->getShowToasts() ) // to prevent toasts in Do Not Disturb mode + || !mChannel.get()->getShowToasts() ) + && nearby_chat->isMessagePaneExpanded()) + // to prevent toasts in Do Not Disturb mode return;//no need in toast if chat is visible or if bubble chat is enabled // arrange a channel on a screen @@ -606,7 +608,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, //Don't show nearby toast, if conversation is visible but not focused LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(LLUUID()); - if (session_floater + if (session_floater && session_floater->isMessagePaneExpanded() && session_floater->isInVisibleChain() && !session_floater->isMinimized() && !(session_floater->getHost() && session_floater->getHost()->isMinimized())) { @@ -614,7 +616,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, } //Will show toast when chat preference is set - if(gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") + if((gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") || !session_floater->isMessagePaneExpanded()) { // Add a nearby chat toast. LLUUID id; diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 0b4251aa29..0b1e47dbae 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -618,7 +618,7 @@ void LLFloaterIMSession::onClose(bool app_quitting) // Last change: // EXT-3516 X Button should end IM session, _ button should hide gIMMgr->leaveSession(mSessionID); - + LLFloaterIMSessionTab::restoreFloater(); // Clean up the conversation *after* the session has been ended LLFloaterIMSessionTab::onClose(app_quitting); } @@ -892,6 +892,11 @@ void LLFloaterIMSession::onInputEditorFocusLost(LLFocusableElement* caller, void void LLFloaterIMSession::onInputEditorKeystroke(LLTextEditor* caller, void* userdata) { LLFloaterIMSession* self = (LLFloaterIMSession*)userdata; + LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); + if (im_box) + { + im_box->flashConversationItemWidget(self->mSessionID,false); + } std::string text = self->mInputEditor->getText(); // Deleting all text counts as stopping typing. diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index d3fcfbbc56..5df1a382cd 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -61,6 +61,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) , mRefreshTimer(new LLTimer()) , mIsHostAttached(false) , mHasVisibleBeenInitialized(false) + , mIsParticipantListExpanded(true) { setAutoFocus(FALSE); mSession = LLIMModel::getInstance()->findIMSession(mSessionID); @@ -169,7 +170,7 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id) conversp->setHostAttached(true); if (!conversp->isNearbyChat() - || gSavedSettings.getBOOL("NearbyChatIsNotTornOff")) + || gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff")) { floater_container->addFloater(conversp, false, LLTabContainer::RIGHT_OF_CURRENT); } @@ -180,6 +181,7 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id) // LLFloater::mLastHostHandle = floater_container (a "future" host) conversp->setHost(floater_container); conversp->setHost(NULL); + conversp->forceReshape(); } // Added floaters share some state (like sort order) with their host @@ -192,19 +194,28 @@ BOOL LLFloaterIMSessionTab::postBuild() { BOOL result; + mBodyStack = getChild("main_stack"); + + mCloseBtn = getChild("close_btn"); mCloseBtn->setCommitCallback(boost::bind(&LLFloater::onClickClose, this)); mExpandCollapseBtn = getChild("expand_collapse_btn"); mExpandCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onSlide, this)); + mExpandCollapseLineBtn = getChild("minz_btn"); + mExpandCollapseLineBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onCollapseToLine, this)); + mTearOffBtn = getChild("tear_off_btn"); mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this)); mGearBtn = getChild("gear_btn"); mParticipantListPanel = getChild("speakers_list_panel"); - + mToolbarPanel = getChild("toolbar_panel"); + mContentPanel = getChild("body_panel"); + mInputButtonPanel = getChild("input_button_layout_panel"); + mInputButtonPanel->setVisible(false); // 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); @@ -231,7 +242,7 @@ BOOL LLFloaterIMSessionTab::postBuild() setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE); mSaveRect = isNearbyChat() - && !gSavedSettings.getBOOL("NearbyChatIsNotTornOff"); + && !gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff"); initRectControl(); if (isChatMultiTab()) @@ -253,6 +264,7 @@ BOOL LLFloaterIMSessionTab::postBuild() p.root = NULL; p.use_ellipses = true; p.options_menu = "menu_conversation.xml"; + p.name = "root"; mConversationsRoot = LLUICtrlFactory::create(p); mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); // Attach that root to the scroller @@ -261,6 +273,8 @@ BOOL LLFloaterIMSessionTab::postBuild() mConversationsRoot->setFollowsAll(); mConversationsRoot->addChild(mConversationsRoot->mStatusTextBox); + setMessagePaneExpanded(true); + buildConversationViewParticipant(); refreshConversation(); @@ -268,6 +282,12 @@ BOOL LLFloaterIMSessionTab::postBuild() mRefreshTimer->setTimerExpirySec(0); mRefreshTimer->start(); initBtns(); + + if (mIsParticipantListExpanded != (bool)gSavedSettings.getBOOL("IMShowControlPanel")) + { + LLFloaterIMSessionTab::onSlide(this); + } + return result; } @@ -324,13 +344,6 @@ void LLFloaterIMSessionTab::onFocusReceived() } LLTransientDockableFloater::onFocusReceived(); - - LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance("im_container"); - if (container) - { - container->selectConversationPair(mSessionID, true); - container->showStub(! getHost()); - } } void LLFloaterIMSessionTab::onFocusLost() @@ -644,11 +657,12 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar() // Participant list should be visible only in torn off floaters. bool is_participant_list_visible = !is_not_torn_off - && gSavedSettings.getBOOL("IMShowControlPanel") + && mIsParticipantListExpanded && !mIsP2PChat; mParticipantListPanel->setVisible(is_participant_list_visible); + // Display collapse image (<<) if the floater is hosted // or if it is torn off but has an open control panel. bool is_expanded = is_not_torn_off || is_participant_list_visible; @@ -672,6 +686,7 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar() mTearOffBtn->setImageOverlay(getString(is_not_torn_off? "tear_off_icon" : "return_icon")); mTearOffBtn->setToolTip(getString(is_not_torn_off? "tooltip_to_separate_window" : "tooltip_to_main_window")); + mCloseBtn->setVisible(is_not_torn_off && !mIsNearbyChat); enableDisableCallBtn(); @@ -775,14 +790,70 @@ void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self) // Expand/collapse the IM control panel self->mParticipantListPanel->setVisible(expand); - - gSavedSettings.setBOOL("IMShowControlPanel", expand); - + gSavedSettings.setBOOL("IMShowControlPanel", expand); + self->mIsParticipantListExpanded = expand; self->mExpandCollapseBtn->setImageOverlay(self->getString(expand ? "collapse_icon" : "expand_icon")); } } } +void LLFloaterIMSessionTab::onCollapseToLine(LLFloaterIMSessionTab* self) +{ + LLFloaterIMContainer* host_floater = dynamic_cast(self->getHost()); + if (!host_floater) + { + bool expand = self->isMessagePaneExpanded(); + self->mExpandCollapseLineBtn->setImageOverlay(self->getString(expand ? "collapseline_icon" : "expandline_icon")); + self->mContentPanel->setVisible(!expand); + self->mToolbarPanel->setVisible(!expand); + self->reshapeFloater(expand); + self->setMessagePaneExpanded(!expand); + } +} + +void LLFloaterIMSessionTab::reshapeFloater(bool collapse) +{ + LLRect floater_rect = getRect(); + + if(collapse) + { + mFloaterHeight = floater_rect.getHeight(); + S32 height = mContentPanel->getRect().getHeight() + mToolbarPanel->getRect().getHeight(); + floater_rect.mTop -= height; + enableResizeCtrls(true, true, false); + } + else + { + floater_rect.mTop = floater_rect.mBottom + mFloaterHeight; + enableResizeCtrls(true, true, true); + + } + + setShape(floater_rect, true); + mBodyStack->updateLayout(); + +} + +void LLFloaterIMSessionTab::restoreFloater() +{ + if(!isMessagePaneExpanded()) + { + if(isMinimized()) + { + setMinimized(false); + } + mContentPanel->setVisible(true); + mToolbarPanel->setVisible(true); + LLRect floater_rect = getRect(); + floater_rect.mTop = floater_rect.mBottom + mFloaterHeight; + setShape(floater_rect, true); + mBodyStack->updateLayout(); + mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon")); + setMessagePaneExpanded(true); + enableResizeCtrls(true, true, true); + } +} + /*virtual*/ void LLFloaterIMSessionTab::onOpen(const LLSD& key) { @@ -792,19 +863,33 @@ void LLFloaterIMSessionTab::onOpen(const LLSD& key) // Show the messages pane when opening a floater hosted in the Conversations host_floater->collapseMessagesPane(false); } + + mInputButtonPanel->setVisible(isTornOff()); } void LLFloaterIMSessionTab::onTearOffClicked() { - setFollows(isTornOff()? FOLLOWS_ALL : FOLLOWS_NONE); + restoreFloater(); + setFollows(isTornOff()? FOLLOWS_ALL : FOLLOWS_NONE); mSaveRect = isTornOff(); initRectControl(); LLFloater::onClickTearOff(this); + LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance("im_container"); + if (isTornOff()) { + container->selectAdjacentConversation(false); forceReshape(); } + //Upon re-docking the torn off floater, select the corresponding conversation line item + else + { + container->selectConversation(mSessionID); + + } + mInputButtonPanel->setVisible(isTornOff()); + refreshConversation(); updateGearBtn(); } diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index d55b021df7..f22e2b5744 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -98,6 +98,9 @@ public: LLConversationItem* getCurSelectedViewModelItem(); void forceReshape(); virtual BOOL handleKeyHere( KEY key, MASK mask ); + bool isMessagePaneExpanded(){return mMessagePaneExpanded;} + void setMessagePaneExpanded(bool expanded){mMessagePaneExpanded = expanded;} + void restoreFloater(); protected: @@ -111,6 +114,8 @@ protected: bool onIMShowModesMenuItemCheck(const LLSD& userdata); bool onIMShowModesMenuItemEnable(const LLSD& userdata); static void onSlide(LLFloaterIMSessionTab *self); + static void onCollapseToLine(LLFloaterIMSessionTab *self); + void reshapeFloater(bool collapse); // refresh a visual state of the Call button void updateCallBtnState(bool callIsActive); @@ -139,13 +144,21 @@ protected: bool mIsNearbyChat; bool mIsP2PChat; + bool mMessagePaneExpanded; + bool mIsParticipantListExpanded; + + LLIMModel::LLIMSession* mSession; // Participants list: model and view LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item); LLUUID mSessionID; + LLLayoutStack* mBodyStack; LLLayoutPanel* mParticipantListPanel; // add the widgets to that see mConversationsListPanel + LLLayoutPanel* mContentPanel; + LLLayoutPanel* mToolbarPanel; + LLLayoutPanel* mInputButtonPanel; LLParticipantList* getParticipantList(); conversations_widgets_map mConversationsWidgets; LLConversationViewModel mConversationViewModel; @@ -157,11 +170,14 @@ protected: LLChatEntry* mInputEditor; int mInputEditorTopPad; // padding between input field and chat history + LLButton* mExpandCollapseLineBtn; LLButton* mExpandCollapseBtn; LLButton* mTearOffBtn; LLButton* mCloseBtn; LLButton* mGearBtn; + S32 mFloaterHeight; + private: // Handling selection and contextual menu diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3f8c23ba83..a28af2101b 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -443,6 +443,8 @@ BOOL LLFloaterPreference::postBuild() std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); setCacheLocation(cache_location); + getChild("log_path_string")->setEnabled(FALSE); // make it read-only but selectable + getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); getChild("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); @@ -1572,7 +1574,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im getChildView("send_im_to_email")->setEnabled(TRUE); getChild("send_im_to_email")->setValue(im_via_email); getChildView("favorites_on_login_check")->setEnabled(TRUE); - getChildView("log_path_string")->setEnabled(FALSE);// LineEditor becomes readonly in this case. getChildView("log_path_button")->setEnabled(TRUE); getChildView("chat_font_size")->setEnabled(TRUE); } @@ -1667,7 +1668,10 @@ void LLFloaterPreference::onClickActionChange() void LLFloaterPreference::onDeleteTranscripts() { - LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", LLSD(), LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); + LLSD args; + args["FOLDER"] = gDirUtilp->getUserName(); + + LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); } void LLFloaterPreference::onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ee487e110d..b379939cfa 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -154,6 +154,7 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id, args["FROM"] = av_name.getCompleteName(); args["FROM_ID"] = msg["from_id"]; args["SESSION_ID"] = msg["session_id"]; + args["SESSION_TYPE"] = msg["session_type"]; LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } @@ -199,13 +200,13 @@ void on_new_message(const LLSD& msg) // execution of the action LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("im_container"); - - if (im_box->isFrontmost() && im_box->getSelectedSession() == session_id) + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); + + if (im_box->isFrontmost() && im_box->getSelectedSession() == session_id + && !(session_floater->getHost() ? im_box->isMinimized() : session_floater->isMinimized())) { return; } - - LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); //session floater not focused (visible or not) bool session_floater_not_focused = session_floater && !session_floater->hasFocus(); @@ -226,17 +227,18 @@ void on_new_message(const LLSD& msg) && !session_floater->isMinimized() && !(session_floater->getHost() && session_floater->getHost()->isMinimized()); - if ("toast" == action && !session_floater_is_open) + bool conversation_floater_collapsed = !session_floater->isMessagePaneExpanded(); + if (("toast" == action && !session_floater_is_open) || conversation_floater_collapsed) { //User is not focused on conversation containing the message - if(session_floater_not_focused) + if(session_floater_not_focused || conversation_floater_collapsed) { if(!LLMuteList::getInstance()->isMuted(participant_id)) { im_box->flashConversationItemWidget(session_id, true); } //The conversation floater isn't focused/open - if(conversation_floater_not_focused) + if(conversation_floater_not_focused || conversation_floater_collapsed) { if(!LLMuteList::getInstance()->isMuted(participant_id) && !gAgent.isDoNotDisturb()) @@ -285,6 +287,24 @@ void on_new_message(const LLSD& msg) { //Surface conversations floater LLFloaterReg::showInstance("im_container"); + im_box->collapseMessagesPane(false); + if (session_floater) + { + if (session_floater->getHost()) + { + if (NULL != im_box && im_box->isMinimized()) + { + LLFloater::onClickMinimize(im_box); + } + } + else + { + if (session_floater->isMinimized()) + { + LLFloater::onClickMinimize(session_floater); + } + } + } } //If in DND mode, allow notification to be stored so upon DND exit @@ -636,8 +656,7 @@ void LLIMModel::LLIMSession::loadHistory() LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const { - return get_if_there(mId2SessionMap, session_id, - (LLIMModel::LLIMSession*) NULL); + return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); } //*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code @@ -990,6 +1009,7 @@ bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, co arg["from"] = from; arg["from_id"] = from_id; arg["time"] = LLLogChat::timestamp(false); + arg["session_type"] = session->mSessionType; mNewMsgSignal(arg); return true; @@ -2638,7 +2658,7 @@ void LLIMMgr::addMessage( if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) { // Evaluate if we need to skip this message when that setting is true (default is false) - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... skip_message &= !session->isGroupSessionType(); // Do not skip group chats... skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself @@ -2654,7 +2674,7 @@ void LLIMMgr::addMessage( { LLFloaterReg::showInstance("im_container"); LLFloaterReg::getTypedInstance("im_container")-> - flashConversationItemWidget(session_id, true); + flashConversationItemWidget(new_session_id, true); } } @@ -2809,7 +2829,7 @@ LLUUID LLIMMgr::addSession( } } - bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); + bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); //works only for outgoing ad-hoc sessions if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 448100c5d6..2d7454b636 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -444,7 +444,7 @@ std::string LLLogChat::oldLogFileName(std::string filename) } // static -void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_transcriptions) +void LLLogChat::findTranscriptFiles(std::string pattern, std::vector& list_of_transcriptions) { // get Users log directory std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); @@ -452,9 +452,6 @@ void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_trans // add final OS dependent delimiter dirname += gDirUtilp->getDirDelimiter(); - // create search pattern - std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; - LLDirIterator iter(dirname, pattern); std::string filename; while (iter.next(filename)) @@ -490,6 +487,22 @@ void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_trans } } +// static +void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_transcriptions) +{ + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; + findTranscriptFiles(pattern, list_of_transcriptions); +} + +// static +void LLLogChat::getListOfTranscriptBackupFiles(std::vector& list_of_transcriptions) +{ + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION + ".backup*"; + findTranscriptFiles(pattern, list_of_transcriptions); +} + //static boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_signal_t::slot_type& cb) { @@ -581,6 +594,7 @@ void LLLogChat::deleteTranscripts() { std::vector list_of_transcriptions; getListOfTranscriptFiles(list_of_transcriptions); + getListOfTranscriptBackupFiles(list_of_transcriptions); BOOST_FOREACH(const std::string& fullpath, list_of_transcriptions) { diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 784786a565..e819f00dd9 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -49,7 +49,9 @@ public: const std::string& from, const LLUUID& from_id, const std::string& line); + static void findTranscriptFiles(std::string pattern, std::vector& list_of_transcriptions); static void getListOfTranscriptFiles(std::vector& list); + static void getListOfTranscriptBackupFiles(std::vector& list_of_transcriptions); static void loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params = LLSD()); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index c5283404f1..4138558bad 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -611,10 +611,10 @@ BOOL LLPanelPeople::postBuild() mGroupList->setNoItemsMsg(getString("no_groups_msg")); mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); - mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); + mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); + mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); @@ -1143,7 +1143,10 @@ void LLPanelPeople::onGearButtonClicked(LLUICtrl* btn) uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); // Spawn at bottom left corner of the button. - LLPanelPeopleMenus::gNearbyMenu.show(btn, selected_uuids, 0, 0); + if (getActiveTabName() == NEARBY_TAB_NAME) + LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); + else + LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); } void LLPanelPeople::onImButtonClicked() diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 47d6b49a50..49f7361c4a 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -39,15 +39,18 @@ #include "llcallingcard.h" // for LLAvatarTracker #include "lllogchat.h" #include "llviewermenu.h" // for gMenuHolder +#include "llconversationmodel.h" +#include "llviewerobjectlist.h" namespace LLPanelPeopleMenus { -NearbyMenu gNearbyMenu; +PeopleContextMenu gPeopleContextMenu; +NearbyPeopleContextMenu gNearbyPeopleContextMenu; -//== NearbyMenu =============================================================== +//== PeopleContextMenu =============================================================== -LLContextMenu* NearbyMenu::createMenu() +LLContextMenu* PeopleContextMenu::createMenu() { // set up the callbacks for all of the avatar menu items LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -64,7 +67,8 @@ LLContextMenu* NearbyMenu::createMenu() registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id)); registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id)); registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id)); - registrar.add("Avatar.OfferTeleport", boost::bind(&NearbyMenu::offerTeleport, this)); + registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this)); + registrar.add("Avatar.ZoomIn", boost::bind(&handle_zoom_to_object, id)); registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id)); registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id)); registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id)); @@ -72,33 +76,72 @@ LLContextMenu* NearbyMenu::createMenu() registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id)); registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id)); - enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); - enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2)); + enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); + enable_registrar.add("Avatar.CheckItem", boost::bind(&PeopleContextMenu::checkContextMenuItem, this, _2)); // create the context menu from the XUI menu = createFromFile("menu_people_nearby.xml"); + buildContextMenu(*menu, 0x0); } else { // Set up for multi-selected People // registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, mUUIDs)); // *TODO: unimplemented - registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startConference, mUUIDs, LLUUID::null)); - registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startAdhocCall, mUUIDs, LLUUID::null)); - registrar.add("Avatar.OfferTeleport", boost::bind(&NearbyMenu::offerTeleport, this)); - registrar.add("Avatar.RemoveFriend",boost::bind(&LLAvatarActions::removeFriendsDialog, mUUIDs)); + registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startConference, mUUIDs, LLUUID::null)); + registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startAdhocCall, mUUIDs, LLUUID::null)); + registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this)); + registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendsDialog, mUUIDs)); // registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::startIM, mUUIDs)); // *TODO: unimplemented - // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented - enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); + // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented + + enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); // create the context menu from the XUI menu = createFromFile("menu_people_nearby_multiselect.xml"); + buildContextMenu(*menu, ITEM_IN_MULTI_SELECTION); } return menu; } -bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) +void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) +{ + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("add_friends")); + items.push_back(std::string("remove_friends")); + items.push_back(std::string("im")); + items.push_back(std::string("call")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); + } + + hide_context_entries(menu, items, disabled_items); +} + +bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) { if(gAgent.getID() == mUUIDs.front()) { @@ -170,6 +213,12 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) { return LLAvatarActions::canCall(); } + else if (item == std::string("can_zoom_in")) + { + const LLUUID& id = mUUIDs.front(); + + return gObjectList.findObject(id); + } else if (item == std::string("can_show_on_map")) { const LLUUID& id = mUUIDs.front(); @@ -193,7 +242,7 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) return false; } -bool NearbyMenu::checkContextMenuItem(const LLSD& userdata) +bool PeopleContextMenu::checkContextMenuItem(const LLSD& userdata) { std::string item = userdata.asString(); const LLUUID& id = mUUIDs.front(); @@ -206,11 +255,50 @@ bool NearbyMenu::checkContextMenuItem(const LLSD& userdata) return false; } -void NearbyMenu::offerTeleport() +void PeopleContextMenu::offerTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(), // so we have to use a wrapper. LLAvatarActions::offerTeleport(mUUIDs); } +//== NearbyPeopleContextMenu =============================================================== + +void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) +{ + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("add_friends")); + items.push_back(std::string("remove_friends")); + items.push_back(std::string("im")); + items.push_back(std::string("call")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("zoom_in")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); + } + + hide_context_entries(menu, items, disabled_items); +} + } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index d51eaec716..0a1dcef303 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -33,19 +33,33 @@ namespace LLPanelPeopleMenus { /** - * Menu used in the nearby people list. + * Menu used in the people lists. */ -class NearbyMenu : public LLListContextMenu +class PeopleContextMenu : public LLListContextMenu { public: /*virtual*/ LLContextMenu* createMenu(); + +protected: + virtual void buildContextMenu(class LLMenuGL& menu, U32 flags); + private: bool enableContextMenuItem(const LLSD& userdata); bool checkContextMenuItem(const LLSD& userdata); void offerTeleport(); }; -extern NearbyMenu gNearbyMenu; +/** + * Menu used in the nearby people list. + */ +class NearbyPeopleContextMenu : public PeopleContextMenu +{ +protected: + /*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags); +}; + +extern PeopleContextMenu gPeopleContextMenu; +extern NearbyPeopleContextMenu gNearbyPeopleContextMenu; } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 2c9da8cfb8..a4582071e8 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -38,6 +38,8 @@ #include "llvoavatar.h" #include "llworld.h" +extern LLControlGroup gSavedSettings; + const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); @@ -311,6 +313,7 @@ LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : mModerateModeHandledFirstTime(false), mSpeakerListUpdated(false) { + mGetListTime.reset(); static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); @@ -409,12 +412,10 @@ void LLSpeakerMgr::update(BOOL resort_ok) // update status of all current speakers BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();) + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) { LLUUID speaker_id = speaker_it->first; LLSpeaker* speakerp = speaker_it->second; - - speaker_it++; if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) { @@ -539,30 +540,39 @@ void LLSpeakerMgr::updateSpeakerList() LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) { + const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout"); // For groups, we need to hit the group manager. // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); - if (!gdatap) + if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout)) { // Request the data the first time around LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id); } - else if (gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) { // Add group members when we get the complete list (note: can take a while before we get that list) LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); + const S32 load_group_max_members = gSavedSettings.getS32("ChatLoadGroupMaxMembers"); + S32 updated = 0; while (member_it != gdatap->mMembers.end()) { LLGroupMemberData* member = member_it->second; - // Add only the members who are online - if (member->getOnlineStatus() == "Online") + LLUUID id = member_it->first; + // Add only members who are online and not already in the list + if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) { - LLPointer speakerp = setSpeaker(member_it->first, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + LLPointer speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); + updated++; } ++member_it; + // Limit the number of "manually updated" participants to a reasonable number to avoid severe fps drop + // *TODO : solve the perf issue of having several hundreds of widgets in the conversation list + if (updated >= load_group_max_members) + break; } - mSpeakerListUpdated = true; + mSpeakerListUpdated = true; } } else if (mSpeakers.size() == 0) diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 5f5095097e..e953dd0e1a 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -264,6 +264,7 @@ protected: typedef std::map > speaker_map_t; speaker_map_t mSpeakers; bool mSpeakerListUpdated; + LLTimer mGetListTime; speaker_list_t mSpeakersSorted; LLFrameTimer mSpeechTimer; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 70256d0e78..cf59e67955 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1038,7 +1038,6 @@ void render_hud_attachments() if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) { LLCamera hud_cam = *LLViewerCamera::getInstance(); - //LLVector3 origin = hud_cam.getOrigin(); hud_cam.setOrigin(-1.f,0,0); hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index f167bd14d8..3c0d6189ac 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2379,7 +2379,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLPostponedNotification::add(params, from_id, false); break; - case IM_NOTHING_SPECIAL: + case IM_NOTHING_SPECIAL: // p2p IM // Don't show dialog, just do IM if (!gAgent.isGodlike() && gAgent.getRegion()->isPrelude() @@ -2780,42 +2780,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } break; - case IM_SESSION_SEND: - { - if (is_do_not_disturb) - { - return; - } - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" - if ( !gIMMgr->hasSession(session_id) ) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); - } - buffer = saved + message; - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - IM_OFFLINE == offline, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - } - break; - case IM_FROM_TASK: { if (is_do_not_disturb && !is_owned_by_me) @@ -2914,6 +2878,76 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLPostponedNotification::add(params, from_id, from_group); } break; + + case IM_SESSION_SEND: // ad-hoc or group IMs + + // Only show messages if we have a session open (which + // should happen after you get an "invitation" + if ( !gIMMgr->hasSession(session_id) ) + { + return; + } + + else if (offline == IM_ONLINE && is_do_not_disturb) + { + + // return a standard "do not disturb" message, but only do it to online IM + // (i.e. not other auto responses and not store-and-forward IM) + if (!gIMMgr->hasSession(session_id)) + { + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + send_do_not_disturb_message(msg, from_id, session_id); + } + + // now store incoming IM in chat history + + buffer = message; + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + // add to IM panel, but do not bother the user + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + } + else + { + // standard message, not from system + std::string saved; + if(offline == IM_OFFLINE) + { + saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); + } + + buffer = saved + message; + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + } + break; + case IM_FROM_TASK_AS_ALERT: if (is_do_not_disturb && !is_owned_by_me) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index a6cd2c9ab7..0910b7536d 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2837,7 +2837,6 @@ void LLViewerWindow::updateUI() BOOL handled = FALSE; - //BOOL handled_by_top_ctrl = FALSE; LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); LLView* captor_view = dynamic_cast(mouse_captor); @@ -3022,7 +3021,6 @@ void LLViewerWindow::updateUI() S32 local_x, local_y; top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask); - //handled_by_top_ctrl = TRUE; } if ( !handled ) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f4a2663d43..bc86bfd0a1 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2533,43 +2533,43 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) return; } - BOOL new_name = FALSE; - if (visible_chat != mVisibleChat) - { - mVisibleChat = visible_chat; - new_name = TRUE; - } - - if (sRenderGroupTitles != mRenderGroupTitles) - { - mRenderGroupTitles = sRenderGroupTitles; - new_name = TRUE; - } + BOOL new_name = FALSE; + if (visible_chat != mVisibleChat) + { + mVisibleChat = visible_chat; + new_name = TRUE; + } - // First Calculate Alpha - // If alpha > 0, create mNameText if necessary, otherwise delete it - F32 alpha = 0.f; - if (mAppAngle > 5.f) - { - const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; - if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) - { - alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; - } - else - { - // ...not fading, full alpha - alpha = 1.f; - } - } - else if (mAppAngle > 2.f) - { - // far away is faded out also - alpha = (mAppAngle-2.f)/3.f; - } + if (sRenderGroupTitles != mRenderGroupTitles) + { + mRenderGroupTitles = sRenderGroupTitles; + new_name = TRUE; + } + + // First Calculate Alpha + // If alpha > 0, create mNameText if necessary, otherwise delete it + F32 alpha = 0.f; + if (mAppAngle > 5.f) + { + const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; + if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) + { + alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; + } + else + { + // ...not fading, full alpha + alpha = 1.f; + } + } + else if (mAppAngle > 2.f) + { + // far away is faded out also + alpha = (mAppAngle-2.f)/3.f; + } if (alpha <= 0.f) - { + { if (mNameText) { mNameText->markDead(); @@ -2579,19 +2579,19 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) return; } - if (!mNameText) - { + if (!mNameText) + { mNameText = static_cast( LLHUDObject::addHUDObject( LLHUDObject::LL_HUD_NAME_TAG) ); //mNameText->setMass(10.f); - mNameText->setSourceObject(this); + mNameText->setSourceObject(this); mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP); - mNameText->setVisibleOffScreen(TRUE); - mNameText->setMaxLines(11); - mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); - sNumVisibleChatBubbles++; - new_name = TRUE; - } + mNameText->setVisibleOffScreen(TRUE); + mNameText->setMaxLines(11); + mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); + sNumVisibleChatBubbles++; + new_name = TRUE; + } idleUpdateNameTagPosition(root_pos_last); idleUpdateNameTagText(new_name); @@ -2636,6 +2636,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Rebuild name tag if state change detected if (mNameString.empty() + || (mNameString.size() == 2 && mNameString[0] == 10 && mNameString[1] == 10) // *TODO : find out why mNameString is sometimes "" || new_name || (!title && !mTitle.empty()) || (title && mTitle != title->getString()) @@ -2840,6 +2841,7 @@ void LLVOAvatar::clearNameTag() mNameText->setLabel(""); mNameText->setString( "" ); } + mTimeVisible.reset(); } //static diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index c82fc50812..1940cf541e 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -965,8 +965,6 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& S32 text_x = x; S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight()); - //BOOL is_in_window = true; - if( x < 0 || y < 0 || x >= getRect().getWidth() @@ -979,7 +977,6 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x = sTrackingArrowX; text_y = sTrackingArrowY; } - //is_in_window = false; } else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION && LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING) diff --git a/indra/newview/skins/default/textures/icons/collapse_to_one_line.png b/indra/newview/skins/default/textures/icons/collapse_to_one_line.png new file mode 100644 index 0000000000..d57144a645 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/collapse_to_one_line.png differ diff --git a/indra/newview/skins/default/textures/icons/expand_one_liner.png b/indra/newview/skins/default/textures/icons/expand_one_liner.png new file mode 100644 index 0000000000..58b7d90131 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/expand_one_liner.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 6a520e9388..fcab966dee 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -171,6 +171,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml index 12c1676127..65f623a47e 100644 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -61,7 +61,7 @@ image_unselected="Toolbar_Middle_Off" menu_filename="menu_participant_view.xml" layout="topleft" - left="10" + left="5" name="sort_btn" tool_tip="View/sort options" top="5" @@ -75,7 +75,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="add_btn" tool_tip="Start a new conversation" width="31"/> @@ -88,7 +88,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="speak_btn" tool_tip="Speak with people using your microphone" width="31"/> @@ -114,7 +114,7 @@ Conv_toolbar_open_call Conv_toolbar_hang_up + + @@ -65,14 +71,28 @@ top="0" left="0" height="355" - width="394"> - + + + @@ -126,7 +146,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="voice_call_btn" tool_tip="Open voice connection" width="31"/> @@ -151,7 +171,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left="283" + left="292" name="close_btn" tool_tip="End this conversation" width="31" /> @@ -164,7 +184,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="5" + left_pad="2" name="expand_collapse_btn" tool_tip="Collapse/Expand this pane" width="31" /> @@ -177,15 +197,22 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="5" + left_pad="2" name="tear_off_btn" width="31" /> - + + + auto_resize="false"> - + + + + + + - + + +