PageRenderTime 160ms CodeModel.GetById 41ms app.highlight 93ms RepoModel.GetById 17ms app.codeStats 1ms

/indra/newview/llsyswellwindow.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 870 lines | 621 code | 126 blank | 123 comment | 72 complexity | d167e1e922ba7d976e9e9faaa4aa2a07 MD5 | raw file
  1/** 
  2 * @file llsyswellwindow.cpp
  3 * @brief                                    // TODO
  4 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  5 * Second Life Viewer Source Code
  6 * Copyright (C) 2010, Linden Research, Inc.
  7 * 
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation;
 11 * version 2.1 of the License only.
 12 * 
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16 * Lesser General Public License for more details.
 17 * 
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 21 * 
 22 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 23 * $/LicenseInfo$
 24 */
 25
 26
 27#include "llviewerprecompiledheaders.h" // must be first include
 28
 29#include "llsyswellwindow.h"
 30
 31#include "llagent.h"
 32#include "llavatarnamecache.h"
 33
 34#include "llflatlistview.h"
 35#include "llfloaterreg.h"
 36#include "llnotifications.h"
 37
 38#include "llscriptfloater.h"
 39#include "llviewercontrol.h"
 40#include "llviewerwindow.h"
 41
 42#include "llchiclet.h"
 43#include "llchicletbar.h"
 44#include "lltoastpanel.h"
 45#include "llnotificationmanager.h"
 46#include "llnotificationsutil.h"
 47#include "llspeakers.h"
 48#include "lltoolbarview.h"
 49
 50//---------------------------------------------------------------------------------
 51LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLTransientDockableFloater(NULL, true,  key),
 52													mChannel(NULL),
 53													mMessageList(NULL),
 54													mSysWellChiclet(NULL),
 55													NOTIFICATION_WELL_ANCHOR_NAME("notification_well_panel"),
 56													IM_WELL_ANCHOR_NAME("im_well_panel"),
 57													mIsReshapedByUser(false)
 58
 59{
 60	setOverlapsScreenChannel(true);
 61}
 62
 63//---------------------------------------------------------------------------------
 64BOOL LLSysWellWindow::postBuild()
 65{
 66	mMessageList = getChild<LLFlatListView>("notification_list");
 67
 68	// get a corresponding channel
 69	initChannel();
 70
 71	// click on SysWell Window should clear "new message" state (and 'Lit' status). EXT-3147.
 72	// mouse up callback is not called in this case.
 73	setMouseDownCallback(boost::bind(&LLSysWellWindow::releaseNewMessagesState, this));
 74
 75	return LLTransientDockableFloater::postBuild();
 76}
 77
 78//---------------------------------------------------------------------------------
 79void LLSysWellWindow::setMinimized(BOOL minimize)
 80{
 81	LLTransientDockableFloater::setMinimized(minimize);
 82}
 83
 84//---------------------------------------------------------------------------------
 85void LLSysWellWindow::handleReshape(const LLRect& rect, bool by_user)
 86{
 87	mIsReshapedByUser |= by_user; // mark floater that it is reshaped by user
 88	LLTransientDockableFloater::handleReshape(rect, by_user);
 89}
 90
 91//---------------------------------------------------------------------------------
 92void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask)
 93{
 94	// just set floater visible. Screen channels will be cleared.
 95	setVisible(TRUE);
 96}
 97
 98void LLSysWellWindow::setSysWellChiclet(LLSysWellChiclet* chiclet) 
 99{ 
100	mSysWellChiclet = chiclet;
101	if(mSysWellChiclet)
102		mSysWellChiclet->updateWidget(isWindowEmpty()); 
103}
104//---------------------------------------------------------------------------------
105LLSysWellWindow::~LLSysWellWindow()
106{
107}
108
109//---------------------------------------------------------------------------------
110void LLSysWellWindow::removeItemByID(const LLUUID& id)
111{
112	if(mMessageList->removeItemByValue(id))
113	{
114		mSysWellChiclet->updateWidget(isWindowEmpty());
115		reshapeWindow();
116	}
117	else
118	{
119		llwarns << "Unable to remove notification from the list, ID: " << id
120			<< llendl;
121	}
122
123	// hide chiclet window if there are no items left
124	if(isWindowEmpty())
125	{
126		setVisible(FALSE);
127	}
128}
129
130//---------------------------------------------------------------------------------
131//---------------------------------------------------------------------------------
132void LLSysWellWindow::initChannel() 
133{
134	LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
135																LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
136	mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
137	if(NULL == mChannel)
138	{
139		llwarns << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << llendl;
140	}
141}
142
143//---------------------------------------------------------------------------------
144void LLSysWellWindow::setVisible(BOOL visible)
145{
146	if (visible)
147	{
148		if (NULL == getDockControl() && getDockTongue().notNull())
149		{
150			setDockControl(new LLDockControl(
151				LLChicletBar::getInstance()->getChild<LLView>(getAnchorViewName()), this,
152				getDockTongue(), LLDockControl::BOTTOM));
153		}
154	}
155
156	// do not show empty window
157	if (NULL == mMessageList || isWindowEmpty()) visible = FALSE;
158
159	LLTransientDockableFloater::setVisible(visible);
160
161	// update notification channel state	
162	initChannel(); // make sure the channel still exists
163	if(mChannel)
164	{
165		mChannel->updateShowToastsState();
166		mChannel->redrawToasts();
167	}
168
169	if (visible)
170	{
171		releaseNewMessagesState();
172	}
173}
174
175//---------------------------------------------------------------------------------
176void LLSysWellWindow::setDocked(bool docked, bool pop_on_undock)
177{
178	LLTransientDockableFloater::setDocked(docked, pop_on_undock);
179
180	// update notification channel state
181	if(mChannel)
182	{
183		mChannel->updateShowToastsState();
184		mChannel->redrawToasts();
185	}
186}
187
188//---------------------------------------------------------------------------------
189void LLSysWellWindow::reshapeWindow()
190{
191	// save difference between floater height and the list height to take it into account while calculating new window height
192	// it includes height from floater top to list top and from floater bottom and list bottom
193	static S32 parent_list_delta_height = getRect().getHeight() - mMessageList->getRect().getHeight();
194
195	if (!mIsReshapedByUser) // Don't reshape Well window, if it ever was reshaped by user. See EXT-5715.
196	{
197		S32 notif_list_height = mMessageList->getItemsRect().getHeight() + 2 * mMessageList->getBorderWidth();
198
199		LLRect curRect = getRect();
200
201		S32 new_window_height = notif_list_height + parent_list_delta_height;
202
203		if (new_window_height > MAX_WINDOW_HEIGHT)
204		{
205			new_window_height = MAX_WINDOW_HEIGHT;
206		}
207		S32 newWidth = curRect.getWidth() < MIN_WINDOW_WIDTH ? MIN_WINDOW_WIDTH	: curRect.getWidth();
208
209		curRect.setLeftTopAndSize(curRect.mLeft, curRect.mTop, newWidth, new_window_height);
210		reshape(curRect.getWidth(), curRect.getHeight(), TRUE);
211		setRect(curRect);
212	}
213
214	// update notification channel state
215	// update on a window reshape is important only when a window is visible and docked
216	if(mChannel && getVisible() && isDocked())
217	{
218		mChannel->updateShowToastsState();
219	}
220}
221
222void LLSysWellWindow::releaseNewMessagesState()
223{
224	if (NULL != mSysWellChiclet)
225	{
226		mSysWellChiclet->setNewMessagesState(false);
227	}
228}
229
230//---------------------------------------------------------------------------------
231bool LLSysWellWindow::isWindowEmpty()
232{
233	return mMessageList->size() == 0;
234}
235
236/************************************************************************/
237/*         RowPanel implementation                                      */
238/************************************************************************/
239
240//---------------------------------------------------------------------------------
241LLIMWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId,
242		S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId) :
243		LLPanel(LLPanel::Params()), mChiclet(NULL), mParent(parent)
244{
245	buildFromFile( "panel_activeim_row.xml", NULL);
246
247	// Choose which of the pre-created chiclets (IM/group) to use.
248	// The other one gets hidden.
249
250	LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(sessionId);
251	switch (im_chiclet_type)
252	{
253	case LLIMChiclet::TYPE_GROUP:
254		mChiclet = getChild<LLIMGroupChiclet>("group_chiclet");
255		break;
256	case LLIMChiclet::TYPE_AD_HOC:
257		mChiclet = getChild<LLAdHocChiclet>("adhoc_chiclet");		
258		break;
259	case LLIMChiclet::TYPE_UNKNOWN: // assign mChiclet a non-null value anyway
260	case LLIMChiclet::TYPE_IM:
261		mChiclet = getChild<LLIMP2PChiclet>("p2p_chiclet");
262		break;
263	}
264
265	// Initialize chiclet.
266	mChiclet->setChicletSizeChangedCallback(boost::bind(&LLIMWellWindow::RowPanel::onChicletSizeChanged, this, mChiclet, _2));
267	mChiclet->enableCounterControl(true);
268	mChiclet->setCounter(chicletCounter);
269	mChiclet->setSessionId(sessionId);
270	mChiclet->setIMSessionName(name);
271	mChiclet->setOtherParticipantId(otherParticipantId);
272	mChiclet->setVisible(true);
273
274	if (im_chiclet_type == LLIMChiclet::TYPE_IM)
275	{
276		LLAvatarNameCache::get(otherParticipantId,
277			boost::bind(&LLIMWellWindow::RowPanel::onAvatarNameCache,
278				this, _1, _2));
279	}
280	else
281	{
282		LLTextBox* contactName = getChild<LLTextBox>("contact_name");
283		contactName->setValue(name);
284	}
285
286	mCloseBtn = getChild<LLButton>("hide_btn");
287	mCloseBtn->setCommitCallback(boost::bind(&LLIMWellWindow::RowPanel::onClosePanel, this));
288}
289
290//---------------------------------------------------------------------------------
291void LLIMWellWindow::RowPanel::onAvatarNameCache(const LLUUID& agent_id,
292												 const LLAvatarName& av_name)
293{
294	LLTextBox* contactName = getChild<LLTextBox>("contact_name");
295	contactName->setValue( av_name.getCompleteName() );
296}
297
298//---------------------------------------------------------------------------------
299void LLIMWellWindow::RowPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param)
300{
301	LLTextBox* text = getChild<LLTextBox>("contact_name");
302	S32 new_text_left = mChiclet->getRect().mRight + CHICLET_HPAD;
303	LLRect text_rect = text->getRect(); 
304	text_rect.mLeft = new_text_left;
305	text->setShape(text_rect);
306}
307
308//---------------------------------------------------------------------------------
309LLIMWellWindow::RowPanel::~RowPanel()
310{
311}
312
313//---------------------------------------------------------------------------------
314void LLIMWellWindow::RowPanel::onClosePanel()
315{
316	gIMMgr->leaveSession(mChiclet->getSessionId());
317	// This row panel will be removed from the list in LLSysWellWindow::sessionRemoved().
318}
319
320//---------------------------------------------------------------------------------
321void LLIMWellWindow::RowPanel::onMouseEnter(S32 x, S32 y, MASK mask)
322{
323	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemSelected"));
324}
325
326//---------------------------------------------------------------------------------
327void LLIMWellWindow::RowPanel::onMouseLeave(S32 x, S32 y, MASK mask)
328{
329	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemUnselected"));
330}
331
332//---------------------------------------------------------------------------------
333// virtual
334BOOL LLIMWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask)
335{
336	// Pass the mouse down event to the chiclet (EXT-596).
337	if (!mChiclet->pointInView(x, y) && !mCloseBtn->getRect().pointInRect(x, y)) // prevent double call of LLIMChiclet::onMouseDown()
338	{
339		mChiclet->onMouseDown();
340		return TRUE;
341	}
342
343	return LLPanel::handleMouseDown(x, y, mask);
344}
345
346// virtual
347BOOL LLIMWellWindow::RowPanel::handleRightMouseDown(S32 x, S32 y, MASK mask)
348{
349	return mChiclet->handleRightMouseDown(x, y, mask);
350}
351/************************************************************************/
352/*         ObjectRowPanel implementation                                */
353/************************************************************************/
354
355LLIMWellWindow::ObjectRowPanel::ObjectRowPanel(const LLUUID& notification_id, bool new_message/* = false*/)
356 : LLPanel()
357 , mChiclet(NULL)
358{
359	buildFromFile( "panel_active_object_row.xml", NULL);
360
361	initChiclet(notification_id);
362
363	LLTextBox* obj_name = getChild<LLTextBox>("object_name");
364	obj_name->setValue(LLScriptFloaterManager::getObjectName(notification_id));
365
366	mCloseBtn = getChild<LLButton>("hide_btn");
367	mCloseBtn->setCommitCallback(boost::bind(&LLIMWellWindow::ObjectRowPanel::onClosePanel, this));
368}
369
370//---------------------------------------------------------------------------------
371LLIMWellWindow::ObjectRowPanel::~ObjectRowPanel()
372{
373}
374
375//---------------------------------------------------------------------------------
376void LLIMWellWindow::ObjectRowPanel::onClosePanel()
377{
378	LLScriptFloaterManager::getInstance()->removeNotification(mChiclet->getSessionId());
379}
380
381void LLIMWellWindow::ObjectRowPanel::initChiclet(const LLUUID& notification_id, bool new_message/* = false*/)
382{
383	// Choose which of the pre-created chiclets to use.
384	switch(LLScriptFloaterManager::getObjectType(notification_id))
385	{
386	case LLScriptFloaterManager::OBJ_GIVE_INVENTORY:
387		mChiclet = getChild<LLInvOfferChiclet>("inv_offer_chiclet");
388		break;
389	default:
390		mChiclet = getChild<LLScriptChiclet>("object_chiclet");
391		break;
392	}
393
394	mChiclet->setVisible(true);
395	mChiclet->setSessionId(notification_id);
396}
397
398//---------------------------------------------------------------------------------
399void LLIMWellWindow::ObjectRowPanel::onMouseEnter(S32 x, S32 y, MASK mask)
400{
401	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemSelected"));
402}
403
404//---------------------------------------------------------------------------------
405void LLIMWellWindow::ObjectRowPanel::onMouseLeave(S32 x, S32 y, MASK mask)
406{
407	setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemUnselected"));
408}
409
410//---------------------------------------------------------------------------------
411// virtual
412BOOL LLIMWellWindow::ObjectRowPanel::handleMouseDown(S32 x, S32 y, MASK mask)
413{
414	// Pass the mouse down event to the chiclet (EXT-596).
415	if (!mChiclet->pointInView(x, y) && !mCloseBtn->getRect().pointInRect(x, y)) // prevent double call of LLIMChiclet::onMouseDown()
416	{
417		mChiclet->onMouseDown();
418		return TRUE;
419	}
420
421	return LLPanel::handleMouseDown(x, y, mask);
422}
423
424// virtual
425BOOL LLIMWellWindow::ObjectRowPanel::handleRightMouseDown(S32 x, S32 y, MASK mask)
426{
427	return mChiclet->handleRightMouseDown(x, y, mask);
428}
429
430/************************************************************************/
431/*         LLNotificationWellWindow implementation                      */
432/************************************************************************/
433
434//////////////////////////////////////////////////////////////////////////
435// PUBLIC METHODS
436LLNotificationWellWindow::LLNotificationWellWindow(const LLSD& key)
437: LLSysWellWindow(key)
438{
439	// init connections to the list's update events
440	connectListUpdaterToSignal("notify");
441	connectListUpdaterToSignal("groupnotify");
442	connectListUpdaterToSignal("offer");
443}
444
445// static
446LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
447{
448	return LLFloaterReg::getTypedInstance<LLNotificationWellWindow>("notification_well_window", key);
449}
450
451// virtual
452BOOL LLNotificationWellWindow::postBuild()
453{
454	BOOL rv = LLSysWellWindow::postBuild();
455	setTitle(getString("title_notification_well_window"));
456	return rv;
457}
458
459// virtual
460void LLNotificationWellWindow::setVisible(BOOL visible)
461{
462	if (visible)
463	{
464		// when Notification channel is cleared, storable toasts will be added into the list.
465		clearScreenChannels();
466	}
467
468	LLSysWellWindow::setVisible(visible);
469}
470
471//---------------------------------------------------------------------------------
472void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
473{
474	LLSD value = p.notification_id;
475	// do not add clones
476	if( mMessageList->getItemByValue(value))
477		return;
478
479	LLSysWellItem* new_item = new LLSysWellItem(p);
480	if (mMessageList->addItem(new_item, value, ADD_TOP))
481	{
482		mSysWellChiclet->updateWidget(isWindowEmpty());
483		reshapeWindow();
484
485		new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
486		new_item->setOnItemClickCallback(boost::bind(&LLNotificationWellWindow::onItemClick, this, _1));
487	}
488	else
489	{
490		llwarns << "Unable to add Notification into the list, notification ID: " << p.notification_id
491			<< ", title: " << p.title
492			<< llendl;
493
494		new_item->die();
495	}
496}
497
498void LLNotificationWellWindow::closeAll()
499{
500	// Need to clear notification channel, to add storable toasts into the list.
501	clearScreenChannels();
502	std::vector<LLPanel*> items;
503	mMessageList->getItems(items);
504	for (std::vector<LLPanel*>::iterator
505			 iter = items.begin(),
506			 iter_end = items.end();
507		 iter != iter_end; ++iter)
508	{
509		LLSysWellItem* sys_well_item = dynamic_cast<LLSysWellItem*>(*iter);
510		if (sys_well_item)
511			onItemClose(sys_well_item);
512	}
513}
514
515//////////////////////////////////////////////////////////////////////////
516// PRIVATE METHODS
517void LLNotificationWellWindow::initChannel() 
518{
519	LLSysWellWindow::initChannel();
520	if(mChannel)
521	{
522		mChannel->setOnStoreToastCallback(boost::bind(&LLNotificationWellWindow::onStoreToast, this, _1, _2));
523	}
524}
525
526void LLNotificationWellWindow::clearScreenChannels()
527{
528	// 1 - remove StartUp toast and channel if present
529	if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown())
530	{
531		LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose();
532	}
533
534	// 2 - remove toasts in Notification channel
535	if(mChannel)
536	{
537		mChannel->removeAndStoreAllStorableToasts();
538	}
539}
540
541void LLNotificationWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id)
542{
543	LLSysWellItem::Params p;	
544	p.notification_id = id;
545	p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
546	addItem(p);
547}
548
549void LLNotificationWellWindow::connectListUpdaterToSignal(std::string notification_type)
550{
551	LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
552	LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
553	if(n_handler)
554	{
555		n_handler->setNotificationIDCallback(boost::bind(&LLNotificationWellWindow::removeItemByID, this, _1));
556	}
557	else
558	{
559		llwarns << "LLSysWellWindow::connectListUpdaterToSignal() - could not get a handler for '" << notification_type <<"' type of notifications" << llendl;
560	}
561}
562
563void LLNotificationWellWindow::onItemClick(LLSysWellItem* item)
564{
565	LLUUID id = item->getID();
566	LLFloaterReg::showInstance("inspect_toast", id);
567}
568
569void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)
570{
571	LLUUID id = item->getID();
572	removeItemByID(id);
573	if(mChannel)
574		mChannel->killToastByNotificationID(id);
575}
576
577
578
579/************************************************************************/
580/*         LLIMWellWindow  implementation                               */
581/************************************************************************/
582
583//////////////////////////////////////////////////////////////////////////
584// PUBLIC METHODS
585LLIMWellWindow::LLIMWellWindow(const LLSD& key)
586: LLSysWellWindow(key)
587{
588	LLIMMgr::getInstance()->addSessionObserver(this);
589}
590
591LLIMWellWindow::~LLIMWellWindow()
592{
593	LLIMMgr::getInstance()->removeSessionObserver(this);
594}
595
596// static
597LLIMWellWindow* LLIMWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
598{
599	return LLFloaterReg::getTypedInstance<LLIMWellWindow>("im_well_window", key);
600}
601
602
603// static
604LLIMWellWindow* LLIMWellWindow::findInstance(const LLSD& key /*= LLSD()*/)
605{
606	return LLFloaterReg::findTypedInstance<LLIMWellWindow>("im_well_window", key);
607}
608
609BOOL LLIMWellWindow::postBuild()
610{
611	BOOL rv = LLSysWellWindow::postBuild();
612	setTitle(getString("title_im_well_window"));
613
614	LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findIMChiclet, this, _1));
615	LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findObjectChiclet, this, _1));
616
617	return rv;
618}
619
620//virtual
621void LLIMWellWindow::sessionAdded(const LLUUID& session_id,
622								   const std::string& name, const LLUUID& other_participant_id)
623{
624	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
625	if (!session) return;
626
627	// no need to spawn chiclets for participants in P2P calls called through Avaline
628	if (session->isP2P() && session->isOtherParticipantAvaline()) return;
629
630	if (mMessageList->getItemByValue(session_id)) return;
631
632	addIMRow(session_id, 0, name, other_participant_id);	
633	reshapeWindow();
634}
635
636//virtual
637void LLIMWellWindow::sessionRemoved(const LLUUID& sessionId)
638{
639	delIMRow(sessionId);
640	reshapeWindow();
641}
642
643//virtual
644void LLIMWellWindow::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
645{
646	//for outgoing ad-hoc and group im sessions only
647	LLChiclet* chiclet = findIMChiclet(old_session_id);
648	if (chiclet)
649	{
650		chiclet->setSessionId(new_session_id);
651		mMessageList->updateValue(old_session_id, new_session_id);
652	}
653}
654
655LLChiclet* LLIMWellWindow::findObjectChiclet(const LLUUID& notification_id)
656{
657	if (!mMessageList) return NULL;
658
659	LLChiclet* res = NULL;
660	ObjectRowPanel* panel = mMessageList->getTypedItemByValue<ObjectRowPanel>(notification_id);
661	if (panel != NULL)
662	{
663		res = panel->mChiclet;
664	}
665
666	return res;
667}
668
669//////////////////////////////////////////////////////////////////////////
670// PRIVATE METHODS
671LLChiclet* LLIMWellWindow::findIMChiclet(const LLUUID& sessionId)
672{
673	if (!mMessageList) return NULL;
674
675	LLChiclet* res = NULL;
676	RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(sessionId);
677	if (panel != NULL)
678	{
679		res = panel->mChiclet;
680	}
681
682	return res;
683}
684
685//---------------------------------------------------------------------------------
686void LLIMWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter,
687							   const std::string& name, const LLUUID& otherParticipantId)
688{
689	RowPanel* item = new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId);
690	if (mMessageList->addItem(item, sessionId))
691	{
692		mSysWellChiclet->updateWidget(isWindowEmpty());
693	}
694	else
695	{
696		llwarns << "Unable to add IM Row into the list, sessionID: " << sessionId
697			<< ", name: " << name
698			<< ", other participant ID: " << otherParticipantId
699			<< llendl;
700
701		item->die();
702	}
703}
704
705//---------------------------------------------------------------------------------
706void LLIMWellWindow::delIMRow(const LLUUID& sessionId)
707{
708	//fix for EXT-3252
709	//without this line LLIMWellWindow receive onFocusLost
710	//and hide itself. It was becaue somehow LLIMChicklet was in focus group for
711	//LLIMWellWindow...
712	//But I didn't find why this happen..
713	gFocusMgr.clearLastFocusForGroup(this);
714
715	if (mMessageList->removeItemByValue(sessionId))
716	{
717		mSysWellChiclet->updateWidget(isWindowEmpty());
718	}
719	else
720	{
721		llwarns << "Unable to remove IM Row from the list, sessionID: " << sessionId
722			<< llendl;
723	}
724
725	// remove all toasts that belong to this session from a screen
726	if(mChannel)
727		mChannel->removeToastsBySessionID(sessionId);
728
729	// hide chiclet window if there are no items left
730	if(isWindowEmpty())
731	{
732		setVisible(FALSE);
733	}
734	else
735	{
736		setFocus(true);
737	}
738}
739
740void LLIMWellWindow::addObjectRow(const LLUUID& notification_id, bool new_message/* = false*/)
741{
742	if (mMessageList->getItemByValue(notification_id) == NULL)
743	{
744		ObjectRowPanel* item = new ObjectRowPanel(notification_id, new_message);
745		if (mMessageList->addItem(item, notification_id))
746		{
747			mSysWellChiclet->updateWidget(isWindowEmpty());
748		}
749		else
750		{
751			llwarns << "Unable to add Object Row into the list, notificationID: " << notification_id << llendl;
752			item->die();
753		}
754		reshapeWindow();
755	}
756}
757
758void LLIMWellWindow::removeObjectRow(const LLUUID& notification_id)
759{
760	if (mMessageList->removeItemByValue(notification_id))
761	{
762		if (mSysWellChiclet)
763		{
764			mSysWellChiclet->updateWidget(isWindowEmpty());
765		}
766	}
767	else
768	{
769		llwarns << "Unable to remove Object Row from the list, notificationID: " << notification_id << llendl;
770	}
771
772	reshapeWindow();
773	// hide chiclet window if there are no items left
774	if(isWindowEmpty())
775	{
776		setVisible(FALSE);
777	}
778}
779
780
781void LLIMWellWindow::addIMRow(const LLUUID& session_id)
782{
783	if (hasIMRow(session_id)) return;
784
785	LLIMModel* im_model = LLIMModel::getInstance();
786	addIMRow(session_id, 0, im_model->getName(session_id), im_model->getOtherParticipantID(session_id));
787	reshapeWindow();
788}
789
790bool LLIMWellWindow::hasIMRow(const LLUUID& session_id)
791{
792	return mMessageList->getItemByValue(session_id);
793}
794
795void LLIMWellWindow::closeAll()
796{
797	// Generate an ignorable alert dialog if there is an active voice IM sesion
798	bool need_confirmation = false;
799	const LLIMModel& im_model = LLIMModel::instance();
800	std::vector<LLSD> values;
801	mMessageList->getValues(values);
802	for (std::vector<LLSD>::iterator
803			 iter = values.begin(),
804			 iter_end = values.end();
805		 iter != iter_end; ++iter)
806	{
807		LLIMSpeakerMgr* speaker_mgr =  im_model.getSpeakerManager(*iter);
808		if (speaker_mgr && speaker_mgr->isVoiceActive())
809		{
810			need_confirmation = true;
811			break;
812		}
813	}
814	if ( need_confirmation )
815	{
816		//Bring up a confirmation dialog
817		LLNotificationsUtil::add
818			("ConfirmCloseAll", LLSD(), LLSD(),
819			 boost::bind(&LLIMWellWindow::confirmCloseAll, this, _1, _2));
820	}
821	else
822	{
823		closeAllImpl();
824	}
825}
826
827void LLIMWellWindow::closeAllImpl()
828{
829	std::vector<LLSD> values;
830	mMessageList->getValues(values);
831
832	for (std::vector<LLSD>::iterator
833			 iter = values.begin(),
834			 iter_end = values.end();
835		 iter != iter_end; ++iter)
836	{
837		LLPanel* panel = mMessageList->getItemByValue(*iter);
838
839		RowPanel* im_panel = dynamic_cast <RowPanel*> (panel);
840		if (im_panel)
841		{
842			gIMMgr->leaveSession(*iter);
843			continue;
844		}
845
846		ObjectRowPanel* obj_panel = dynamic_cast <ObjectRowPanel*> (panel);
847		if (obj_panel)
848		{
849			LLScriptFloaterManager::instance().removeNotification(*iter);
850		}
851	}
852}
853
854bool LLIMWellWindow::confirmCloseAll(const LLSD& notification, const LLSD& response)
855{
856	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
857	switch(option)
858	{
859	case 0:
860		{
861			closeAllImpl();
862			return  true;
863		}
864	default:
865		break;
866	}
867	return false;
868}
869
870// EOF