summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/settings.xml22
-rwxr-xr-xindra/newview/llavataractions.cpp16
-rw-r--r--indra/newview/llchathistory.cpp22
-rw-r--r--indra/newview/llconversationlog.cpp70
-rw-r--r--indra/newview/llconversationlog.h15
-rw-r--r--indra/newview/llconversationloglist.cpp69
-rw-r--r--indra/newview/llconversationmodel.cpp29
-rwxr-xr-xindra/newview/llconversationmodel.h6
-rwxr-xr-xindra/newview/llconversationview.cpp82
-rwxr-xr-xindra/newview/llconversationview.h5
-rw-r--r--indra/newview/lldrawable.cpp19
-rw-r--r--indra/newview/llfloaterconversationpreview.cpp17
-rw-r--r--indra/newview/llfloaterconversationpreview.h5
-rw-r--r--indra/newview/llfloaterimcontainer.cpp186
-rw-r--r--indra/newview/llfloaterimcontainer.h14
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp52
-rw-r--r--indra/newview/llfloaterimnearbychat.h3
-rw-r--r--indra/newview/llfloaterimsession.h1
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp73
-rw-r--r--indra/newview/llfloaterimsessiontab.h4
-rwxr-xr-xindra/newview/llfloaterpreference.cpp104
-rw-r--r--indra/newview/llfloaterpreference.h3
-rw-r--r--indra/newview/llimview.cpp10
-rw-r--r--indra/newview/lllogchat.cpp123
-rw-r--r--indra/newview/lllogchat.h11
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp6
-rw-r--r--indra/newview/lloutputmonitorctrl.h3
-rw-r--r--indra/newview/llpanelpeople.cpp5
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp7
-rw-r--r--indra/newview/llspeakers.cpp28
-rw-r--r--indra/newview/llspeakers.h1
-rwxr-xr-xindra/newview/llviewerwindow.cpp9
-rw-r--r--indra/newview/llvoavatar.cpp81
-rw-r--r--indra/newview/skins/default/xui/en/menu_object_icon.xml18
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_agent.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_group.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_objectim.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml8
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml23
39 files changed, 949 insertions, 225 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6436f11967..0aa01f6fd9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1584,6 +1584,28 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>ChatLoadGroupMaxMembers</key>
+ <map>
+ <key>Comment</key>
+ <string>Max number of active members we'll show up for an unresponsive group</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>100</real>
+ </map>
+ <key>ChatLoadGroupTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Time we give the server to send group participants before we hit the server for group info (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
<key>ChatOnlineNotification</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index d6e457887b..b513a52ff7 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -44,6 +44,7 @@
#include "llcallingcard.h" // for LLAvatarTracker
#include "llconversationlog.h"
#include "llfloateravatarpicker.h" // for LLFloaterAvatarPicker
+#include "llfloaterconversationpreview.h"
#include "llfloatergroupinvite.h"
#include "llfloatergroups.h"
#include "llfloaterreg.h"
@@ -192,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));
@@ -926,9 +927,20 @@ void LLAvatarActions::viewChatHistory(const LLUUID& id)
if (iter->getParticipantID() == id)
{
LLFloaterReg::showInstance("preview_conversation", iter->getSessionID(), true);
- break;
+ return;
}
}
+
+ if (LLLogChat::isTranscriptExist(id))
+ {
+ LLAvatarName avatar_name;
+ LLSD extended_id(id);
+
+ LLAvatarNameCache::get(id, &avatar_name);
+ extended_id[LL_FCP_COMPLETE_NAME] = avatar_name.getCompleteName();
+ extended_id[LL_FCP_ACCOUNT_NAME] = avatar_name.getAccountName();
+ LLFloaterReg::showInstance("preview_conversation", extended_id, true);
+ }
}
//== private methods ========================================================================================
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<LLChatHistory> 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/llconversationlog.cpp b/indra/newview/llconversationlog.cpp
index b777edba77..dd20ca15ae 100644
--- a/indra/newview/llconversationlog.cpp
+++ b/indra/newview/llconversationlog.cpp
@@ -28,9 +28,13 @@
#include "llagent.h"
#include "llavatarnamecache.h"
#include "llconversationlog.h"
+#include "lldiriterator.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
+#include <boost/foreach.hpp>
+#include "boost/lexical_cast.hpp"
+
const int CONVERSATION_LIFETIME = 30; // lifetime of LLConversation is 30 days by spec
struct ConversationParams
@@ -378,6 +382,71 @@ void LLConversationLog::cache()
}
}
+void LLConversationLog::getListOfBackupLogs(std::vector<std::string>& 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<std::string> 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)
+{
+
+ std::string backupFileName;
+ unsigned backupFileCount = 0;
+
+ //Does the file exist in the current path, if it does lets move it
+ if(LLFile::isfile(originDirectory))
+ {
+ //The target directory contains that file already, so lets store it
+ if(LLFile::isfile(targetDirectory))
+ {
+ backupFileName = targetDirectory + ".backup";
+
+ //If needed store backup file as .backup1 etc.
+ while(LLFile::isfile(backupFileName))
+ {
+ ++backupFileCount;
+ backupFileName = targetDirectory + ".backup" + boost::lexical_cast<std::string>(backupFileCount);
+ }
+
+ //Rename the file to its backup name so it is not overwritten
+ LLFile::rename(targetDirectory, backupFileName);
+ }
+
+ //Move the file from the current path to target path
+ if(LLFile::rename(originDirectory, targetDirectory) != 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
std::string LLConversationLog::getFileName()
{
std::string filename = "conversation";
@@ -538,5 +607,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 fd38556131..265b1f0ef0 100644
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -137,6 +137,9 @@ public:
* public method which is called on viewer exit to save conversation log
*/
void cache();
+ bool moveLog(const std::string &originDirectory, const std::string &targetDirectory);
+ void getListOfBackupLogs(std::vector<std::string>& list_of_backup_logs);
+ void deleteBackupLogs();
void onClearLog();
void onClearLogResponse(const LLSD& notification, const LLSD& response);
@@ -144,6 +147,12 @@ public:
bool getIsLoggingEnabled() { return mLoggingEnabled; }
bool isLogEmpty() { return mConversations.empty(); }
+ /**
+ * constructs file name in which conversations log will be saved
+ * file name is conversation.log
+ */
+ std::string getFileName();
+
private:
LLConversationLog();
@@ -164,12 +173,6 @@ private:
void notifyParticularConversationObservers(const LLUUID& session_id, U32 mask);
- /**
- * constructs file name in which conversations log will be saved
- * file name is conversation.log
- */
- std::string getFileName();
-
bool saveToFile(const std::string& filename);
bool loadFromFile(const std::string& filename);
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 96b225b841..b202cfc9d3 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;
@@ -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 0977056b2a..009fce0a92 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -322,7 +322,7 @@ void LLConversationItemSession::setParticipantIsMuted(const LLUUID& participant_
LLConversationItemParticipant* participant = findParticipant(participant_id);
if (participant)
{
- participant->setIsMuted(is_muted);
+ participant->muteVoice(is_muted);
}
}
@@ -462,7 +462,6 @@ void LLConversationItemSession::onAvatarNameCache(const LLAvatarName& av_name)
LLConversationItemParticipant::LLConversationItemParticipant(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
LLConversationItem(display_name,uuid,root_view_model),
- mIsMuted(false),
mIsModerator(false),
mDisplayModeratorLabel(false),
mDistToAgent(-1.0)
@@ -473,7 +472,6 @@ LLConversationItemParticipant::LLConversationItemParticipant(std::string display
LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
LLConversationItem(uuid,root_view_model),
- mIsMuted(false),
mIsModerator(false),
mDisplayModeratorLabel(false),
mDistToAgent(-1.0)
@@ -549,7 +547,7 @@ LLConversationItemSession* LLConversationItemParticipant::getParentSession()
void LLConversationItemParticipant::dumpDebugData()
{
- llinfos << "Merov debug : participant, uuid = " << mUUID << ", name = " << mName << ", display name = " << mDisplayName << ", muted = " << mIsMuted << ", moderator = " << mIsModerator << llendl;
+ llinfos << "Merov debug : participant, uuid = " << mUUID << ", name = " << mName << ", display name = " << mDisplayName << ", muted = " << isVoiceMuted() << ", moderator = " << mIsModerator << llendl;
}
void LLConversationItemParticipant::setDisplayModeratorRole(bool displayRole)
@@ -561,6 +559,29 @@ void LLConversationItemParticipant::setDisplayModeratorRole(bool displayRole)
}
}
+bool LLConversationItemParticipant::isVoiceMuted()
+{
+ return LLMuteList::getInstance()->isMuted(mUUID, LLMute::flagVoiceChat);
+}
+
+void LLConversationItemParticipant::muteVoice(bool mute_voice)
+{
+ std::string name;
+ gCacheName->getFullName(mUUID, name);
+ LLMuteList * mute_listp = LLMuteList::getInstance();
+ bool voice_already_muted = mute_listp->isMuted(mUUID, name);
+
+ LLMute mute(mUUID, name, LLMute::AGENT);
+ if (voice_already_muted && !mute_voice)
+ {
+ mute_listp->remove(mute);
+ }
+ else if (!voice_already_muted && mute_voice)
+ {
+ mute_listp->add(mute);
+ }
+}
+
//
// LLConversationSort
//
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index c907d1d6d2..8766585049 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -189,9 +189,9 @@ public:
virtual const std::string& getDisplayName() const { return mDisplayName; }
- bool isMuted() { return mIsMuted; }
- bool isModerator() {return mIsModerator; }
- void setIsMuted(bool is_muted) { mIsMuted = is_muted; mNeedsRefresh = true; }
+ bool isVoiceMuted();
+ bool isModerator() const { return mIsModerator; }
+ void muteVoice(bool mute_voice);
void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; }
void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; }
void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; }
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index 5ac6353daa..956abcd586 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -39,6 +39,7 @@
#include "llfloaterreg.h"
#include "llgroupiconctrl.h"
#include "lluictrlfactory.h"
+#include "lltoolbarview.h"
//
// Implementation of conversations list session widgets
@@ -103,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();
@@ -241,21 +251,42 @@ void LLConversationViewSession::draw()
BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )
{
- LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem());
- LLUUID session_id = item? item->getUUID() : LLUUID();
- //Will try to select a child node and then itself (if a child was not selected)
+ //Will try to select a child node and then itself (if a child was not selected)
BOOL result = LLFolderViewFolder::handleMouseDown(x, y, mask);
//This node (conversation) was selected and a child (participant) was not
- if(result && getRoot()->getCurSelectedItem() == this)
+ if(result && getRoot())
+ {
+ 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<LLConversationItem *>(getViewModelItem());
+ LLUUID session_id = item? item->getUUID() : LLUUID();
+
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
im_container->flashConversationItemWidget(session_id,false);
im_container->selectConversationPair(session_id, false);
im_container->collapseMessagesPane(false);
}
-
- return result;
}
// virtual
@@ -375,7 +406,7 @@ void LLConversationViewSession::refresh()
}
}
}
-
+ requestArrange();
// Do the regular upstream refresh
LLFolderViewFolder::refresh();
}
@@ -517,26 +548,13 @@ S32 LLConversationViewParticipant::arrange(S32* width, S32* height)
return arranged;
}
-void LLConversationViewParticipant::refresh()
-{
- // Refresh the participant view from its model data
- LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
- participant_model->resetRefresh();
-
- // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
- mSpeakingIndicator->setIsMuted(participant_model->isMuted());
-
- // Do the regular upstream refresh
- LLFolderViewItem::refresh();
-}
-
void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)
{
// Add the item to the folder (conversation)
LLFolderViewItem::addToFolder(folder);
// Retrieve the folder (conversation) UUID, which is also the speaker session UUID
- LLConversationItem* vmi = this->getParentFolder() ? dynamic_cast<LLConversationItem*>(this->getParentFolder()->getViewModelItem()) : NULL;
+ LLConversationItem* vmi = getParentFolder() ? dynamic_cast<LLConversationItem*>(getParentFolder()->getViewModelItem()) : NULL;
if (vmi)
{
addToSession(vmi->getUUID());
@@ -557,6 +575,28 @@ void LLConversationViewParticipant::onInfoBtnClick()
LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", mUUID));
}
+BOOL LLConversationViewParticipant::handleMouseDown( S32 x, S32 y, MASK mask )
+{
+ BOOL result = LLFolderViewItem::handleMouseDown(x, y, mask);
+
+ if(result && getRoot())
+ {
+ if(getRoot()->getCurSelectedItem() == this)
+ {
+ LLConversationItem* vmi = getParentFolder() ? dynamic_cast<LLConversationItem*>(getParentFolder()->getViewModelItem()) : NULL;
+ LLUUID session_id = vmi? vmi->getUUID() : LLUUID();
+
+ LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+ LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
+ im_container->setSelectedSession(session_id);
+ im_container->flashConversationItemWidget(session_id,false);
+ im_container->selectFloater(session_floater);
+ im_container->collapseMessagesPane(false);
+ }
+ }
+ return result;
+}
+
void LLConversationViewParticipant::onMouseEnter(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(true);
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index f2fa2fb042..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;
@@ -130,7 +132,6 @@ public:
virtual ~LLConversationViewParticipant( void );
bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); }
- virtual void refresh();
void addToFolder(LLFolderViewFolder* folder);
void addToSession(const LLUUID& session_id);
@@ -138,7 +139,7 @@ public:
void onMouseLeave(S32 x, S32 y, MASK mask);
/*virtual*/ S32 getLabelXPos();
-
+ /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
void hideSpeakingIndicator();
protected:
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 59c2f15dd9..4b0d3b361d 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -577,6 +577,12 @@ F32 LLDrawable::updateXform(BOOL undamped)
mVObjp->dirtySpatialGroup();
}
}
+ else if (!isRoot() &&
+ ((dist_vec_squared(old_pos, target_pos) > 0.f)
+ || (1.f - dot(old_rot, target_rot)) > 0.f))
+ { //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
+ }
else if (!getVOVolume() && !isAvatar())
{
movePartition();
@@ -643,18 +649,9 @@ BOOL LLDrawable::updateMove()
return FALSE;
}
- BOOL done;
+ makeActive();
- if (isState(MOVE_UNDAMPED))
- {
- done = updateMoveUndamped();
- }
- else
- {
- makeActive();
- done = updateMoveDamped();
- }
- return done;
+ return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped();
}
BOOL LLDrawable::updateMoveUndamped()
diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp
index 48e0caa0ce..a3d715530d 100644
--- a/indra/newview/llfloaterconversationpreview.cpp
+++ b/indra/newview/llfloaterconversationpreview.cpp
@@ -33,13 +33,19 @@
#include "llspinctrl.h"
#include "lltrans.h"
+const std::string LL_FCP_COMPLETE_NAME("complete_name");
+const std::string LL_FCP_ACCOUNT_NAME("user_name");
+
LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id)
: LLFloater(session_id),
mChatHistory(NULL),
mSessionID(session_id.asUUID()),
mCurrentPage(0),
- mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize"))
-{}
+ mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")),
+ mAccountName(session_id[LL_FCP_ACCOUNT_NAME]),
+ mCompleteName(session_id[LL_FCP_COMPLETE_NAME])
+{
+}
BOOL LLFloaterConversationPreview::postBuild()
{
@@ -49,7 +55,12 @@ BOOL LLFloaterConversationPreview::postBuild()
std::string name;
std::string file;
- if (mSessionID != LLUUID::null && conv)
+ if (mAccountName != "")
+ {
+ name = mCompleteName;
+ file = mAccountName;
+ }
+ else if (mSessionID != LLUUID::null && conv)
{
name = conv->getConversationName();
file = conv->getHistoryFileName();
diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h
index 0341e5d2a0..b17ae84b63 100644
--- a/indra/newview/llfloaterconversationpreview.h
+++ b/indra/newview/llfloaterconversationpreview.h
@@ -29,6 +29,9 @@
#include "llchathistory.h"
#include "llfloater.h"
+extern const std::string LL_FCP_COMPLETE_NAME; //"complete_name"
+extern const std::string LL_FCP_ACCOUNT_NAME; //"user_name"
+
class LLSpinCtrl;
class LLFloaterConversationPreview : public LLFloater
@@ -54,6 +57,8 @@ private:
int mPageSize;
std::list<LLSD> mMessages;
+ std::string mAccountName;
+ std::string mCompleteName;
};
#endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index c8088588da..7437dd8cda 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -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();
@@ -605,7 +607,7 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
setSelectedSession(LLUUID(NULL));
}
openNearbyChat();
- selectConversationPair(getSelectedSession(), false);
+ selectConversationPair(getSelectedSession(), false, false);
}
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
@@ -667,7 +669,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 +678,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 +692,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 +702,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 +733,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();
@@ -758,13 +767,17 @@ void LLFloaterIMContainer::assignResizeLimits()
// between the panels are merged into one
S32 number_of_visible_borders = llmin((is_conv_pane_expanded? 2 : 0) + (is_msg_pane_expanded? 2 : 0), 3);
S32 summary_width_of_visible_borders = number_of_visible_borders * LLPANEL_BORDER_WIDTH;
- S32 conv_pane_current_width = is_msg_pane_expanded
- ? mConversationsPane->getRect().getWidth()
- : (is_conv_pane_expanded? mConversationsPane->getExpandedMinDim() : mConversationsPane->getMinDim());
+ S32 conv_pane_target_width = is_conv_pane_expanded?
+ (is_msg_pane_expanded?
+ mConversationsPane->getRect().getWidth()
+ : mConversationsPane->getExpandedMinDim())
+ : mConversationsPane->getMinDim();
S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0;
- S32 new_min_width = conv_pane_current_width + msg_pane_min_width + summary_width_of_visible_borders;
+ S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders;
setResizeLimits(new_min_width, getMinHeight());
+
+ mConversationsStack->updateLayout();
}
void LLFloaterIMContainer::onAddButtonClicked()
@@ -1096,12 +1109,9 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
}
else if("chat_history" == command)
{
- const LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(conversationItem->getUUID());
-
- if (NULL != session)
+ if (selectedIDS.size() > 0)
{
- const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgouigAdHocHash() : session->mSessionID;
- LLFloaterReg::showInstance("preview_conversation", session_id, true);
+ LLAvatarActions::viewChatHistory(selectedIDS.front());
}
}
else
@@ -1165,15 +1175,9 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
}
//Enable Chat history item for ad-hoc and group conversations
- if ("can_chat_history" == item)
+ if ("can_chat_history" == item && uuids.size() > 0)
{
- if(getCurSelectedViewModelItem())
- {
- if (getCurSelectedViewModelItem()->getType() != LLConversationItem::CONV_PARTICIPANT)
- {
- return isConversationLoggingAllowed();
- }
- }
+ return LLLogChat::isTranscriptExist(uuids.front());
}
// If nothing is selected(and selected item is not group chat), everything needs to be disabled
@@ -1213,6 +1217,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
return false;
}
+ // If the user agent is selected with others, everything is disabled
+ for (uuid_vec_t::const_iterator id = uuids.begin(); id != uuids.end(); ++id)
+ {
+ if (gAgent.getID() == *id)
+ {
+ return false;
+ }
+ }
+
// Handle all other options
if (("can_invite" == item) || ("can_chat_history" == item) || ("can_share" == item) || ("can_pay" == item))
{
@@ -1337,8 +1350,21 @@ void LLFloaterIMContainer::selectConversation(const LLUUID& session_id)
selectConversationPair(session_id, true);
}
+// Select the conversation *after* (or before if none after) the passed uuid conversation
+// Used to change the selection on key hits
+void LLFloaterIMContainer::selectNextConversationByID(const LLUUID& uuid)
+{
+ bool new_selection = false;
+ selectConversation(uuid);
+ new_selection = selectNextorPreviousConversation(true);
+ if (!new_selection)
+ {
+ selectNextorPreviousConversation(false);
+ }
+}
+
// Synchronous select the conversation item and the conversation floater
-BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool select_widget)
+BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool select_widget, bool focus_floater/*=true*/)
{
BOOL handled = TRUE;
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
@@ -1379,13 +1405,17 @@ 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
if (!session_floater->hasFocus())
{
BOOL is_minimized = session_floater->isMinimized();
- session_floater->setFocus(TRUE);
+ session_floater->setFocus(focus_floater);
session_floater->setMinimized(is_minimized);
}
}
@@ -1853,17 +1883,97 @@ void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id,
}
}
+bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget)
+{
+ 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);
+ return !mConversationsRoot->getVisibleRect().overlaps(widget_rect);
+}
+
+BOOL LLFloaterIMContainer::handleKeyHere(KEY key, MASK mask )
+{
+ if(mask == MASK_ALT)
+ {
+ if (KEY_RETURN == key )
+ {
+ expandConversation();
+ }
+
+ if ((KEY_DOWN == key ) || (KEY_RIGHT == key))
+ {
+ selectNextorPreviousConversation(true);
+ }
+ if ((KEY_UP == key) || (KEY_LEFT == key))
+ {
+ selectNextorPreviousConversation(false);
+ }
+ }
+ return TRUE;
+}
+
+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)
+ {
+ LLFolderViewItem* new_selection = NULL;
+ LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,getSelectedSession());
+ if (widget)
+ {
+ if(select_next)
+ {
+ new_selection = mConversationsRoot->getNextFromChild(widget, FALSE);
+ }
+ else
+ {
+ new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE);
+ }
+ if (new_selection)
+ {
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(new_selection->getViewModelItem());
+ if (vmi)
+ {
+ selectConversationPair(vmi->getUUID(), true, focus_selected);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void LLFloaterIMContainer::expandConversation()
+{
+ LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(get_ptr_in_map(mConversationsWidgets,getSelectedSession()));
+ if (widget)
+ {
+ widget->setOpen(!widget->isOpen());
+ }
+}
+
void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
{
// Always unminimize before trying to close.
// Most of the time the user will never see this state.
setMinimized(FALSE);
- S32 conv_pane_width = mConversationsPane->getRect().getWidth();
-
- // Save the conversations pane width before collapsing it.
- gSavedPerAccountSettings.setS32("ConversationsListPaneWidth", conv_pane_width);
-
LLFloater::closeFloater(app_quitting);
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 569fa9faab..5139651d8d 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -69,8 +69,12 @@ public:
void returnFloaterToHost();
void showConversation(const LLUUID& session_id);
void selectConversation(const LLUUID& session_id);
- BOOL selectConversationPair(const LLUUID& session_id, bool select_widget);
+ void selectNextConversationByID(const LLUUID& session_id);
+ BOOL selectConversationPair(const LLUUID& session_id, bool select_widget, bool focus_floater = true);
void clearAllFlashStates();
+ bool selectAdjacentConversation(bool focus_selected);
+ bool selectNextorPreviousConversation(bool select_next, bool focus_selected = true);
+ void expandConversation();
/*virtual*/ void tabClose();
void showStub(bool visible);
@@ -108,7 +112,7 @@ public:
void doToParticipants(const std::string& item, uuid_vec_t& selectedIDS);
void assignResizeLimits();
-
+ virtual BOOL handleKeyHere(KEY key, MASK mask );
/*virtual*/ void closeFloater(bool app_quitting = false);
private:
@@ -125,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);
@@ -185,7 +189,9 @@ public:
void updateSpeakBtnState();
static bool isConversationLoggingAllowed();
void flashConversationItemWidget(const LLUUID& session_id, bool is_flashes);
+ bool isScrolledOutOfSight(LLConversationViewSession* conversation_item_widget);
boost::signals2::connection mMicroChangedSignal;
+ S32 getConversationListItemSize() { return mConversationsWidgets.size(); }
private:
LLConversationViewSession* createConversationItemWidget(LLConversationItem* item);
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index c0a2c2e13f..66aac9c570 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -136,6 +136,25 @@ BOOL LLFloaterIMNearbyChat::postBuild()
}
// virtual
+void LLFloaterIMNearbyChat::closeHostedFloater()
+{
+ // Should check how many conversations are ongoing. Close all if 1 only (the Nearby Chat), select next one otherwise
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ if (floater_container->getConversationListItemSize() == 1)
+ {
+ floater_container->closeFloater();
+ }
+ else
+ {
+ if (!getHost())
+ {
+ setVisible(FALSE);
+ }
+ floater_container->selectNextConversationByID(LLUUID());
+ }
+}
+
+// virtual
void LLFloaterIMNearbyChat::refresh()
{
displaySpeakingIndicator();
@@ -238,6 +257,17 @@ 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()
{
@@ -334,6 +364,28 @@ BOOL LLFloaterIMNearbyChat::handleKeyHere( KEY key, MASK mask )
sendChat(CHAT_TYPE_SHOUT);
handled = TRUE;
}
+ else if (KEY_RETURN == key && mask == MASK_SHIFT)
+ {
+ // whisper
+ sendChat(CHAT_TYPE_WHISPER);
+ handled = TRUE;
+ }
+
+
+ if((mask == MASK_ALT) && isTornOff())
+ {
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ if ((KEY_UP == key) || (KEY_LEFT == key))
+ {
+ floater_container->selectNextorPreviousConversation(false);
+ handled = TRUE;
+ }
+ if ((KEY_DOWN == key ) || (KEY_RIGHT == key))
+ {
+ floater_container->selectNextorPreviousConversation(true);
+ handled = TRUE;
+ }
+ }
return handled;
}
diff --git a/indra/newview/llfloaterimnearbychat.h b/indra/newview/llfloaterimnearbychat.h
index 14c7d01ecd..05b48cccb0 100644
--- a/indra/newview/llfloaterimnearbychat.h
+++ b/indra/newview/llfloaterimnearbychat.h
@@ -54,6 +54,8 @@ 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();
void reloadMessages(bool clean_messages = false);
@@ -68,6 +70,7 @@ public:
LLChatEntry* getChatBox() { return mInputEditor; }
std::string getCurrentChat();
+ S32 getMessageArchiveLength() {return mMessageArchive.size();}
virtual BOOL handleKeyHere( KEY key, MASK mask );
diff --git a/indra/newview/llfloaterimsession.h b/indra/newview/llfloaterimsession.h
index 381b3cf721..cb330bca0f 100644
--- a/indra/newview/llfloaterimsession.h
+++ b/indra/newview/llfloaterimsession.h
@@ -133,6 +133,7 @@ public:
static floater_showed_signal_t sIMFloaterShowedSignal;
bool needsTitleOverwrite() { return mSessionNameUpdatedForTyping && mOtherTyping; }
+ S32 getLastChatMessageIndex() {return mLastMessageIndex;}
private:
/*virtual*/ void refresh();
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 6dbcdb4474..9fd22b1537 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);
@@ -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
@@ -253,6 +255,7 @@ BOOL LLFloaterIMSessionTab::postBuild()
p.root = NULL;
p.use_ellipses = true;
p.options_menu = "menu_conversation.xml";
+ p.name = "root";
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
// Attach that root to the scroller
@@ -268,6 +271,12 @@ BOOL LLFloaterIMSessionTab::postBuild()
mRefreshTimer->setTimerExpirySec(0);
mRefreshTimer->start();
initBtns();
+
+ if (mIsParticipantListExpanded != (bool)gSavedSettings.getBOOL("IMShowControlPanel"))
+ {
+ LLFloaterIMSessionTab::onSlide(this);
+ }
+
return result;
}
@@ -324,13 +333,6 @@ void LLFloaterIMSessionTab::onFocusReceived()
}
LLTransientDockableFloater::onFocusReceived();
-
- LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("im_container");
- if (container)
- {
- container->selectConversationPair(mSessionID, true);
- container->showStub(! getHost());
- }
}
void LLFloaterIMSessionTab::onFocusLost()
@@ -644,7 +646,7 @@ 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);
@@ -725,6 +727,27 @@ void LLFloaterIMSessionTab::processChatHistoryStyleUpdate(bool clean_messages/*
}
}
+// static
+void LLFloaterIMSessionTab::reloadEmptyFloaters()
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
+ iter != inst_list.end(); ++iter)
+ {
+ LLFloaterIMSession* floater = dynamic_cast<LLFloaterIMSession*>(*iter);
+ if (floater && floater->getLastChatMessageIndex() == -1)
+ {
+ floater->reloadMessages(true);
+ }
+ }
+
+ LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
+ if (nearby_chat && nearby_chat->getMessageArchiveLength() == 0)
+ {
+ nearby_chat->reloadMessages(true);
+ }
+}
+
void LLFloaterIMSessionTab::updateCallBtnState(bool callIsActive)
{
LLButton* voiceButton = getChild<LLButton>("voice_call_btn");
@@ -754,9 +777,8 @@ 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"));
}
}
@@ -780,10 +802,18 @@ void LLFloaterIMSessionTab::onTearOffClicked()
mSaveRect = isTornOff();
initRectControl();
LLFloater::onClickTearOff(this);
+ LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("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);
+ }
refreshConversation();
updateGearBtn();
}
@@ -918,3 +948,24 @@ LLConversationItem* LLFloaterIMSessionTab::getCurSelectedViewModelItem()
return conversationItem;
}
+
+BOOL LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask )
+{
+ if(mask == MASK_ALT)
+ {
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ if (KEY_RETURN == key && !isTornOff())
+ {
+ floater_container->expandConversation();
+ }
+ if ((KEY_UP == key) || (KEY_LEFT == key))
+ {
+ floater_container->selectNextorPreviousConversation(false);
+ }
+ if ((KEY_DOWN == key ) || (KEY_RIGHT == key))
+ {
+ floater_container->selectNextorPreviousConversation(true);
+ }
+ }
+ return TRUE;
+}
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index e90fcbb806..e8ae557412 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -54,6 +54,7 @@ public:
// reload all message with new settings of visual modes
static void processChatHistoryStyleUpdate(bool clean_messages = false);
+ static void reloadEmptyFloaters();
/**
* Returns true if chat is displayed in multi tabbed floater
@@ -95,8 +96,8 @@ public:
void initBtns();
virtual void updateMessages() {}
LLConversationItem* getCurSelectedViewModelItem();
-
void forceReshape();
+ virtual BOOL handleKeyHere( KEY key, MASK mask );
protected:
@@ -137,6 +138,7 @@ protected:
bool mIsNearbyChat;
bool mIsP2PChat;
+ bool mIsParticipantListExpanded;
LLIMModel::LLIMSession* mSession;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 3d8d0e15ec..b308a820b2 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -646,9 +646,6 @@ void LLFloaterPreference::cancel()
LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get();
pPathfindingConsole->onRegionBoundaryCross();
}
-
- std::string dir_name(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
- updateLogLocation(dir_name);
}
void LLFloaterPreference::onOpen(const LLSD& key)
@@ -798,8 +795,31 @@ void LLFloaterPreference::onBtnOK()
apply();
closeFloater(false);
+ //Conversation transcript and log path changed so reload conversations based on new location
+ if(mPriorInstantMessageLogPath.length())
+ {
+ if(moveTranscriptsAndLog())
+ {
+ //When floaters are empty but have a chat history files, reload chat history into them
+ LLFloaterIMSessionTab::reloadEmptyFloaters();
+ }
+ //Couldn't move files so restore the old path and show a notification
+ else
+ {
+ gSavedPerAccountSettings.setString("InstantMessageLogPath", mPriorInstantMessageLogPath);
+ LLNotificationsUtil::add("PreferenceChatPathChanged");
+ }
+ mPriorInstantMessageLogPath.clear();
+ }
+
LLUIColorTable::instance().saveUserSettings();
gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
+
+ //Only save once logged in and loaded per account settings
+ if(mGotPersonalInfo)
+ {
+ gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
+ }
}
else
{
@@ -1437,28 +1457,91 @@ void LLFloaterPreference::setAllIgnored()
void LLFloaterPreference::onClickLogPath()
{
std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
+ mPriorInstantMessageLogPath.clear();
LLDirPicker& picker = LLDirPicker::instance();
+ //Launches a directory picker and waits for feedback
if (!picker.getDir(&proposed_name ) )
{
return; //Canceled!
}
+ //Gets the path from the directory picker
std::string dir_name = picker.getDirName();
+
+ //Path changed
+ if(proposed_name != dir_name)
+ {
gSavedPerAccountSettings.setString("InstantMessageLogPath", dir_name);
+ mPriorInstantMessageLogPath = proposed_name;
// enable/disable 'Delete transcripts button
updateDeleteTranscriptsButton();
}
+}
-void LLFloaterPreference::updateLogLocation(const std::string& dir_name)
+bool LLFloaterPreference::moveTranscriptsAndLog()
{
- gDirUtilp->setChatLogsDir(dir_name);
+ std::string instantMessageLogPath(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
+ std::string chatLogPath = gDirUtilp->add(instantMessageLogPath, gDirUtilp->getUserName());
+
+ bool madeDirectory = false;
+
+ //Does the directory really exist, if not then make it
+ if(!LLFile::isdir(chatLogPath))
+ {
+ //mkdir success is defined as zero
+ if(LLFile::mkdir(chatLogPath) != 0)
+ {
+ return false;
+ }
+ madeDirectory = true;
+ }
+
+ std::string originalConversationLogDir = LLConversationLog::instance().getFileName();
+ std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log");
+ //Try to move the conversation log
+ if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir))
+ {
+ //Couldn't move the log and created a new directory so remove the new directory
+ if(madeDirectory)
+ {
+ LLFile::rmdir(chatLogPath);
+ }
+ return false;
+ }
+
+ //Attempt to move transcripts
+ std::vector<std::string> listOfTranscripts;
+ std::vector<std::string> listOfFilesMoved;
+
+ LLLogChat::getListOfTranscriptFiles(listOfTranscripts);
+
+ if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(),
+ instantMessageLogPath,
+ listOfTranscripts,
+ listOfFilesMoved))
+ {
+ //Couldn't move all the transcripts so restore those that moved back to their old location
+ LLLogChat::moveTranscripts(instantMessageLogPath,
+ gDirUtilp->getChatLogsDir(),
+ listOfFilesMoved);
+
+ //Move the conversation log back
+ LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir);
+
+ if(madeDirectory)
+ {
+ LLFile::rmdir(chatLogPath);
+ }
+
+ return false;
+ }
+
+ gDirUtilp->setChatLogsDir(instantMessageLogPath);
gDirUtilp->updatePerAccountChatLogsDir();
- LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
- // refresh IM floaters with new logs from files from new selected directory
- LLFloaterIMSessionTab::processChatHistoryStyleUpdate(true);
+ return true;
}
void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im_via_email)
@@ -1584,7 +1667,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/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index dbd87f74a1..22e80a21cb 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -143,7 +143,7 @@ public:
void resetAllIgnored();
void setAllIgnored();
void onClickLogPath();
- void updateLogLocation(const std::string& dir_name);
+ bool moveTranscriptsAndLog();
void enableHistory();
void setPersonalInfo(const std::string& visibility, bool im_via_email);
void refreshEnabledState();
@@ -187,6 +187,7 @@ private:
bool mOriginalIMViaEmail;
bool mLanguageChanged;
bool mAvatarDataInitialized;
+ std::string mPriorInstantMessageLogPath;
bool mOriginalHideOnlineStatus;
std::string mDirectoryVisibility;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index d69bd89f13..37f5888e8c 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -273,7 +273,7 @@ void on_new_message(const LLSD& msg)
}
}
- else if("openconversations" == action && !session_floater_is_open)
+ else if("openconversations" == action)
{
//User is not focused on conversation containing the message
if(session_floater_not_focused)
@@ -285,13 +285,19 @@ void on_new_message(const LLSD& msg)
{
//Surface conversations floater
LLFloaterReg::showInstance("im_container");
+
+ if (session_floater && session_floater->isMinimized())
+ {
+ LLFloater::onClickMinimize(session_floater);
+ }
}
//If in DND mode, allow notification to be stored so upon DND exit
//useMostItrusiveIMNotification will be called to notify user a message exists
if(session_id.notNull()
&& participant_id.notNull()
- && gAgent.isDoNotDisturb())
+ && gAgent.isDoNotDisturb()
+ && !session_floater_is_open)
{
LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 17b72c5023..2d7454b636 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -28,6 +28,7 @@
#include "llagent.h"
#include "llagentui.h"
+#include "llavatarnamecache.h"
#include "lllogchat.h"
#include "lltrans.h"
#include "llviewercontrol.h"
@@ -443,7 +444,7 @@ std::string LLLogChat::oldLogFileName(std::string filename)
}
// static
-void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& list_of_transcriptions)
+void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string>& list_of_transcriptions)
{
// get Users log directory
std::string dirname = gDirUtilp->getPerAccountChatLogsDir();
@@ -451,9 +452,6 @@ void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& 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))
@@ -489,6 +487,22 @@ void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& list_of_trans
}
}
+// static
+void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& list_of_transcriptions)
+{
+ // create search pattern
+ std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION;
+ findTranscriptFiles(pattern, list_of_transcriptions);
+}
+
+// static
+void LLLogChat::getListOfTranscriptBackupFiles(std::vector<std::string>& 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)
{
@@ -501,10 +515,86 @@ boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_s
}
//static
+bool LLLogChat::moveTranscripts(const std::string originDirectory,
+ const std::string targetDirectory,
+ std::vector<std::string>& listOfFilesToMove,
+ std::vector<std::string>& listOfFilesMoved)
+{
+ std::string newFullPath;
+ bool movedAllTranscripts = true;
+ std::string backupFileName;
+ unsigned backupFileCount;
+
+ BOOST_FOREACH(const std::string& fullpath, listOfFilesToMove)
+ {
+ backupFileCount = 0;
+ newFullPath = targetDirectory + fullpath.substr(originDirectory.length(), std::string::npos);
+
+ //The target directory contains that file already, so lets store it
+ if(LLFile::isfile(newFullPath))
+ {
+ backupFileName = newFullPath + ".backup";
+
+ //If needed store backup file as .backup1 etc.
+ while(LLFile::isfile(backupFileName))
+ {
+ ++backupFileCount;
+ backupFileName = newFullPath + ".backup" + boost::lexical_cast<std::string>(backupFileCount);
+ }
+
+ //Rename the file to its backup name so it is not overwritten
+ LLFile::rename(newFullPath, backupFileName);
+ }
+
+ S32 retry_count = 0;
+ while (retry_count < 5)
+ {
+ //success is zero
+ if (LLFile::rename(fullpath, newFullPath) != 0)
+ {
+ retry_count++;
+ S32 result = errno;
+ LL_WARNS("LLLogChat::moveTranscripts") << "Problem renaming " << fullpath << " - errorcode: "
+ << result << " attempt " << retry_count << LL_ENDL;
+
+ ms_sleep(100);
+ }
+ else
+ {
+ listOfFilesMoved.push_back(newFullPath);
+
+ if (retry_count)
+ {
+ LL_WARNS("LLLogChat::moveTranscripts") << "Successfully renamed " << fullpath << LL_ENDL;
+ }
+ break;
+ }
+ }
+ }
+
+ if(listOfFilesMoved.size() != listOfFilesToMove.size())
+ {
+ movedAllTranscripts = false;
+ }
+
+ return movedAllTranscripts;
+}
+
+//static
+bool LLLogChat::moveTranscripts(const std::string currentDirectory,
+ const std::string newDirectory,
+ std::vector<std::string>& listOfFilesToMove)
+{
+ std::vector<std::string> listOfFilesMoved;
+ return moveTranscripts(currentDirectory, newDirectory, listOfFilesToMove, listOfFilesMoved);
+}
+
+//static
void LLLogChat::deleteTranscripts()
{
std::vector<std::string> list_of_transcriptions;
getListOfTranscriptFiles(list_of_transcriptions);
+ getListOfTranscriptBackupFiles(list_of_transcriptions);
BOOST_FOREACH(const std::string& fullpath, list_of_transcriptions)
{
@@ -540,6 +630,31 @@ void LLLogChat::deleteTranscripts()
LLFloaterIMSessionTab::processChatHistoryStyleUpdate(true);
}
+// static
+bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id)
+{
+ std::vector<std::string> list_of_transcriptions;
+ LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+
+ if (list_of_transcriptions.size() > 0)
+ {
+ LLAvatarName avatar_name;
+ LLAvatarNameCache::get(avatar_id, &avatar_name);
+ std::string avatar_user_name = avatar_name.getAccountName();
+ std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_');
+
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (std::string::npos != transcript_file_name.find(avatar_user_name))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 5fbb4ade96..e819f00dd9 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -49,14 +49,25 @@ public:
const std::string& from,
const LLUUID& from_id,
const std::string& line);
+ static void findTranscriptFiles(std::string pattern, std::vector<std::string>& list_of_transcriptions);
static void getListOfTranscriptFiles(std::vector<std::string>& list);
+ static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions);
static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD());
typedef boost::signals2::signal<void ()> save_history_signal_t;
static boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb);
+ static bool moveTranscripts(const std::string currentDirectory,
+ const std::string newDirectory,
+ std::vector<std::string>& listOfFilesToMove,
+ std::vector<std::string>& listOfFilesMoved);
+ static bool moveTranscripts(const std::string currentDirectory,
+ const std::string newDirectory,
+ std::vector<std::string>& listOfFilesToMove);
+
static void deleteTranscripts();
+ static bool isTranscriptExist(const LLUUID& avatar_id);
private:
static std::string cleanFileName(std::string filename);
diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp
index f6e3c0cac0..6c26073d5b 100644
--- a/indra/newview/lloutputmonitorctrl.cpp
+++ b/indra/newview/lloutputmonitorctrl.cpp
@@ -284,12 +284,12 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& s
{
if (speaker_id == gAgentID)
{
- setIsMuted(false);
+ mIsMuted = false;
}
else
{
// check only blocking on voice. EXT-3542
- setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat));
+ mIsMuted = LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat);
LLMuteList::getInstance()->addObserver(this);
}
}
@@ -298,7 +298,7 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& s
void LLOutputMonitorCtrl::onChange()
{
// check only blocking on voice. EXT-3542
- setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat));
+ mIsMuted = LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat);
}
// virtual
diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h
index af2fd45823..a346909027 100644
--- a/indra/newview/lloutputmonitorctrl.h
+++ b/indra/newview/lloutputmonitorctrl.h
@@ -73,9 +73,6 @@ public:
void setPower(F32 val);
F32 getPower(F32 val) const { return mPower; }
- bool getIsMuted() const { return mIsMuted; }
- void setIsMuted(bool val) { mIsMuted = val; }
-
// For the current user, need to know the PTT state to show
// correct button image.
void setIsAgentControl(bool val) { mIsAgentControl = val; }
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 6667706333..c5283404f1 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -812,19 +812,20 @@ void LLPanelPeople::updateButtons()
else
{
bool is_friend = true;
-
+ bool is_self = false;
// Check whether selected avatar is our friend.
if (item_selected)
{
selected_id = selected_uuids.front();
is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;
+ is_self = gAgent.getID() == selected_id;
}
LLPanel* cur_panel = mTabContainer->getCurrentPanel();
if (cur_panel)
{
if (cur_panel->hasChild("add_friend_btn", TRUE))
- cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend);
+ cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self);
if (friends_tab_active)
{
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 61e9468ce5..47d6b49a50 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -37,6 +37,7 @@
#include "llagentdata.h" // for gAgentID
#include "llavataractions.h"
#include "llcallingcard.h" // for LLAvatarTracker
+#include "lllogchat.h"
#include "llviewermenu.h" // for gMenuHolder
namespace LLPanelPeopleMenus
@@ -180,7 +181,11 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata)
{
return LLAvatarActions::canOfferTeleport(mUUIDs);
}
- else if (item == std::string("can_im") || item == std::string("can_callog") || item == std::string("can_invite") ||
+ else if (item == std::string("can_callog"))
+ {
+ return LLLogChat::isTranscriptExist(mUUIDs.front());
+ }
+ else if (item == std::string("can_im") || item == std::string("can_invite") ||
item == std::string("can_share") || item == std::string("can_pay"))
{
return true;
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 05df7261e1..8783d99b11 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<F32> 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_map_t::iterator cur_speaker_it = 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<LLSpeaker> speakerp = setSpeaker(member_it->first, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ LLPointer<LLSpeaker> 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<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
speaker_map_t mSpeakers;
bool mSpeakerListUpdated;
+ LLTimer mGetListTime;
speaker_list_t mSpeakersSorted;
LLFrameTimer mSpeechTimer;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e6e93d81bc..e44a2cc4df 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2515,7 +2515,9 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
{
// let Control-Up and Control-Down through for chat line history,
if (!(key == KEY_UP && mask == MASK_CONTROL)
- && !(key == KEY_DOWN && mask == MASK_CONTROL))
+ && !(key == KEY_DOWN && mask == MASK_CONTROL)
+ && !(key == KEY_UP && mask == MASK_ALT)
+ && !(key == KEY_DOWN && mask == MASK_ALT))
{
switch(key)
{
@@ -2607,7 +2609,10 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
if ((uni_char == 13 && mask != MASK_CONTROL)
|| (uni_char == 3 && mask == MASK_NONE))
{
- return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ if (mask != MASK_ALT)
+ {
+ return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ }
}
// let menus handle navigation (jump) keys
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 157be08f45..c74d9f1292 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -2994,43 +2994,43 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
return;
}
- BOOL new_name = FALSE;
- if (visible_chat != mVisibleChat)
+ BOOL new_name = FALSE;
+ if (visible_chat != mVisibleChat)
+ {
+ mVisibleChat = visible_chat;
+ new_name = TRUE;
+ }
+
+ 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)
{
- mVisibleChat = visible_chat;
- new_name = TRUE;
+ alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION;
}
-
- if (sRenderGroupTitles != mRenderGroupTitles)
+ else
{
- mRenderGroupTitles = sRenderGroupTitles;
- new_name = TRUE;
+ // ...not fading, full alpha
+ alpha = 1.f;
}
-
- // 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;
- }
+ }
+ 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();
@@ -3040,19 +3040,19 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
return;
}
- if (!mNameText)
- {
+ if (!mNameText)
+ {
mNameText = static_cast<LLHUDNameTag*>( 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);
@@ -3303,6 +3303,7 @@ void LLVOAvatar::clearNameTag()
mNameText->setLabel("");
mNameText->setString( "" );
}
+ mTimeVisible.reset();
}
//static
diff --git a/indra/newview/skins/default/xui/en/menu_object_icon.xml b/indra/newview/skins/default/xui/en/menu_object_icon.xml
index 0c8a2af002..2d4f1792c2 100644
--- a/indra/newview/skins/default/xui/en/menu_object_icon.xml
+++ b/indra/newview/skins/default/xui/en/menu_object_icon.xml
@@ -24,4 +24,22 @@
function="ObjectIcon.Action"
parameter="block" />
</menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Show on Map"
+ layout="topleft"
+ name="show_on_map">
+ <menu_item_call.on_click
+ function="ObjectIcon.Action"
+ parameter="map" />
+ </menu_item_call>
+ <menu_item_call
+ label="Teleport to Object Location"
+ layout="topleft"
+ name="teleport_to_object">
+ <menu_item_call.on_click
+ function="ObjectIcon.Action"
+ parameter="teleport" />
+ </menu_item_call>
</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml
index 73f0fa7979..7cd56f257a 100644
--- a/indra/newview/skins/default/xui/en/menu_url_agent.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml
@@ -1,13 +1,27 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<context_menu
layout="topleft"
- name="Url Popup">
+ name="Url Popup">
<menu_item_call
- label="Show Resident Profile"
+ label="View Profile"
layout="topleft"
name="show_agent">
<menu_item_call.on_click
- function="Url.ShowProfile" />
+ function="Url.ShowProfile" />
+ </menu_item_call>
+ <menu_item_call
+ label="Send IM..."
+ layout="topleft"
+ name="send_im">
+ <menu_item_call.on_click
+ function="Url.SendIM" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add Friend..."
+ layout="topleft"
+ name="add_friend">
+ <menu_item_call.on_click
+ function="Url.AddFriend" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/menu_url_group.xml b/indra/newview/skins/default/xui/en/menu_url_group.xml
index c5eaf94d22..2cb125ce09 100644
--- a/indra/newview/skins/default/xui/en/menu_url_group.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_group.xml
@@ -7,7 +7,7 @@
layout="topleft"
name="show_group">
<menu_item_call.on_click
- function="Url.Execute" />
+ function="Url.ShowProfile" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/menu_url_objectim.xml b/indra/newview/skins/default/xui/en/menu_url_objectim.xml
index 35c2269b0d..87ab58e622 100644
--- a/indra/newview/skins/default/xui/en/menu_url_objectim.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_objectim.xml
@@ -3,7 +3,7 @@
layout="topleft"
name="Url Popup">
<menu_item_call
- label="Show Object Information"
+ label="Object Profile..."
layout="topleft"
name="show_object">
<menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index b50deb7d7a..544f06ac0c 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -183,8 +183,7 @@
</menu_item_call>
<menu_item_call
label="Toolbar buttons..."
- name="Toolbars"
- shortcut="control|T">
+ name="Toolbars">
<menu_item_call.on_click
function="Floater.Toggle"
parameter="toybox" />
@@ -223,7 +222,8 @@
tear_off="true">
<menu_item_check
label="Conversations..."
- name="Conversations">
+ name="Conversations"
+ shortcut="control|T">
<menu_item_check.on_check
function="Floater.IsOpen"
parameter="im_container" />
@@ -240,7 +240,7 @@
function="Floater.Visible"
parameter="nearby_chat" />
<menu_item_check.on_click
- function="Floater.Toggle"
+ function="Floater.ToggleOrBringToFront"
parameter="nearby_chat" />
</menu_item_check>
<menu_item_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 3ae9b206a4..c681e39002 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9708,14 +9708,6 @@ No room to sit here, try another spot.
<notification
icon="alertmodal.tga"
- name="AutopilotCanceled"
- type="notify">
- <tag>fail</tag>
-Autopilot canceled
- </notification>
-
- <notification
- icon="alertmodal.tga"
name="ClaimObjectFailedNoPermission"
type="notify">
<tag>fail</tag>
@@ -10006,7 +9998,7 @@ Cannot create large prims that intersect other players. Please re-try when othe
icon="alertmodal.tga"
name="PreferenceChatClearLog"
type="alertmodal">
- This will delete the log of previous conversations. Proceed?
+ This will delete the logs of previous conversations, and any backups of that file.
<tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I delete the log of previous conversations."
@@ -10019,7 +10011,7 @@ Cannot create large prims that intersect other players. Please re-try when othe
icon="alertmodal.tga"
name="PreferenceChatDeleteTranscripts"
type="alertmodal">
- This will delete transcripts for all previous conversations. The list of conversations will not be affected. If you run scripts on your chat transcript files, you may want to proceed with caution. Proceed?
+ This will delete the transcripts for all previous conversations. The list of past conversations will not be affected. All files with the suffixes .txt and txt.backup in the folder [FOLDER] will be deleted.
<tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I delete transcripts."
@@ -10028,4 +10020,15 @@ Cannot create large prims that intersect other players. Please re-try when othe
yestext="OK"/>
</notification>
+ <notification
+ icon="alert.tga"
+ name="PreferenceChatPathChanged"
+ type="alert">
+ Unable to move files. Restored previous path.
+ <usetemplate
+ ignoretext="Unable to move files. Restored previous path."
+ name="okignore"
+ yestext="OK"/>
+ </notification>
+
</notifications>