summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags1
-rw-r--r--doc/contributions.txt1
-rwxr-xr-xindra/llui/llfolderviewitem.cpp2
-rw-r--r--indra/llui/lltabcontainer.cpp2
-rw-r--r--indra/llui/lltextbase.cpp1
-rw-r--r--indra/llui/llurlaction.cpp14
-rw-r--r--indra/llui/llurlaction.h1
-rw-r--r--indra/llvfs/lldir.cpp5
-rw-r--r--indra/llvfs/lldir.h1
-rw-r--r--indra/newview/llconversationlog.cpp37
-rw-r--r--indra/newview/llconversationlog.h13
-rw-r--r--indra/newview/llconversationmodel.cpp29
-rwxr-xr-xindra/newview/llconversationmodel.h6
-rwxr-xr-xindra/newview/llconversationview.cpp14
-rwxr-xr-xindra/newview/llconversationview.h1
-rw-r--r--indra/newview/lldrawable.cpp19
-rw-r--r--indra/newview/llfloaterimcontainer.cpp138
-rw-r--r--indra/newview/llfloaterimcontainer.h8
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp24
-rw-r--r--indra/newview/llfloaterimnearbychat.h1
-rw-r--r--indra/newview/llfloaterimsession.h1
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp42
-rw-r--r--indra/newview/llfloaterimsessiontab.h3
-rwxr-xr-xindra/newview/llfloaterpreference.cpp97
-rw-r--r--indra/newview/llfloaterpreference.h2
-rw-r--r--indra/newview/llimview.cpp5
-rw-r--r--indra/newview/lllogchat.cpp75
-rw-r--r--indra/newview/lllogchat.h8
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp6
-rw-r--r--indra/newview/lloutputmonitorctrl.h3
-rwxr-xr-xindra/newview/llviewerwindow.cpp9
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_agent.xml7
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml19
33 files changed, 480 insertions, 115 deletions
diff --git a/.hgtags b/.hgtags
index 2aa78a5ed0..f45d8381e9 100644
--- a/.hgtags
+++ b/.hgtags
@@ -422,3 +422,4 @@ b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292
a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release
279ef1dfc9b749a6cc499cf190fec0c090b6d682 DRTVWR-288
9b19edaf1d8ddf435f60fbbb444dd25db8f63953 3.5.0-beta1
+c6b3561c7d7ad365eeba669db54eb57b5149ce75 3.5.0-beta2
diff --git a/doc/contributions.txt b/doc/contributions.txt
index e86ef11a72..10c935f9bb 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -748,6 +748,7 @@ Marine Kelley
MartinRJ Fayray
STORM-1844
STORM-1845
+ STORM-1934
Matthew Anthony
Matthew Dowd
VWR-1344
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index f67c134751..fdb4108afb 100755
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -2072,7 +2072,7 @@ LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* it
if (fit != fend)
{
// try selecting child element of this folder
- if ((*fit)->isOpen())
+ if ((*fit)->isOpen() && include_children)
{
result = (*fit)->getPreviousFromChild(NULL);
}
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 91527c68f2..0c43a571b8 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -1483,6 +1483,8 @@ 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);
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7cee9f5b46..4bb819a7f6 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1911,6 +1911,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.SendIM", boost::bind(&LLUrlAction::sendIM, 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));
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index fd9b3d9a6d..fd872eca4b 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -157,3 +157,17 @@ void LLUrlAction::showProfile(std::string url)
}
}
}
+
+void LLUrlAction::sendIM(std::string url)
+{
+ LLURI uri(url);
+ LLSD path_array = uri.pathArray();
+ 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");
+ }
+ }
+}
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index c34960b826..f5f2ceba72 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -76,6 +76,7 @@ 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 void sendIM(std::string url);
/// specify the callbacks to enable this class's functionality
typedef boost::function<void (const std::string&)> url_callback_t;
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index f7bc19574a..6899e9a44a 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -347,6 +347,11 @@ const std::string &LLDir::getLLPluginDir() const
return mLLPluginDir;
}
+const std::string &LLDir::getUserName() const
+{
+ return mUserName;
+}
+
static std::string ELLPathToString(ELLPath location)
{
typedef std::map<ELLPath, const char*> ELLPathMap;
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 95cab65149..cc10ed5bbd 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -104,6 +104,7 @@ class LLDir
const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin
const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins
const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell
+ const std::string &getUserName() const;
// Expanded filename
std::string getExpandedFilename(ELLPath location, const std::string &filename) const;
diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp
index b777edba77..4be169e267 100644
--- a/indra/newview/llconversationlog.cpp
+++ b/indra/newview/llconversationlog.cpp
@@ -31,6 +31,8 @@
#include "llnotificationsutil.h"
#include "lltrans.h"
+#include "boost/lexical_cast.hpp"
+
const int CONVERSATION_LIFETIME = 30; // lifetime of LLConversation is 30 days by spec
struct ConversationParams
@@ -378,6 +380,41 @@ void LLConversationLog::cache()
}
}
+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";
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index fd38556131..58e698de25 100644
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -137,6 +137,7 @@ 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 onClearLog();
void onClearLogResponse(const LLSD& notification, const LLSD& response);
@@ -144,6 +145,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 +171,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/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 73b2c6f88c..74b348cd81 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -527,19 +527,6 @@ 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)
@@ -580,6 +567,7 @@ BOOL LLConversationViewParticipant::handleMouseDown( S32 x, S32 y, MASK mask )
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);
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index f9b45073f4..76d3d079ea 100755
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -130,7 +130,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);
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/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index c5edd11c12..413707baae 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -605,7 +605,7 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
setSelectedSession(LLUUID(NULL));
}
openNearbyChat();
- selectConversationPair(getSelectedSession(), false);
+ selectConversationPair(getSelectedSession(), false, false);
}
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
@@ -759,11 +759,19 @@ void LLFloaterIMContainer::assignResizeLimits()
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->getRect().getWidth() : mConversationsPane->getMinDim())
: (is_conv_pane_expanded? 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;
+ if (is_conv_pane_expanded)
+ {
+ // Save the conversations pane width.
+ gSavedPerAccountSettings.setS32(
+ "ConversationsListPaneWidth",
+ mConversationsPane->getRect().getWidth());
+ }
+
setResizeLimits(new_min_width, getMinHeight());
}
@@ -1096,12 +1104,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 +1170,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 +1212,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))
{
@@ -1339,30 +1347,19 @@ void LLFloaterIMContainer::selectConversation(const LLUUID& session_id)
// Select the conversation *after* (or before if none after) the passed uuid conversation
// Used to change the selection on key hits
-void LLFloaterIMContainer::selectNextConversation(const LLUUID& uuid)
+void LLFloaterIMContainer::selectNextConversationByID(const LLUUID& uuid)
{
- LLFolderViewItem* new_selection = NULL;
- LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid);
- if (widget)
+ bool new_selection = false;
+ selectConversation(uuid);
+ new_selection = selectNextorPreviousConversation(true);
+ if (!new_selection)
{
- new_selection = mConversationsRoot->getNextFromChild(widget, FALSE);
- if (!new_selection)
- {
- new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE);
- }
- }
- if (new_selection)
- {
- LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(new_selection->getViewModelItem());
- if (vmi)
- {
- selectConversationPair(vmi->getUUID(), true);
- }
+ 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);
@@ -1409,7 +1406,7 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
if (!session_floater->hasFocus())
{
BOOL is_minimized = session_floater->isMinimized();
- session_floater->setFocus(TRUE);
+ session_floater->setFocus(focus_floater);
session_floater->setMinimized(is_minimized);
}
}
@@ -1887,16 +1884,81 @@ bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conve
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::selectNextorPreviousConversation(bool select_next)
+{
+ 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);
+ LLFloater* floaterp = get_ptr_in_map(mSessions, getSelectedSession());
+ if(floaterp && !floaterp->isTornOff())
+ {
+ setFocus(TRUE);
+ }
+ 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);
+ // 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 419239f90b..c84d4978ec 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -69,9 +69,11 @@ public:
void returnFloaterToHost();
void showConversation(const LLUUID& session_id);
void selectConversation(const LLUUID& session_id);
- void selectNextConversation(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 selectNextorPreviousConversation(bool select_next);
+ void expandConversation();
/*virtual*/ void tabClose();
void showStub(bool visible);
@@ -109,7 +111,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:
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index a3b81e037a..dfaf4bbdd6 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -150,7 +150,7 @@ void LLFloaterIMNearbyChat::closeHostedFloater()
{
setVisible(FALSE);
}
- floater_container->selectNextConversation(LLUUID());
+ floater_container->selectNextConversationByID(LLUUID());
}
}
@@ -353,6 +353,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 2992c12436..4ad37eb0c7 100644
--- a/indra/newview/llfloaterimnearbychat.h
+++ b/indra/newview/llfloaterimnearbychat.h
@@ -69,6 +69,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..d3fcfbbc56 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -725,6 +725,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");
@@ -918,3 +939,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..d55b021df7 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:
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 688d453789..3f8c23ba83 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -798,13 +798,28 @@ void LLFloaterPreference::onBtnOK()
//Conversation transcript and log path changed so reload conversations based on new location
if(mPriorInstantMessageLogPath.length())
{
- std::string dir_name(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
- updateLogLocation(dir_name);
+ 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
{
@@ -1441,9 +1456,9 @@ void LLFloaterPreference::setAllIgnored()
void LLFloaterPreference::onClickLogPath()
{
- std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
+ 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 ) )
@@ -1457,22 +1472,76 @@ void LLFloaterPreference::onClickLogPath()
//Path changed
if(proposed_name != dir_name)
{
- gSavedPerAccountSettings.setString("InstantMessageLogPath", dir_name);
+ gSavedPerAccountSettings.setString("InstantMessageLogPath", dir_name);
mPriorInstantMessageLogPath = proposed_name;
-
- // enable/disable 'Delete transcripts button
- updateDeleteTranscriptsButton();
- }
+
+ // 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)
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 31c1e2d9e5..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();
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index d69bd89f13..8f3f5145a9 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)
@@ -291,7 +291,8 @@ void on_new_message(const LLSD& msg)
//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 09f816a4e6..448100c5d6 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -502,6 +502,81 @@ 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;
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index b981d9ce04..784786a565 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -56,6 +56,14 @@ public:
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);
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/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/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml
index 73f0fa7979..88ae441bd3 100644
--- a/indra/newview/skins/default/xui/en/menu_url_agent.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml
@@ -3,6 +3,13 @@
layout="topleft"
name="Url Popup">
<menu_item_call
+ label="Send IM"
+ layout="topleft"
+ name="show_agent">
+ <menu_item_call.on_click
+ function="Url.SendIM" />
+ </menu_item_call>
+ <menu_item_call
label="Show Resident Profile"
layout="topleft"
name="show_agent">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 3ae9b206a4..88c02fc84e 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>
@@ -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>