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: [PATCH] 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 +
 .../lldonotdisturbnotificationstorage.cpp     | 53 +++++++++++++++++++
 .../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 4b0a70ffd86..a99047c163f 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 0e15e1cd150..c07933118d8 100644
--- a/indra/newview/llcommunicationchannel.h
+++ b/indra/newview/llcommunicationchannel.h
@@ -48,6 +48,7 @@ class LLCommunicationChannel : public LLNotificationChannel
 	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 ac41a3804ff..764da25b08c 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 60bcd89ec3d..8edb8569b48 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -45,6 +45,7 @@ class LLDoNotDisturbNotificationStorage : public LLSingleton<LLDoNotDisturbNotif
 
 	void saveNotifications();
 	void loadNotifications();
+    void removeIMNotification(const LLUUID& session_id);
 
 protected:
 
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index a17b89af0de..376144951d3 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 3d4a1c44d88..9c836489f3e 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 37a531e99e6..3d5d49294ea 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -86,6 +86,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver
 	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 067f0d19930..e513d2e6d1e 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,
-- 
GitLab