diff options
Diffstat (limited to 'indra/newview/llsyswellwindow.cpp')
-rw-r--r-- | indra/newview/llsyswellwindow.cpp | 430 |
1 files changed, 289 insertions, 141 deletions
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 98428bf0f7..669d8d1d70 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -32,6 +32,8 @@ #include "llviewerprecompiledheaders.h" // must be first include +#include "llflatlistview.h" + #include "llsyswellwindow.h" #include "llbottomtray.h" @@ -39,89 +41,169 @@ #include "llviewerwindow.h" #include "llchiclet.h" +#include "lltoastpanel.h" +#include "llnotificationmanager.h" + + +// IM session ID can be the same as Avatar UUID. (See LLIMMgr::computeSessionID) +// Probably notification ID also can be the same as Avatar UUID. +// In case when session ID & notification ID are the same it will be impossible to add both +// appropriate Items into Flat List. +// Functions below are intended to wrap passed LLUUID into LLSD value with different "type". +// Use them anywhere you need to add, get, remove items via the list +inline +LLSD get_notification_value(const LLUUID& notification_id) +{ + return LLSD() + .insert("type", "notification") + .insert("uuid", notification_id); +} + +inline +LLSD get_session_value(const LLUUID& session_id) +{ + return LLSD() + .insert("type", "im_chiclet") + .insert("uuid", session_id); +} + + //--------------------------------------------------------------------------------- LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key), mChannel(NULL), - mScrollContainer(NULL), - mNotificationList(NULL) + 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; } //--------------------------------------------------------------------------------- BOOL LLSysWellWindow::postBuild() { - mScrollContainer = getChild<LLScrollContainer>("notification_list_container"); - mTwinListPanel = getChild<LLPanel>("twin_list_panel"); - mNotificationList = getChild<LLScrollingPanelList>("notification_list"); - mIMRowList = getChild<LLScrollingPanelList>("im_row_panel_list"); + mMessageList = getChild<LLFlatListView>("notification_list"); + + // init connections to the list's update events + connectListUpdaterToSignal("notify"); + connectListUpdaterToSignal("groupnotify"); + + // get a corresponding channel + initChannel(); - mScrollContainer->setBorderVisible(FALSE); + LLPanel::Params params; + mSeparator = LLUICtrlFactory::create<LLPanel>(params); + LLUICtrlFactory::instance().buildPanel(mSeparator, "panel_separator.xml"); + + LLRect rc = mSeparator->getRect(); + rc.setOriginAndSize(0, 0, mMessageList->getItemsRect().getWidth(), rc.getHeight()); + mSeparator->setRect(rc); + mSeparator->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + mSeparator->setVisible(FALSE); + + mMessageList->addItem(mSeparator); return LLDockableFloater::postBuild(); } //--------------------------------------------------------------------------------- -LLSysWellWindow::~LLSysWellWindow() +void LLSysWellWindow::setMinimized(BOOL minimize) { - LLIMMgr::getInstance()->removeSessionObserver(this); + // we don't show empty Message Well window + setVisible(!minimize && !isWindowEmpty()); + + LLFloater::setMinimized(minimize); } //--------------------------------------------------------------------------------- -void LLSysWellWindow::addItem(LLSysWellItem::Params p) +void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type) { - // do not add clones - if( findItemByID(p.notification_id) >= 0 ) - return; + 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; + } +} - LLSysWellItem* new_item = new LLSysWellItem(p); - mNotificationList->addPanel(dynamic_cast<LLScrollingPanel*>(new_item)); - reshapeWindow(); +//--------------------------------------------------------------------------------- +void LLSysWellWindow::onChicletClick() +{ + // 1 - remove StartUp toast and channel if present + if(!LLNotificationsUI::LLScreenChannel::getStartUpToastShown()) + { + LLNotificationsUI::LLChannelManager::getInstance()->onStartUpToastClose(); + } - new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); - new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); + // 2 - toggle instance of SysWell's chiclet-window + toggleWindow(); } //--------------------------------------------------------------------------------- -void LLSysWellWindow::clear() +LLSysWellWindow::~LLSysWellWindow() { - // *TODO: fill later + LLIMMgr::getInstance()->removeSessionObserver(this); } //--------------------------------------------------------------------------------- -S32 LLSysWellWindow::findItemByID(const LLUUID& id) +void LLSysWellWindow::addItem(LLSysWellItem::Params p) { - const LLScrollingPanelList::panel_list_t list = mNotificationList->getPanelList(); - if(list.size() == 0) - return -1; + LLSD value = get_notification_value(p.notification_id); + // do not add clones + if( mMessageList->getItemByValue(value)) + return; - LLScrollingPanelList::panel_list_t::const_iterator it; - S32 index = 0; - for(it = list.begin(); it != list.end(); ++it, ++index) + LLSysWellItem* new_item = new LLSysWellItem(p); + if (mMessageList->addItem(new_item, value, ADD_TOP)) { - if( dynamic_cast<LLSysWellItem*>(*it)->getID() == id ) - break; - } + handleItemAdded(IT_NOTIFICATION); + + reshapeWindow(); - if(it == list.end()) - return -1; + new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); + new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); + } else - return index; + { + llwarns << "Unable to add Notification into the list, notification ID: " << p.notification_id + << ", title: " << p.title + << llendl; + new_item->die(); + } } //--------------------------------------------------------------------------------- -void LLSysWellWindow::removeItemByID(const LLUUID& id) +void LLSysWellWindow::clear() { - S32 index = findItemByID(id); + mMessageList->clear(); +} - if(index >= 0) - mNotificationList->removePanel(index); +//--------------------------------------------------------------------------------- +void LLSysWellWindow::removeItemByID(const LLUUID& id) +{ + if(mMessageList->removeItemByValue(get_notification_value(id))) + { + handleItemRemoved(IT_NOTIFICATION); + reshapeWindow(); + } else - return; + { + llwarns << "Unable to remove notification from the list, ID: " << id + << llendl; + } - reshapeWindow(); + // hide chiclet window if there are no items left + if(isWindowEmpty()) + { + setVisible(FALSE); + } } //--------------------------------------------------------------------------------- @@ -129,7 +211,7 @@ void LLSysWellWindow::onItemClick(LLSysWellItem* item) { LLUUID id = item->getID(); if(mChannel) - mChannel->loadStoredToastByIDToChannel(id); + mChannel->loadStoredToastByNotificationIDToChannel(id); } //--------------------------------------------------------------------------------- @@ -139,9 +221,37 @@ void LLSysWellWindow::onItemClose(LLSysWellItem* item) removeItemByID(id); if(mChannel) mChannel->killToastByNotificationID(id); +} - // hide chiclet window if there are no items left - setVisible(!isWindowEmpty()); +//-------------------------------------------------------------------------- +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 + { + llwarns << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << llendl; + } +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRect(); } //--------------------------------------------------------------------------------- @@ -151,9 +261,26 @@ void LLSysWellWindow::toggleWindow() { setDockControl(new LLDockControl( LLBottomTray::getInstance()->getSysWell(), this, - getDockTongue(), LLDockControl::TOP, isDocked())); + getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getAllowedRect, this, _1))); + } + + if(!getVisible()) + { + if(mChannel) + { + mChannel->removeAndStoreAllStorableToasts(); + } + if(isWindowEmpty()) + { + return; + } + + setVisible(TRUE); + } + else + { + setVisible(FALSE); } - setVisible(!getVisible()); //set window in foreground setFocus(getVisible()); } @@ -161,15 +288,12 @@ void LLSysWellWindow::toggleWindow() //--------------------------------------------------------------------------------- void LLSysWellWindow::setVisible(BOOL visible) { - // on Show adjust position of SysWell chiclet's window if(visible) { if (LLBottomTray::instanceExists()) { LLBottomTray::getInstance()->getSysWell()->setToggleState(TRUE); } - if(mChannel) - mChannel->removeAndStoreAllVisibleToasts(); } else { @@ -178,86 +302,56 @@ void LLSysWellWindow::setVisible(BOOL visible) LLBottomTray::getInstance()->getSysWell()->setToggleState(FALSE); } } - if(mChannel) - mChannel->setShowToasts(!visible); LLDockableFloater::setVisible(visible); + + // update notification channel state + if(mChannel) + { + mChannel->updateShowToastsState(); + } } //--------------------------------------------------------------------------------- -void LLSysWellWindow::reshapeWindow() +void LLSysWellWindow::setDocked(bool docked, bool pop_on_undock) { - // Get size for scrollbar and floater's header - const LLUICachedControl<S32> SCROLLBAR_SIZE("UIScrollbarSize", 0); - const LLUICachedControl<S32> HEADER_SIZE("UIFloaterHeaderSize", 0); + LLDockableFloater::setDocked(docked, pop_on_undock); - LLRect notif_list_rect = mNotificationList->getRect(); - LLRect im_list_rect = mIMRowList->getRect(); - LLRect panel_rect = mTwinListPanel->getRect(); - - S32 notif_list_height = notif_list_rect.getHeight(); - S32 im_list_height = im_list_rect.getHeight(); - - S32 new_panel_height = notif_list_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + im_list_height; - S32 new_window_height = new_panel_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + HEADER_SIZE; - - U32 twinListWidth = 0; - - if (new_window_height > MAX_WINDOW_HEIGHT) - { - twinListWidth = MIN_PANELLIST_WIDTH - SCROLLBAR_SIZE; - new_window_height = MAX_WINDOW_HEIGHT; - } - else + // update notification channel state + if(mChannel) { - twinListWidth = MIN_PANELLIST_WIDTH; + mChannel->updateShowToastsState(); } - - reshape(MIN_WINDOW_WIDTH, new_window_height, FALSE); - mTwinListPanel->reshape(twinListWidth, new_panel_height, TRUE); - mNotificationList->reshape(twinListWidth, notif_list_height, TRUE); - mIMRowList->reshape(twinListWidth, im_list_height, TRUE); - - // arrange panel and lists - // move panel - panel_rect.setLeftTopAndSize(1, new_panel_height, twinListWidth, new_panel_height); - mTwinListPanel->setRect(panel_rect); - // move notif list panel - notif_list_rect.setLeftTopAndSize(notif_list_rect.mLeft, new_panel_height, twinListWidth, notif_list_height); - mNotificationList->setRect(notif_list_rect); - // move IM list panel - im_list_rect.setLeftTopAndSize(im_list_rect.mLeft, notif_list_rect.mBottom - LLScrollingPanelList::GAP_BETWEEN_PANELS, twinListWidth, im_list_height); - mIMRowList->setRect(im_list_rect); - - mNotificationList->updatePanels(TRUE); - mIMRowList->updatePanels(TRUE); } //--------------------------------------------------------------------------------- -LLSysWellWindow::RowPanel * LLSysWellWindow::findIMRow(const LLUUID& sessionId) +void LLSysWellWindow::reshapeWindow() { - RowPanel * res = NULL; - const LLScrollingPanelList::panel_list_t &list = mIMRowList->getPanelList(); - if (!list.empty()) + // save difference between floater height and the list height to take it into account while calculating new window height + // it includes height from floater top to list top and from floater bottom and list bottom + static S32 parent_list_delta_height = getRect().getHeight() - mMessageList->getRect().getHeight(); + + S32 notif_list_height = mMessageList->getItemsRect().getHeight() + 2 * mMessageList->getBorderWidth(); + + LLRect curRect = getRect(); + + S32 new_window_height = notif_list_height + parent_list_delta_height; + + if (new_window_height > MAX_WINDOW_HEIGHT) { - for (LLScrollingPanelList::panel_list_t::const_iterator iter = list.begin(); iter != list.end(); ++iter) - { - RowPanel *panel = static_cast<RowPanel*> (*iter); - if (panel->mChiclet->getSessionId() == sessionId) - { - res = panel; - break; - } - } + new_window_height = MAX_WINDOW_HEIGHT; } - return res; + S32 newY = curRect.mTop + new_window_height - curRect.getHeight(); + curRect.setLeftTopAndSize(curRect.mLeft, newY, MIN_WINDOW_WIDTH, new_window_height); + reshape(curRect.getWidth(), curRect.getHeight(), TRUE); + setRect(curRect); } //--------------------------------------------------------------------------------- LLChiclet* LLSysWellWindow::findIMChiclet(const LLUUID& sessionId) { LLChiclet* res = NULL; - RowPanel* panel = findIMRow(sessionId); + RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(get_session_value(sessionId)); if (panel != NULL) { res = panel->mChiclet; @@ -270,52 +364,67 @@ LLChiclet* LLSysWellWindow::findIMChiclet(const LLUUID& sessionId) 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, get_session_value(sessionId))) + { + handleItemAdded(IT_INSTANT_MESSAGE); + } + else + { + llwarns << "Unable to add IM Row into the list, sessionID: " << sessionId + << ", name: " << name + << ", other participant ID: " << otherParticipantId + << llendl; - mIMRowList->addPanel(new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId)); + item->die(); + } } //--------------------------------------------------------------------------------- void LLSysWellWindow::delIMRow(const LLUUID& sessionId) { - RowPanel *panel = findIMRow(sessionId); - if (panel != NULL) + if (mMessageList->removeItemByValue(get_session_value(sessionId))) + { + handleItemRemoved(IT_INSTANT_MESSAGE); + } + else { - mIMRowList->removePanel(panel); + 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 - setVisible(!isWindowEmpty()); + if(isWindowEmpty()) + { + setVisible(FALSE); + } } //--------------------------------------------------------------------------------- bool LLSysWellWindow::isWindowEmpty() { - if(mIMRowList->getPanelList().size() == 0 && LLBottomTray::getInstance()->getSysWell()->getCounter() == 0) - { - return true; - } - else - { - return false; - } + // keep in mind, mSeparator is always in the list + return mMessageList->size() == 1; } //--------------------------------------------------------------------------------- //virtual -void LLSysWellWindow::sessionAdded(const LLUUID& sessionId, - const std::string& name, const LLUUID& otherParticipantId) +void LLSysWellWindow::sessionAdded(const LLUUID& session_id, + const std::string& name, const LLUUID& other_participant_id) { - if (findIMRow(sessionId) == NULL) + //*TODO get rid of get_session_value, session_id's are unique, cause performance degradation with lots chiclets (IB) + if (mMessageList->getItemByValue(get_session_value(session_id)) == NULL) { - S32 chicletCounter = 0; - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::sSessionsMap, - sessionId, (LLIMModel::LLIMSession*) NULL); - if (session != NULL) + S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id); + if (chicletCounter > -1) { - chicletCounter = session->mNumUnread; + addIMRow(session_id, chicletCounter, name, other_participant_id); + reshapeWindow(); } - addIMRow(sessionId, chicletCounter, name, otherParticipantId); - reshapeWindow(); } } @@ -328,10 +437,57 @@ void LLSysWellWindow::sessionRemoved(const LLUUID& sessionId) LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications(); } +void LLSysWellWindow::handleItemAdded(EItemType added_item_type) +{ + bool should_be_shown = ++mTypedItemsCount[added_item_type] == 1 && anotherTypeExists(added_item_type); + + if (should_be_shown && !mSeparator->getVisible()) + { + mSeparator->setVisible(TRUE); + + // refresh list to recalculate mSeparator position + mMessageList->reshape(mMessageList->getRect().getWidth(), mMessageList->getRect().getHeight()); + } +} + +void LLSysWellWindow::handleItemRemoved(EItemType removed_item_type) +{ + bool should_be_hidden = --mTypedItemsCount[removed_item_type] == 0; + + if (should_be_hidden && mSeparator->getVisible()) + { + mSeparator->setVisible(FALSE); + + // refresh list to recalculate mSeparator position + mMessageList->reshape(mMessageList->getRect().getWidth(), mMessageList->getRect().getHeight()); + } +} + +bool LLSysWellWindow::anotherTypeExists(EItemType item_type) +{ + bool exists = false; + switch(item_type) + { + case IT_INSTANT_MESSAGE: + if (mTypedItemsCount[IT_NOTIFICATION] > 0) + { + exists = true; + } + break; + case IT_NOTIFICATION: + if (mTypedItemsCount[IT_INSTANT_MESSAGE] > 0) + { + exists = true; + } + break; + } + return exists; +} + //--------------------------------------------------------------------------------- LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId, S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId) : - LLScrollingPanel(LLPanel::Params()), mChiclet(NULL), mParent(parent) + LLPanel(LLPanel::Params()), mChiclet(NULL), mParent(parent) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_activeim_row.xml", NULL); @@ -342,6 +498,7 @@ LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& switch (im_chiclet_type) { case LLIMChiclet::TYPE_GROUP: + case LLIMChiclet::TYPE_AD_HOC: mChiclet = getChild<LLIMChiclet>("group_chiclet"); childSetVisible("p2p_chiclet", false); break; @@ -373,8 +530,8 @@ LLSysWellWindow::RowPanel::~RowPanel() //--------------------------------------------------------------------------------- void LLSysWellWindow::RowPanel::onClose() { - mParent->mIMRowList->removePanel(this); gIMMgr->removeSession(mChiclet->getSessionId()); + // This row panel will be removed from the list in LLSysWellWindow::sessionRemoved(). } //--------------------------------------------------------------------------------- @@ -400,13 +557,4 @@ BOOL LLSysWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask) return LLPanel::handleMouseDown(x, y, mask); } -//--------------------------------------------------------------------------------- -void LLSysWellWindow::RowPanel::updatePanel(BOOL allow_modify) -{ - S32 parent_width = getParent()->getRect().getWidth(); - S32 panel_height = getRect().getHeight(); - - reshape(parent_width, panel_height, TRUE); -} - -//--------------------------------------------------------------------------------- +// EOF |