From 69497e645bbefe85d83e85bb353e5fb719263877 Mon Sep 17 00:00:00 2001
From: Gilbert Gonzales <gilbert@lindenlab.com>
Date: Fri, 11 Jan 2013 18:20:29 -0800
Subject: CHUI-668: Not fully complete but as of this commit, have
 functionality to use the user's most intrusive chat notification upon exiting
 from DND mode with IM's. Also if in DND mode, clicking on a conversation line
 item or floater, will flush the DND notifications system of storing that
 conversation. This way upon existing DND mode already responded conversations
 won't be notified to the user.

---
 indra/newview/llcommunicationchannel.cpp           |  8 +++-
 indra/newview/llcommunicationchannel.h             |  1 +
 .../newview/lldonotdisturbnotificationstorage.cpp  | 53 ++++++++++++++++++++++
 indra/newview/lldonotdisturbnotificationstorage.h  |  1 +
 indra/newview/llfloaterimcontainer.cpp             | 10 ++++
 indra/newview/llfloaterpreference.cpp              | 30 ++++++++++++
 indra/newview/llfloaterpreference.h                |  1 +
 indra/newview/llimview.cpp                         | 42 +++++++++++++++--
 8 files changed, 142 insertions(+), 4 deletions(-)

diff --git a/indra/newview/llcommunicationchannel.cpp b/indra/newview/llcommunicationchannel.cpp
index 4b0a70ffd8..a99047c163 100644
--- a/indra/newview/llcommunicationchannel.cpp
+++ b/indra/newview/llcommunicationchannel.cpp
@@ -67,12 +67,18 @@ void LLCommunicationChannel::clearHistory()
 	mHistory.clear();
 }
 
+void LLCommunicationChannel::removeItem(history_list_t::const_iterator itemToRemove)
+{
+    mHistory.erase(itemToRemove);
+}
+
 void LLCommunicationChannel::onFilterFail(LLNotificationPtr pNotificationPtr)
 {
 	std::string notificationType = pNotificationPtr->getType();
 	if ((notificationType == "groupnotify")
 		|| (notificationType == "offer")
-		|| (notificationType == "notifytoast"))
+		|| (notificationType == "notifytoast")
+        && !pNotificationPtr->isCancelled())
 	{
 		mHistory.insert(std::make_pair<LLDate, LLNotificationPtr>(pNotificationPtr->getDate(), pNotificationPtr));
 	}
diff --git a/indra/newview/llcommunicationchannel.h b/indra/newview/llcommunicationchannel.h
index 0e15e1cd15..c07933118d 100644
--- a/indra/newview/llcommunicationchannel.h
+++ b/indra/newview/llcommunicationchannel.h
@@ -48,6 +48,7 @@ public:
 	history_list_t::const_iterator endHistory() const;
 	
 	void clearHistory();
+    void removeItem(history_list_t::const_iterator itemToRemove);
 
 protected:
 	virtual void onFilterFail(LLNotificationPtr pNotificationPtr);
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index ac41a3804f..764da25b08 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -41,6 +41,8 @@
 #include "llsingleton.h"
 #include "lluuid.h"
 
+extern void useMostItrusiveIMNotification();
+
 LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()
 	: LLSingleton<LLDoNotDisturbNotificationStorage>()
 	, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"))
@@ -103,15 +105,22 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 	}
 	
 	LLNotifications& instance = LLNotifications::instance();
+    bool imToastExists = false;
 	
 	for (LLSD::array_const_iterator notification_it = data.beginArray();
 		 notification_it != data.endArray();
 		 ++notification_it)
 	{
 		LLSD notification_params = *notification_it;
+        const std::string notificationName = notification_params["name"].asString();
         const LLUUID& notificationID = notification_params["id"];
         LLNotificationPtr notification = instance.find(notificationID);
 		
+        if(notificationName == "IMToast")
+        {
+            imToastExists = true;
+        }
+
         //Notification already exists in notification pipeline (same instance of app running)
 		if (notification)
 		{
@@ -138,6 +147,11 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 		}
 	}
 
+    if(imToastExists)
+    {
+        useMostItrusiveIMNotification();
+    }
+
 	// Clear the communication channel history and rewrite the save file to empty it as well
 	LLNotificationChannelPtr channelPtr = getCommunicationChannel();
 	LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
@@ -154,6 +168,45 @@ LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChan
 	return channelPtr;
 }
 
+void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& session_id)
+{
+    LLNotifications& instance = LLNotifications::instance();
+    LLNotificationChannelPtr channelPtr = getCommunicationChannel();
+    LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
+    LLNotificationPtr notification;
+    LLSD substitutions;
+    LLUUID notificationSessionID;
+    LLCommunicationChannel::history_list_t::const_iterator it;
+    std::vector<LLCommunicationChannel::history_list_t::const_iterator> itemsToRemove;
+
+    //Find notification with the matching session id
+    for (it = commChannel->beginHistory();
+        it != commChannel->endHistory(); 
+        ++it)
+    {
+        notification = it->second;
+        substitutions = notification->getSubstitutions();
+        notificationSessionID = substitutions["SESSION_ID"].asUUID();
+
+        if(session_id == notificationSessionID)
+        {
+            itemsToRemove.push_back(it);
+        }
+    }
+
+    //Remove the notification
+    while(itemsToRemove.size())
+    {
+        it = itemsToRemove.back();
+        notification = it->second;
+        commChannel->removeItem(it);
+        //instance.cancel triggers onChannelChanged to be called within LLNotificationChannelBase::updateItem (which save changes to the .xml file)
+        //but this means that saveNotifications write a file each time as well, BAD! Will find a way to prevent this.
+        instance.cancel(notification);
+        itemsToRemove.pop_back();
+    }
+}
+
 
 bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload)
 {
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index 60bcd89ec3..8edb8569b4 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -45,6 +45,7 @@ public:
 
 	void saveNotifications();
 	void loadNotifications();
+    void removeIMNotification(const LLUUID& session_id);
 
 protected:
 
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index a17b89af0d..376144951d 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -39,6 +39,7 @@
 #include "llavatariconctrl.h"
 #include "llavatarnamecache.h"
 #include "llcallbacklist.h"
+#include "lldonotdisturbnotificationstorage.h"
 #include "llgroupactions.h"
 #include "llgroupiconctrl.h"
 #include "llflashtimer.h"
@@ -1291,6 +1292,10 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
     	if (widget && widget->getParentFolder())
     	{
     		widget->getParentFolder()->setSelection(widget, FALSE, FALSE);
+            if(gAgent.isDoNotDisturb())
+            {
+                LLDoNotDisturbNotificationStorage::getInstance()->removeIMNotification(session_id);
+            }
     	}
     }
 
@@ -1312,6 +1317,11 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
 				// Switch to the conversation floater that is being selected
 				selectFloater(session_floater);
 			}
+
+            if(gAgent.isDoNotDisturb())
+            {
+                LLDoNotDisturbNotificationStorage::getInstance()->removeIMNotification(session_id);
+            }
 		}
 
 		// Set the focus on the selected floater
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 3d4a1c44d8..9c836489f3 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1624,6 +1624,36 @@ void LLFloaterPreference::selectChatPanel()
 	selectPanel("chat");
 }
 
+S32 LLFloaterPreference::getHighestNotificationIndex() //change this name
+{
+    static const S32 comboBoxNamesLength = 5;
+    static std::string comboBoxNames[comboBoxNamesLength] = {"NearbyChatOptions",
+                                            "FriendIMOptions",
+                                            "NonFriendIMOptions",
+                                            "ConferenceIMOptions",
+                                            "GroupChatOptions"};
+    S32 selectedIndex;
+    S32 priorityindex = 3;
+    LLComboBox * comboBox;
+
+    for(S32 i = 0; i < comboBoxNamesLength; ++i)
+    {
+        comboBox = getChild<LLComboBox>(comboBoxNames[i]);
+
+        if(comboBox)
+        {
+            selectedIndex = comboBox->getCurrentIndex();
+
+            if(selectedIndex < priorityindex)
+            {
+                priorityindex = selectedIndex;
+            }
+        }
+    }
+
+    return priorityindex;
+}
+
 //------------------------------Updater---------------------------------------
 
 static bool handleBandwidthChanged(const LLSD& newvalue)
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 37a531e99e..3d5d49294e 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -86,6 +86,7 @@ public:
 	void saveAvatarProperties( void );
 	void selectPrivacyPanel();
 	void selectChatPanel();
+    S32 getHighestNotificationIndex();
 
 protected:	
 	void		onBtnOK();
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 067f0d1993..e513d2e6d1 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -52,6 +52,7 @@
 #include "llchat.h"
 #include "llfloaterimsession.h"
 #include "llfloaterimcontainer.h"
+#include "llfloaterpreference.h"
 #include "llgroupiconctrl.h"
 #include "llmd5.h"
 #include "llmutelist.h"
@@ -128,11 +129,46 @@ void process_dnd_im(const LLSD& notification)
             false, 
             false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
     }
-
-    //Flash toolbar button for now, eventually the user's preference will be taken into account
-    gToolBarView->flashCommand(LLCommandId("chat"), true);
 }
 
+void useMostItrusiveIMNotification()
+{
+    LLFloaterPreference * instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
+    if (instance)
+    {    
+        LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+
+        //conv. floater is closed
+        bool conversation_floater_is_closed =
+            !(  im_box
+            && im_box->isInVisibleChain()
+            && !im_box->isMinimized());
+
+        //conversation floater not focused (visible or not)
+        bool conversation_floater_not_focused =
+            conversation_floater_is_closed || !im_box->hasFocus();
+
+        switch(instance->getHighestNotificationIndex())
+        {
+            //Highest priority to lowest (cases correspond to options in drop down box inside Preferences->Chat)
+
+            //open conversation floater
+            case 0:
+                    LLFloaterReg::showInstance("im_container");
+                break;
+            //pop up message
+            case 1:
+            //flash toolbar button
+            case 2:
+                if(conversation_floater_not_focused)
+                {
+                    gToolBarView->flashCommand(LLCommandId("chat"), true);
+                }
+                break;
+        }
+    }
+
+}
 
 static void on_avatar_name_cache_toast(const LLUUID& agent_id,
 									   const LLAvatarName& av_name,
-- 
cgit v1.2.3


From e42755dd16195244a6743fc3970f24fec08f03b9 Mon Sep 17 00:00:00 2001
From: Gilbert Gonzales <gilbert@lindenlab.com>
Date: Fri, 11 Jan 2013 19:43:12 -0800
Subject: CHUI-668: Now when exiting DND mode, the user's most intrusive
 notification will be used to notify that user (if received IM's during DND
 mode). Nearby chat messages/settings are ignored.

---
 indra/newview/llfloaterpreference.cpp | 11 +++----
 indra/newview/llimview.cpp            | 59 ++++++++++++++++++++++-------------
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9c836489f3..4c74d3a8ef 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1626,12 +1626,11 @@ void LLFloaterPreference::selectChatPanel()
 
 S32 LLFloaterPreference::getHighestNotificationIndex() //change this name
 {
-    static const S32 comboBoxNamesLength = 5;
-    static std::string comboBoxNames[comboBoxNamesLength] = {"NearbyChatOptions",
-                                            "FriendIMOptions",
-                                            "NonFriendIMOptions",
-                                            "ConferenceIMOptions",
-                                            "GroupChatOptions"};
+    static const S32 comboBoxNamesLength = 4;
+    static std::string comboBoxNames[comboBoxNamesLength] = {"FriendIMOptions",
+                                                                "NonFriendIMOptions",
+                                                                "ConferenceIMOptions",
+                                                                "GroupChatOptions"};
     S32 selectedIndex;
     S32 priorityindex = 3;
     LLComboBox * comboBox;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index e513d2e6d1..b29c1484cc 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -134,36 +134,32 @@ void process_dnd_im(const LLSD& notification)
 void useMostItrusiveIMNotification()
 {
     LLFloaterPreference * instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
-    if (instance)
-    {    
-        LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+    LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
 
-        //conv. floater is closed
-        bool conversation_floater_is_closed =
-            !(  im_box
-            && im_box->isInVisibleChain()
-            && !im_box->isMinimized());
+    //conv. floater is closed
+    bool conversation_floater_is_closed =
+        !(  im_box
+        && im_box->isInVisibleChain()
+        && !im_box->isMinimized());
 
-        //conversation floater not focused (visible or not)
-        bool conversation_floater_not_focused =
-            conversation_floater_is_closed || !im_box->hasFocus();
+    //conversation floater not focused (visible or not)
+    bool conversation_floater_not_focused =
+        conversation_floater_is_closed || !im_box->hasFocus();
 
+    //Only notify user of stored DND IM messages when conversation floater isn't focused
+    if (instance && conversation_floater_not_focused)
+    {
         switch(instance->getHighestNotificationIndex())
         {
-            //Highest priority to lowest (cases correspond to options in drop down box inside Preferences->Chat)
-
             //open conversation floater
             case 0:
-                    LLFloaterReg::showInstance("im_container");
+                LLFloaterReg::showInstance("im_container");
                 break;
             //pop up message
             case 1:
             //flash toolbar button
             case 2:
-                if(conversation_floater_not_focused)
-                {
-                    gToolBarView->flashCommand(LLCommandId("chat"), true);
-                }
+                gToolBarView->flashCommand(LLCommandId("chat"), true);
                 break;
         }
     }
@@ -284,13 +280,22 @@ void on_new_message(const LLSD& msg)
     {
     	if (conversation_floater_not_focused)
     	{
-            if(session_floater_not_focused)
+            if(session_floater_not_focused && !gAgent.isDoNotDisturb())
             {
             	//User is not focused on conversation containing the message
                 gToolBarView->flashCommand(LLCommandId("chat"), true);
             }
 
             im_box->flashConversationItemWidget(session_id, true);
+
+            //If a DND message, 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())
+            {
+                LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
+            }
         }
     }
 
@@ -302,8 +307,20 @@ void on_new_message(const LLSD& msg)
             //Flash line item
             im_box->flashConversationItemWidget(session_id, true);
 
-            //Surface conversations floater
-            LLFloaterReg::showInstance("im_container");
+            if(!gAgent.isDoNotDisturb())
+            {
+                //Surface conversations floater
+                LLFloaterReg::showInstance("im_container");
+            }
+
+            //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())
+            {
+                LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
+            }
         }
     }
 }
-- 
cgit v1.2.3


From 0e90e94a4d5cbac2d186f0056821a51078e8d1bd Mon Sep 17 00:00:00 2001
From: Gilbert Gonzales <gilbert@lindenlab.com>
Date: Mon, 14 Jan 2013 17:23:06 -0800
Subject: CHUI-668: The user's most intrusive notification is not used anymore
 when coming out of DND mode with IMs. Adjusted code to just open the
 converseation floater (which was changed also in a prior fix by PE).

---
 indra/newview/lldonotdisturbnotificationstorage.cpp | 13 +++++++++++++
 indra/newview/llimview.cpp                          | 19 +++----------------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index 5cc0ab2081..12ff308a77 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -33,6 +33,7 @@
 #include "lldir.h"
 #include "llerror.h"
 #include "llfasttimer_class.h"
+#include "llfloaterreg.h"
 #include "llnotifications.h"
 #include "llnotificationhandler.h"
 #include "llnotificationstorage.h"
@@ -103,6 +104,7 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 	}
 	
 	LLNotifications& instance = LLNotifications::instance();
+    bool imToastExists = false;
 	
 	for (LLSD::array_const_iterator notification_it = data.beginArray();
 		 notification_it != data.endArray();
@@ -110,8 +112,14 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 	{
 		LLSD notification_params = *notification_it;
         const LLUUID& notificationID = notification_params["id"];
+        std::string notificationName = notification_params["name"];
         LLNotificationPtr notification = instance.find(notificationID);
 
+        if(notificationName == "IMToast")
+        {
+            imToastExists = true;
+        }
+
         //Notification already exists in notification pipeline (same instance of app running)
 		if (notification)
 		{
@@ -138,6 +146,11 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 		}
 	}
 
+    if(imToastExists)
+    {
+        LLFloaterReg::showInstance("im_container");
+    }
+
 	// Clear the communication channel history and rewrite the save file to empty it as well
 	LLNotificationChannelPtr channelPtr = getCommunicationChannel();
 	LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 32b4afcfef..ff171fc0f8 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -128,18 +128,11 @@ void process_dnd_im(const LLSD& notification)
             false, 
             false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
     }
-
-    // open conversation floater
-	LLFloaterIMContainer* container_floater =
-			LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
-	if (container_floater && !(container_floater->isFrontmost()))
-    {
-		container_floater->openFloater();
-		container_floater->setFrontmost(TRUE);
-    }
 }
 
 
+
+
 static void on_avatar_name_cache_toast(const LLUUID& agent_id,
 									   const LLAvatarName& av_name,
 									   LLSD msg)
@@ -2626,13 +2619,7 @@ void LLIMMgr::addMessage(
 	// Open conversation floater if offline messages are present
 	if (is_offline_msg)
     {
-		LLFloaterIMContainer* container_floater =
-				LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
-		if (container_floater && !(container_floater->isFrontmost()))
-		{
-			container_floater->openFloater();
-			container_floater->setFrontmost(TRUE);
-		}
+        LLFloaterReg::showInstance("im_container");
     }
 
 }
-- 
cgit v1.2.3


From de9e2c38126682e5c6215151e3389380a93b8bc0 Mon Sep 17 00:00:00 2001
From: Gilbert Gonzales <gilbert@lindenlab.com>
Date: Tue, 15 Jan 2013 20:36:48 -0800
Subject: CHUI-668: Code review changes

---
 indra/newview/llagent.cpp                          |   2 +-
 indra/newview/llcommunicationchannel.cpp           |  32 +++++-
 indra/newview/llcommunicationchannel.h             |   8 +-
 .../newview/lldonotdisturbnotificationstorage.cpp  | 108 +++++++++++++++++----
 indra/newview/lldonotdisturbnotificationstorage.h  |  21 +++-
 5 files changed, 146 insertions(+), 25 deletions(-)

diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index d28af3eff9..094d502078 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1397,7 +1397,7 @@ void LLAgent::setDoNotDisturb(bool pIsDoNotDisturb)
 	LLNotificationsUI::LLChannelManager::getInstance()->muteAllChannels(pIsDoNotDisturb);
 	if (isDoNotDisturbSwitchedOff)
 	{
-		LLDoNotDisturbNotificationStorage::getInstance()->loadNotifications();
+		LLDoNotDisturbNotificationStorage::getInstance()->updateNotifications();
 	}
 }
 
diff --git a/indra/newview/llcommunicationchannel.cpp b/indra/newview/llcommunicationchannel.cpp
index a99047c163..0821510645 100644
--- a/indra/newview/llcommunicationchannel.cpp
+++ b/indra/newview/llcommunicationchannel.cpp
@@ -52,6 +52,11 @@ bool LLCommunicationChannel::filterByDoNotDisturbStatus(LLNotificationPtr)
 	return !gAgent.isDoNotDisturb();
 }
 
+S32 LLCommunicationChannel::getHistorySize() const
+{
+    return mHistory.size();
+}
+
 LLCommunicationChannel::history_list_t::const_iterator LLCommunicationChannel::beginHistory() const
 {
 	return mHistory.begin();
@@ -62,14 +67,37 @@ LLCommunicationChannel::history_list_t::const_iterator LLCommunicationChannel::e
 	return mHistory.end();
 }
 
+LLCommunicationChannel::history_list_t::iterator LLCommunicationChannel::beginHistory()
+{
+    return mHistory.begin();
+}
+
+LLCommunicationChannel::history_list_t::iterator LLCommunicationChannel::endHistory()
+{
+    return mHistory.end();
+}
+
 void LLCommunicationChannel::clearHistory()
 {
 	mHistory.clear();
 }
 
-void LLCommunicationChannel::removeItem(history_list_t::const_iterator itemToRemove)
+void LLCommunicationChannel::removeItemFromHistory(LLNotificationPtr p)
+{
+    //Find the notification and removes it from mHistory
+    for(history_list_t::iterator it = beginHistory(); it != endHistory(); ++it)
+    {
+        if(it->second == p)
+        {
+            mHistory.erase(it);
+            break;
+        }
+    }
+}
+
+void LLCommunicationChannel::onDelete(LLNotificationPtr p) 
 {
-    mHistory.erase(itemToRemove);
+    removeItemFromHistory(p);
 }
 
 void LLCommunicationChannel::onFilterFail(LLNotificationPtr pNotificationPtr)
diff --git a/indra/newview/llcommunicationchannel.h b/indra/newview/llcommunicationchannel.h
index c07933118d..0d8f7f4387 100644
--- a/indra/newview/llcommunicationchannel.h
+++ b/indra/newview/llcommunicationchannel.h
@@ -44,13 +44,17 @@ public:
 	static bool filterByDoNotDisturbStatus(LLNotificationPtr);
 
 	typedef std::multimap<LLDate, LLNotificationPtr> history_list_t;
+    S32 getHistorySize() const;	
 	history_list_t::const_iterator beginHistory() const;
 	history_list_t::const_iterator endHistory() const;
-	
+    history_list_t::iterator beginHistory();
+    history_list_t::iterator endHistory();	
+
 	void clearHistory();
-    void removeItem(history_list_t::const_iterator itemToRemove);
+    void removeItemFromHistory(LLNotificationPtr p);
 
 protected:
+    virtual void onDelete(LLNotificationPtr p);
 	virtual void onFilterFail(LLNotificationPtr pNotificationPtr);
 
 private:
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index 12ff308a77..42b455c1ce 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -42,9 +42,34 @@
 #include "llsingleton.h"
 #include "lluuid.h"
 
+static const F32 DND_TIMER = 3.0;
+
+LLDoNotDisturbNotificationStorageTimer::LLDoNotDisturbNotificationStorageTimer() : LLEventTimer(DND_TIMER)
+{
+    mEventTimer.start();
+}
+
+LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer()
+{
+    mEventTimer.stop();
+}
+
+BOOL LLDoNotDisturbNotificationStorageTimer::tick()
+{
+    LLDoNotDisturbNotificationStorage * doNotDisturbNotificationStorage =  LLDoNotDisturbNotificationStorage::getInstance();
+
+    if(doNotDisturbNotificationStorage
+        && doNotDisturbNotificationStorage->getDirty())
+    {
+        doNotDisturbNotificationStorage->saveNotifications();
+    }
+    return FALSE;
+}
+
 LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()
 	: LLSingleton<LLDoNotDisturbNotificationStorage>()
 	, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"))
+    , mDirty(false)
 {
 }
 
@@ -57,6 +82,16 @@ void LLDoNotDisturbNotificationStorage::initialize()
 	getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1));
 }
 
+bool LLDoNotDisturbNotificationStorage::getDirty()
+{
+    return mDirty;
+}
+
+void LLDoNotDisturbNotificationStorage::resetDirty()
+{
+    mDirty = false;
+}
+
 static LLFastTimer::DeclareTimer FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications");
 
 void LLDoNotDisturbNotificationStorage::saveNotifications()
@@ -83,6 +118,8 @@ void LLDoNotDisturbNotificationStorage::saveNotifications()
 	}
 
 	writeNotifications(output);
+
+    resetDirty();
 }
 
 static LLFastTimer::DeclareTimer FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifications");
@@ -120,15 +157,7 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
             imToastExists = true;
         }
 
-        //Notification already exists in notification pipeline (same instance of app running)
-		if (notification)
-		{
-            notification->setDND(true);
-			instance.update(notification);
-		}
-        //Notification doesn't exist (different instance since restarted app while in DND mode)
-		else
-		{
+        //New notification needs to be added
             notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true));
 			LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]);
 			if (responder == NULL)
@@ -144,21 +173,58 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 			
 			instance.add(notification);
 		}
-	}
 
     if(imToastExists)
     {
         LLFloaterReg::showInstance("im_container");
     }
 
-	// Clear the communication channel history and rewrite the save file to empty it as well
+    //writes out empty .xml file (since LLCommunicationChannel::mHistory is empty)
+	saveNotifications();
+}
+
+void LLDoNotDisturbNotificationStorage::updateNotifications()
+{
+
 	LLNotificationChannelPtr channelPtr = getCommunicationChannel();
 	LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
 	llassert(commChannel != NULL);
+
+    LLNotifications& instance = LLNotifications::instance();
+    bool imToastExists = false;
+  
+    for (LLCommunicationChannel::history_list_t::const_iterator it = commChannel->beginHistory();
+        it != commChannel->endHistory();
+        ++it)
+    {
+        LLNotificationPtr notification = it->second;
+        std::string notificationName = notification->getName();
+
+        if(notificationName == "IMToast")
+        {
+            imToastExists = true;
+        }
+
+        //Notification already exists in notification pipeline (same instance of app running)
+        if (notification)
+        {
+            notification->setDND(true);
+            instance.update(notification);
+        }
+    }
+
+    if(imToastExists)
+    {   
+        LLFloaterReg::showInstance("im_container");
+    }
+
+    //When exit DND mode, write empty notifications file
+    if(commChannel->getHistorySize())
+    {
 	commChannel->clearHistory();
-	
 	saveNotifications();
 }
+}
 
 LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const
 {
@@ -175,8 +241,8 @@ void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& sessi
     LLNotificationPtr notification;
     LLSD substitutions;
     LLUUID notificationSessionID;
-    LLCommunicationChannel::history_list_t::const_iterator it;
-    std::vector<LLCommunicationChannel::history_list_t::const_iterator> itemsToRemove;
+    LLCommunicationChannel::history_list_t::iterator it;
+    std::vector<LLCommunicationChannel::history_list_t::iterator> itemsToRemove;
 
     //Find notification with the matching session id
     for (it = commChannel->beginHistory();
@@ -193,17 +259,21 @@ void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& sessi
         }
     }
 
-    //Remove the notification
+   
+    //Remove the notifications
+    if(itemsToRemove.size())
+    {
     while(itemsToRemove.size())
     {
         it = itemsToRemove.back();
         notification = it->second;
-        commChannel->removeItem(it);
-        //instance.cancel triggers onChannelChanged to be called within LLNotificationChannelBase::updateItem (which save changes to the .xml file)
-        //but this means that saveNotifications write a file each time as well, BAD! Will find a way to prevent this.
+            commChannel->removeItemFromHistory(notification);
         instance.cancel(notification);
         itemsToRemove.pop_back();
     }
+        //Trigger saving of notifications to xml once all have been removed
+        saveNotifications();
+    }
 }
 
 
@@ -211,7 +281,7 @@ bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload)
 {
 	if (pPayload["sigtype"].asString() != "load")
 	{
-		saveNotifications();
+        mDirty = true;
 	}
 
 	return false;
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index 8edb8569b4..fd03b71357 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -28,12 +28,26 @@
 #define LL_LLDONOTDISTURBNOTIFICATIONSTORAGE_H
 
 #include "llerror.h"
+#include "lleventtimer.h"
 #include "llnotifications.h"
 #include "llnotificationstorage.h"
 #include "llsingleton.h"
 
 class LLSD;
 
+class LLDoNotDisturbNotificationStorageTimer : public LLEventTimer
+{
+public:
+    LLDoNotDisturbNotificationStorageTimer();
+    ~LLDoNotDisturbNotificationStorageTimer();
+
+public:
+    void startTimer();
+    void stopTimer();
+    bool isRunning();
+    BOOL tick();
+};
+
 class LLDoNotDisturbNotificationStorage : public LLSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage
 {
 	LOG_CLASS(LLDoNotDisturbNotificationStorage);
@@ -42,14 +56,19 @@ public:
 	~LLDoNotDisturbNotificationStorage();
 
 	void initialize();
-
+    bool getDirty();
+    void resetDirty();
 	void saveNotifications();
 	void loadNotifications();
+    void updateNotifications();
     void removeIMNotification(const LLUUID& session_id);
 
 protected:
 
 private:
+    bool mDirty;
+    LLDoNotDisturbNotificationStorageTimer mTimer;
+
 	LLNotificationChannelPtr getCommunicationChannel() const;
 	bool                     onChannelChanged(const LLSD& pPayload);
 };
-- 
cgit v1.2.3


From f43f51406b024ed2423e068114ae818bac5c6df5 Mon Sep 17 00:00:00 2001
From: Merov Linden <merov@lindenlab.com>
Date: Wed, 16 Jan 2013 14:53:23 -0800
Subject: CHUI-683 : Default sort order for Blocked was wrong, unrecognized
 value was not tested.

---
 indra/newview/app_settings/settings.xml | 2 +-
 indra/newview/llpanelblockedlist.cpp    | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 126df69519..fd4d1df894 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10215,7 +10215,7 @@
       <key>Type</key>
       <string>U32</string>
       <key>Value</key>
-      <integer>2</integer>
+      <integer>0</integer>
     </map>
     <key>CallLogSortOrder</key>
     <map>
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index df1ccdd9fc..115114bb53 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -89,6 +89,9 @@ BOOL LLPanelBlockedList::postBuild()
 	case E_SORT_BY_TYPE:
 		mBlockedList->sortByType();
 		break;
+	default:
+		llwarns << "Unrecognized sort order for blocked list" << llendl;
+		break;
 	}
 
 	// Use the context menu of the Block list for the Block tab gear menu.
-- 
cgit v1.2.3