From 69cd9ac98bde4d602a8bdb785ac576df958ea1f5 Mon Sep 17 00:00:00 2001
From: Mike Antipov <mantipov@productengine.com>
Date: Fri, 4 Dec 2009 18:31:57 +0200
Subject: Completed normal task EXT-3081 (Separate Message Well on
 Notifications Well and IM Well)  -- created IM Wel icon  -- functionality is
 moved from the base class into appropriate classes (for Notification & IM
 Well windows)

--HG--
branch : product-engine
---
 indra/newview/llchiclet.cpp                        |  32 +-
 indra/newview/llchiclet.h                          |  16 +-
 indra/newview/llsyswellwindow.cpp                  | 418 +++++++++++----------
 indra/newview/llsyswellwindow.h                    | 101 +++--
 .../skins/default/xui/en/panel_bottomtray.xml      |  43 ++-
 5 files changed, 350 insertions(+), 260 deletions(-)

diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 588855d088..5fad030e5b 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -55,6 +55,7 @@
 #include "lltransientfloatermgr.h"
 
 static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
+static LLDefaultChildRegistry::Register<LLSysWellChiclet> t2_0("chiclet_im_well");
 static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
 static LLDefaultChildRegistry::Register<LLIMP2PChiclet> t3("chiclet_im_p2p");
 static LLDefaultChildRegistry::Register<LLIMGroupChiclet> t4("chiclet_im_group");
@@ -69,7 +70,6 @@ static const S32	OVERLAY_ICON_SHIFT = 2;	// used for shifting of an overlay icon
 // static
 const S32 LLChicletPanel::s_scroll_ratio = 10;
 
-S32 LLNotificationChiclet::mUreadSystemNotifications = 0;
 
 boost::signals2::signal<LLChiclet* (const LLUUID&),
 		LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > >
@@ -78,7 +78,7 @@ boost::signals2::signal<LLChiclet* (const LLUUID&),
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
-LLNotificationChiclet::Params::Params()
+LLSysWellChiclet::Params::Params()
 : button("button")
 , unread_notifications("unread_notifications")
 {
@@ -88,27 +88,23 @@ LLNotificationChiclet::Params::Params()
 
 }
 
-LLNotificationChiclet::LLNotificationChiclet(const Params& p)
+LLSysWellChiclet::LLSysWellChiclet(const Params& p)
 : LLChiclet(p)
 , mButton(NULL)
 , mCounter(0)
+, mUreadSystemNotifications(0)
 {
 	LLButton::Params button_params = p.button;
 	mButton = LLUICtrlFactory::create<LLButton>(button_params);
 	addChild(mButton);
-
-	// connect counter handlers to the signals
-	connectCounterUpdatersToSignal("notify");
-	connectCounterUpdatersToSignal("groupnotify");
-	connectCounterUpdatersToSignal("offer");
 }
 
-LLNotificationChiclet::~LLNotificationChiclet()
+LLSysWellChiclet::~LLSysWellChiclet()
 {
 
 }
 
-void LLNotificationChiclet::connectCounterUpdatersToSignal(std::string notification_type)
+void LLSysWellChiclet::connectCounterUpdatersToSignal(std::string notification_type)
 {
 	LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
 	LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
@@ -119,7 +115,7 @@ void LLNotificationChiclet::connectCounterUpdatersToSignal(std::string notificat
 	}
 }
 
-void LLNotificationChiclet::setCounter(S32 counter)
+void LLSysWellChiclet::setCounter(S32 counter)
 {
 	std::string s_count;
 	if(counter != 0)
@@ -132,16 +128,26 @@ void LLNotificationChiclet::setCounter(S32 counter)
 	mCounter = counter;
 }
 
-boost::signals2::connection LLNotificationChiclet::setClickCallback(
+boost::signals2::connection LLSysWellChiclet::setClickCallback(
 	const commit_callback_t& cb)
 {
 	return mButton->setClickedCallback(cb);
 }
 
-void LLNotificationChiclet::setToggleState(BOOL toggled) {
+void LLSysWellChiclet::setToggleState(BOOL toggled) {
 	mButton->setToggleState(toggled);
 }
 
+LLNotificationChiclet::LLNotificationChiclet(const Params& p)
+: LLSysWellChiclet(p)
+{
+	// connect counter handlers to the signals
+	connectCounterUpdatersToSignal("notify");
+	connectCounterUpdatersToSignal("groupnotify");
+	connectCounterUpdatersToSignal("offer");
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index c75ad2b546..7e2d1ea411 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -746,7 +746,7 @@ private:
  * Implements notification chiclet. Used to display total amount of unread messages 
  * across all IM sessions, total amount of system notifications.
  */
-class LLNotificationChiclet : public LLChiclet
+class LLSysWellChiclet : public LLChiclet
 {
 public:
 
@@ -768,7 +768,7 @@ public:
 
 	boost::signals2::connection setClickCallback(const commit_callback_t& cb);
 
-	/*virtual*/ ~LLNotificationChiclet();
+	/*virtual*/ ~LLSysWellChiclet();
 
 	// methods for updating a number of unread System notifications
 	void incUreadSystemNotifications() { setCounter(++mUreadSystemNotifications); }
@@ -779,16 +779,24 @@ protected:
 	// connect counter updaters to the corresponding signals
 	void connectCounterUpdatersToSignal(std::string notification_type);
 
-	LLNotificationChiclet(const Params& p);
+	LLSysWellChiclet(const Params& p);
 	friend class LLUICtrlFactory;
 
-	static S32 mUreadSystemNotifications;
+	S32 mUreadSystemNotifications;
 
 protected:
 	LLButton* mButton;
 	S32 mCounter;
 };
 
+class LLNotificationChiclet : public LLSysWellChiclet
+{
+	friend class LLUICtrlFactory;
+protected:
+	LLNotificationChiclet(const Params& p);
+
+};
+
 /**
  * Storage class for all IM chiclets. Provides mechanism to display, 
  * scroll, create, remove chiclets.
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index a64c200b92..c288301923 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -54,9 +54,6 @@ LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key)
 													mMessageList(NULL),
 													mSeparator(NULL)
 {
-	LLIMMgr::getInstance()->addSessionObserver(this);
-	LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLSysWellWindow::findIMChiclet, this, _1));
-
 	mTypedItemsCount[IT_NOTIFICATION] = 0;
 	mTypedItemsCount[IT_INSTANT_MESSAGE] = 0;
 }
@@ -66,11 +63,6 @@ BOOL LLSysWellWindow::postBuild()
 {
 	mMessageList = getChild<LLFlatListView>("notification_list");
 
-	// init connections to the list's update events
-	connectListUpdaterToSignal("notify");
-	connectListUpdaterToSignal("groupnotify");
-	connectListUpdaterToSignal("offer");
-
 	// get a corresponding channel
 	initChannel();
 
@@ -95,21 +87,6 @@ void LLSysWellWindow::setMinimized(BOOL minimize)
 	LLDockableFloater::setMinimized(minimize);
 }
 
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type)
-{
-	LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
-	LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
-	if(n_handler)
-	{
-		n_handler->setNotificationIDCallback(boost::bind(&LLSysWellWindow::removeItemByID, this, _1));
-	}
-	else
-	{
-		llwarns << "LLSysWellWindow::connectListUpdaterToSignal() - could not get a handler for '" << notification_type <<"' type of notifications" << llendl;
-	}
-}
-
 //---------------------------------------------------------------------------------
 void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask)
 {
@@ -117,54 +94,9 @@ void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask)
 	setVisible(TRUE);
 }
 
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::clearScreenChannels()
-{
-	// 1 - remove StartUp toast and channel if present
-	if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
-	{
-		LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
-	}
-
-	// 2 - remove toasts in Notification channel
-	if(mChannel)
-	{
-		mChannel->removeAndStoreAllStorableToasts();
-	}
-}
-
 //---------------------------------------------------------------------------------
 LLSysWellWindow::~LLSysWellWindow()
 {
-	LLIMMgr::getInstance()->removeSessionObserver(this);
-}
-
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::addItem(LLSysWellItem::Params p)
-{
-	LLSD value = p.notification_id;
-	// do not add clones
-	if( mMessageList->getItemByValue(value))
-		return;
-
-	LLSysWellItem* new_item = new LLSysWellItem(p);
-	if (mMessageList->addItem(new_item, value, ADD_TOP))
-	{
-		handleItemAdded(IT_NOTIFICATION);
-
-		reshapeWindow();
-
-		new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1));
-		new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1));
-	}
-	else
-	{
-		llwarns << "Unable to add Notification into the list, notification ID: " << p.notification_id
-			<< ", title: " << p.title
-			<< llendl;
-
-		new_item->die();
-	}
 }
 
 //---------------------------------------------------------------------------------
@@ -195,42 +127,13 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id)
 }
 
 //---------------------------------------------------------------------------------
-void LLSysWellWindow::onItemClick(LLSysWellItem* item)
-{
-	LLUUID id = item->getID();
-	if(mChannel)
-		mChannel->loadStoredToastByNotificationIDToChannel(id);
-}
-
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::onItemClose(LLSysWellItem* item)
-{
-	LLUUID id = item->getID();
-	removeItemByID(id);
-	if(mChannel)
-		mChannel->killToastByNotificationID(id);
-}
-
-//--------------------------------------------------------------------------
-void LLSysWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id)
-{
-	LLSysWellItem::Params p;	
-	p.notification_id = id;
-	p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
-	addItem(p);
-}
-
 //---------------------------------------------------------------------------------
 void LLSysWellWindow::initChannel() 
 {
 	LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
 																LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
 	mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
-	if(mChannel)
-	{
-		mChannel->setOnStoreToastCallback(boost::bind(&LLSysWellWindow::onStoreToast, this, _1, _2));
-	}
-	else
+	if(NULL == mChannel)
 	{
 		llwarns << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << llendl;
 	}
@@ -256,9 +159,6 @@ void LLSysWellWindow::setVisible(BOOL visible)
 				LLBottomTray::getInstance()->getChild<LLView>(NOTIFICATION_WELL_ANCHOR_NAME), this,
 				getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getAllowedRect, this, _1)));
 		}
-
-		// when Notification channel is cleared, storable toasts will be added into the list.
-		clearScreenChannels();
 	}
 
 	// do not show empty window
@@ -317,63 +217,6 @@ void LLSysWellWindow::reshapeWindow()
 	}
 }
 
-//---------------------------------------------------------------------------------
-LLChiclet* LLSysWellWindow::findIMChiclet(const LLUUID& sessionId)
-{
-	LLChiclet* res = NULL;
-	RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(sessionId);
-	if (panel != NULL)
-	{
-		res = panel->mChiclet;
-	}
-
-	return res;
-}
-
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
-		const std::string& name, const LLUUID& otherParticipantId)
-{
-	RowPanel* item = new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId);
-	if (mMessageList->insertItemAfter(mSeparator, item, sessionId))
-	{
-		handleItemAdded(IT_INSTANT_MESSAGE);
-	}
-	else
-	{
-		llwarns << "Unable to add IM Row into the list, sessionID: " << sessionId
-			<< ", name: " << name
-			<< ", other participant ID: " << otherParticipantId
-			<< llendl;
-
-		item->die();
-	}
-}
-
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::delIMRow(const LLUUID& sessionId)
-{
-	if (mMessageList->removeItemByValue(sessionId))
-	{
-		handleItemRemoved(IT_INSTANT_MESSAGE);
-	}
-	else
-	{
-		llwarns << "Unable to remove IM Row from the list, sessionID: " << sessionId
-			<< llendl;
-	}
-
-	// remove all toasts that belong to this session from a screen
-	if(mChannel)
-		mChannel->removeToastsBySessionID(sessionId);
-
-	// hide chiclet window if there are no items left
-	if(isWindowEmpty())
-	{
-		setVisible(FALSE);
-	}
-}
-
 //---------------------------------------------------------------------------------
 bool LLSysWellWindow::isWindowEmpty()
 {
@@ -381,41 +224,7 @@ bool LLSysWellWindow::isWindowEmpty()
 	return mMessageList->size() == 1;
 }
 
-//---------------------------------------------------------------------------------
-//virtual
-void LLSysWellWindow::sessionAdded(const LLUUID& session_id,
-		const std::string& name, const LLUUID& other_participant_id)
-{
-	if (mMessageList->getItemByValue(session_id) == NULL)
-	{
-		S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id);
-		if (chicletCounter > -1)
-		{
-			addIMRow(session_id, chicletCounter, name, other_participant_id);	
-			reshapeWindow();
-		}
-	}
-}
-
-//---------------------------------------------------------------------------------
-//virtual
-void LLSysWellWindow::sessionRemoved(const LLUUID& sessionId)
-{
-	delIMRow(sessionId);
-	reshapeWindow();
-}
-
-void LLSysWellWindow::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
-{
-	//for outgoing ad-hoc and group im sessions only
-	LLChiclet* chiclet = findIMChiclet(old_session_id);
-	if (chiclet)
-	{
-		chiclet->setSessionId(new_session_id);
-		mMessageList->updateValue(old_session_id, new_session_id);
-	}
-}
-
+// *TODO: mantipov: probably is deprecated
 void LLSysWellWindow::handleItemAdded(EItemType added_item_type)
 {
 	bool should_be_shown = ++mTypedItemsCount[added_item_type] == 1 && anotherTypeExists(added_item_type);
@@ -463,8 +272,12 @@ bool LLSysWellWindow::anotherTypeExists(EItemType item_type)
 	return exists;
 }
 
+/************************************************************************/
+/*         RowPanel implementation                                      */
+/************************************************************************/
+
 //---------------------------------------------------------------------------------
-LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId,
+LLIMWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId,
 		S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId) :
 		LLPanel(LLPanel::Params()), mChiclet(NULL), mParent(parent)
 {
@@ -499,36 +312,36 @@ LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID&
 	contactName->setValue(name);
 
 	mCloseBtn = getChild<LLButton>("hide_btn");
-	mCloseBtn->setCommitCallback(boost::bind(&LLSysWellWindow::RowPanel::onClosePanel, this));
+	mCloseBtn->setCommitCallback(boost::bind(&LLIMWellWindow::RowPanel::onClosePanel, this));
 }
 
 //---------------------------------------------------------------------------------
-LLSysWellWindow::RowPanel::~RowPanel()
+LLIMWellWindow::RowPanel::~RowPanel()
 {
 }
 
 //---------------------------------------------------------------------------------
-void LLSysWellWindow::RowPanel::onClosePanel()
+void LLIMWellWindow::RowPanel::onClosePanel()
 {
 	gIMMgr->leaveSession(mChiclet->getSessionId());
 	// This row panel will be removed from the list in LLSysWellWindow::sessionRemoved().
 }
 
 //---------------------------------------------------------------------------------
-void LLSysWellWindow::RowPanel::onMouseEnter(S32 x, S32 y, MASK mask)
+void LLIMWellWindow::RowPanel::onMouseEnter(S32 x, S32 y, MASK mask)
 {
 	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemSelected"));
 }
 
 //---------------------------------------------------------------------------------
-void LLSysWellWindow::RowPanel::onMouseLeave(S32 x, S32 y, MASK mask)
+void LLIMWellWindow::RowPanel::onMouseLeave(S32 x, S32 y, MASK mask)
 {
 	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemUnselected"));
 }
 
 //---------------------------------------------------------------------------------
 // virtual
-BOOL LLSysWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask)
+BOOL LLIMWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	// Pass the mouse down event to the chiclet (EXT-596).
 	if (!mChiclet->pointInView(x, y) && !mCloseBtn->getRect().pointInRect(x, y)) // prevent double call of LLIMChiclet::onMouseDown()
@@ -548,7 +361,10 @@ BOOL LLSysWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask)
 LLNotificationWellWindow::LLNotificationWellWindow(const LLSD& key)
 : LLSysWellWindow(key)
 {
-
+	// init connections to the list's update events
+	connectListUpdaterToSignal("notify");
+	connectListUpdaterToSignal("groupnotify");
+	connectListUpdaterToSignal("offer");
 }
 
 // static
@@ -557,6 +373,108 @@ LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key
 	return LLFloaterReg::getTypedInstance<LLNotificationWellWindow>("notification_well_window", key);
 }
 
+void LLNotificationWellWindow::setVisible(BOOL visible)
+{
+	if (visible)
+	{
+		// when Notification channel is cleared, storable toasts will be added into the list.
+		clearScreenChannels();
+	}
+
+	LLSysWellWindow::setVisible(visible);
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
+{
+	LLSD value = p.notification_id;
+	// do not add clones
+	if( mMessageList->getItemByValue(value))
+		return;
+
+	LLSysWellItem* new_item = new LLSysWellItem(p);
+	if (mMessageList->addItem(new_item, value, ADD_TOP))
+	{
+		handleItemAdded(IT_NOTIFICATION);
+
+		reshapeWindow();
+
+		new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
+		new_item->setOnItemClickCallback(boost::bind(&LLNotificationWellWindow::onItemClick, this, _1));
+	}
+	else
+	{
+		llwarns << "Unable to add Notification into the list, notification ID: " << p.notification_id
+			<< ", title: " << p.title
+			<< llendl;
+
+		new_item->die();
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PRIVATE METHODS
+void LLNotificationWellWindow::initChannel() 
+{
+	LLSysWellWindow::initChannel();
+	if(mChannel)
+	{
+		mChannel->setOnStoreToastCallback(boost::bind(&LLNotificationWellWindow::onStoreToast, this, _1, _2));
+	}
+}
+
+void LLNotificationWellWindow::clearScreenChannels()
+{
+	// 1 - remove StartUp toast and channel if present
+	if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
+	{
+		LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
+	}
+
+	// 2 - remove toasts in Notification channel
+	if(mChannel)
+	{
+		mChannel->removeAndStoreAllStorableToasts();
+	}
+}
+
+void LLNotificationWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id)
+{
+	LLSysWellItem::Params p;	
+	p.notification_id = id;
+	p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
+	addItem(p);
+}
+
+void LLNotificationWellWindow::connectListUpdaterToSignal(std::string notification_type)
+{
+	LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
+	LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
+	if(n_handler)
+	{
+		n_handler->setNotificationIDCallback(boost::bind(&LLNotificationWellWindow::removeItemByID, this, _1));
+	}
+	else
+	{
+		llwarns << "LLSysWellWindow::connectListUpdaterToSignal() - could not get a handler for '" << notification_type <<"' type of notifications" << llendl;
+	}
+}
+
+void LLNotificationWellWindow::onItemClick(LLSysWellItem* item)
+{
+	LLUUID id = item->getID();
+	if(mChannel)
+		mChannel->loadStoredToastByNotificationIDToChannel(id);
+}
+
+void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)
+{
+	LLUUID id = item->getID();
+	removeItemByID(id);
+	if(mChannel)
+		mChannel->killToastByNotificationID(id);
+}
+
 
 
 /************************************************************************/
@@ -568,7 +486,13 @@ LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key
 LLIMWellWindow::LLIMWellWindow(const LLSD& key)
 : LLSysWellWindow(key)
 {
+	LLIMMgr::getInstance()->addSessionObserver(this);
+	LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findIMChiclet, this, _1));
+}
 
+LLIMWellWindow::~LLIMWellWindow()
+{
+	LLIMMgr::getInstance()->removeSessionObserver(this);
 }
 
 // static
@@ -577,4 +501,96 @@ LLIMWellWindow* LLIMWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
 	return LLFloaterReg::getTypedInstance<LLIMWellWindow>("im_well_window", key);
 }
 
+//virtual
+void LLIMWellWindow::sessionAdded(const LLUUID& session_id,
+								   const std::string& name, const LLUUID& other_participant_id)
+{
+	if (mMessageList->getItemByValue(session_id) == NULL)
+	{
+		S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id);
+		if (chicletCounter > -1)
+		{
+			addIMRow(session_id, chicletCounter, name, other_participant_id);	
+			reshapeWindow();
+		}
+	}
+}
+
+//virtual
+void LLIMWellWindow::sessionRemoved(const LLUUID& sessionId)
+{
+	delIMRow(sessionId);
+	reshapeWindow();
+}
+
+//virtual
+void LLIMWellWindow::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
+{
+	//for outgoing ad-hoc and group im sessions only
+	LLChiclet* chiclet = findIMChiclet(old_session_id);
+	if (chiclet)
+	{
+		chiclet->setSessionId(new_session_id);
+		mMessageList->updateValue(old_session_id, new_session_id);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PRIVATE METHODS
+LLChiclet* LLIMWellWindow::findIMChiclet(const LLUUID& sessionId)
+{
+	LLChiclet* res = NULL;
+	RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(sessionId);
+	if (panel != NULL)
+	{
+		res = panel->mChiclet;
+	}
+
+	return res;
+}
+
+//---------------------------------------------------------------------------------
+void LLIMWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
+							   const std::string& name, const LLUUID& otherParticipantId)
+{
+	RowPanel* item = new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId);
+	if (mMessageList->insertItemAfter(mSeparator, item, sessionId))
+	{
+		handleItemAdded(IT_INSTANT_MESSAGE);
+	}
+	else
+	{
+		llwarns << "Unable to add IM Row into the list, sessionID: " << sessionId
+			<< ", name: " << name
+			<< ", other participant ID: " << otherParticipantId
+			<< llendl;
+
+		item->die();
+	}
+}
+
+//---------------------------------------------------------------------------------
+void LLIMWellWindow::delIMRow(const LLUUID& sessionId)
+{
+	if (mMessageList->removeItemByValue(sessionId))
+	{
+		handleItemRemoved(IT_INSTANT_MESSAGE);
+	}
+	else
+	{
+		llwarns << "Unable to remove IM Row from the list, sessionID: " << sessionId
+			<< llendl;
+	}
+
+	// remove all toasts that belong to this session from a screen
+	if(mChannel)
+		mChannel->removeToastsBySessionID(sessionId);
+
+	// hide chiclet window if there are no items left
+	if(isWindowEmpty())
+	{
+		setVisible(FALSE);
+	}
+}
+
 // EOF
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 04596c0622..21391cebea 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -47,7 +47,7 @@ class LLFlatListView;
 class LLChiclet;
 class LLIMChiclet;
 
-class LLSysWellWindow : public LLDockableFloater, LLIMSessionObserver
+class LLSysWellWindow : public LLDockableFloater
 {
 public:
     LLSysWellWindow(const LLSD& key);
@@ -59,7 +59,6 @@ public:
 	bool isWindowEmpty();
 
 	// Operating with items
-	void addItem(LLSysWellItem::Params p);
     void clear( void );
 	void removeItemByID(const LLUUID& id);
 
@@ -70,18 +69,13 @@ public:
 	// override LLFloater's minimization according to EXT-1216
 	/*virtual*/ void	setMinimized(BOOL minimize);
 
-	// Handlers
-	void onItemClick(LLSysWellItem* item);
-	void onItemClose(LLSysWellItem* item);
-	void onStoreToast(LLPanel* info_panel, LLUUID id);
-	void clearScreenChannels();
 	void onStartUpToastClick(S32 x, S32 y, MASK mask);
 
 	// size constants for the window and for its elements
 	static const S32 MAX_WINDOW_HEIGHT		= 200;
 	static const S32 MIN_WINDOW_WIDTH		= 318;
 
-private:
+protected:
 
 	typedef enum{
 		IT_NOTIFICATION,
@@ -90,25 +84,17 @@ private:
 
 	// gets a rect that bounds possible positions for the SysWellWindow on a screen (EXT-1111)
 	void getAllowedRect(LLRect& rect);
-	// connect counter and list updaters to the corresponding signals
-	void connectListUpdaterToSignal(std::string notification_type);
+
+
 	// init Window's channel
-	void initChannel();
+	virtual void initChannel();
 	void handleItemAdded(EItemType added_item_type);
 	void handleItemRemoved(EItemType removed_item_type);
 	bool anotherTypeExists(EItemType item_type) ;
 
 
 
-	class RowPanel;
 	void reshapeWindow();
-	LLChiclet * findIMChiclet(const LLUUID& sessionId);
-	void addIMRow(const LLUUID& sessionId, S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId);
-	void delIMRow(const LLUUID& sessionId);
-	// LLIMSessionObserver observe triggers
-	virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
-	virtual void sessionRemoved(const LLUUID& session_id);
-	void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
 
 	// pointer to a corresponding channel's instance
 	LLNotificationsUI::LLScreenChannel*	mChannel;
@@ -124,27 +110,6 @@ private:
 	typedef std::map<EItemType, S32> typed_items_count_t;
 	typed_items_count_t mTypedItemsCount;
 
-private:
-	/**
-	 * Scrolling row panel.
-	 */
-	class RowPanel: public LLPanel
-	{
-	public:
-		RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId, S32 chicletCounter,
-				const std::string& name, const LLUUID& otherParticipantId);
-		virtual ~RowPanel();
-		void onMouseEnter(S32 x, S32 y, MASK mask);
-		void onMouseLeave(S32 x, S32 y, MASK mask);
-		BOOL handleMouseDown(S32 x, S32 y, MASK mask);
-	private:
-		void onClosePanel();
-	public:
-		LLIMChiclet* mChiclet;
-	private:
-		LLButton*	mCloseBtn;
-		const LLSysWellWindow* mParent;
-	};
 };
 
 /**
@@ -160,6 +125,25 @@ public:
 
 	static void initClass() { getInstance(); }
 
+	/*virtual*/ void setVisible(BOOL visible);
+
+	// Operating with items
+	void addItem(LLSysWellItem::Params p);
+
+private:
+	// init Window's channel
+	void initChannel();
+	void clearScreenChannels();
+
+	void onStoreToast(LLPanel* info_panel, LLUUID id);
+
+	// connect counter and list updaters to the corresponding signals
+	void connectListUpdaterToSignal(std::string notification_type);
+
+	// Handlers
+	void onItemClick(LLSysWellItem* item);
+	void onItemClose(LLSysWellItem* item);
+
 };
 
 /**
@@ -167,11 +151,46 @@ public:
  * 
  * It contains a list list of all active IM sessions.
  */
-class LLIMWellWindow : public LLSysWellWindow
+class LLIMWellWindow : public LLSysWellWindow, LLIMSessionObserver, LLInitClass<LLIMWellWindow>
 {
 public:
 	LLIMWellWindow(const LLSD& key);
+	~LLIMWellWindow();
+
 	static LLIMWellWindow* getInstance(const LLSD& key = LLSD());
+	static void initClass() { getInstance(); }
+
+	// LLIMSessionObserver observe triggers
+	/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+	/*virtual*/ void sessionRemoved(const LLUUID& session_id);
+	/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
+
+private:
+	LLChiclet * findIMChiclet(const LLUUID& sessionId);
+	void addIMRow(const LLUUID& sessionId, S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId);
+	void delIMRow(const LLUUID& sessionId);
+
+
+	/**
+	 * Scrolling row panel.
+	 */
+	class RowPanel: public LLPanel
+	{
+	public:
+		RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId, S32 chicletCounter,
+				const std::string& name, const LLUUID& otherParticipantId);
+		virtual ~RowPanel();
+		void onMouseEnter(S32 x, S32 y, MASK mask);
+		void onMouseLeave(S32 x, S32 y, MASK mask);
+		BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	private:
+		void onClosePanel();
+	public:
+		LLIMChiclet* mChiclet;
+	private:
+		LLButton*	mCloseBtn;
+		const LLSysWellWindow* mParent;
+	};
 };
 
 #endif // LL_LLSYSWELLWINDOW_H
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index 2796b4a1f7..7f847237ce 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -312,6 +312,47 @@ as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly.
          min_width="4" 
          top="0"
          width="5"/>
+        <layout_panel
+         auto_resize="false"
+         follows="right"
+         height="28"
+         layout="topleft"
+         min_height="28"
+         top="0"
+         name="im_well_panel"
+         width="34"
+         min_width="34"
+         user_resize="false">
+            <chiclet_im_well
+             follows="right"
+             height="23"
+             layout="topleft"
+             left="0"
+             name="im_well"
+             top="4"
+             width="34">
+                <button
+                 auto_resize="true"
+                 flash_color="EmphasisColor"
+                 follows="right"
+                 halign="center"
+                 height="23"
+                 image_overlay="Notices_Unread"
+                 image_overlay_alignment="center" 
+                 image_pressed="PushButton_Press"
+                 image_pressed_selected="PushButton_Selected_Press"
+                 image_selected="PushButton_Selected_Press"
+                 left="0"
+                 name="Unread IM messages"
+                 pad_left="0"
+                 pad_right="0"
+                 width="34" >
+                    <button.init_callback
+                     function="Button.SetDockableFloaterToggle"
+                     parameter="im_well_window" />
+                </button>
+            </chiclet_im_well>
+        </layout_panel>
         <layout_panel
          auto_resize="false"
          follows="right"
@@ -353,7 +394,7 @@ as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly.
               </button>
 	    </chiclet_notification>
         </layout_panel>
-       <icon
+        <icon
          auto_resize="false"
          color="0 0 0 0"
          follows="left|right"
-- 
cgit v1.2.3