summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/newview/CMakeLists.txt6
-rwxr-xr-xindra/newview/llavatariconctrl.cpp1
-rwxr-xr-xindra/newview/llchannelmanager.cpp3
-rwxr-xr-xindra/newview/llchiclet.cpp8
-rwxr-xr-xindra/newview/llchicletbar.cpp3
-rw-r--r--indra/newview/llfloaternotificationstabbed.cpp571
-rw-r--r--indra/newview/llfloaternotificationstabbed.h174
-rw-r--r--indra/newview/llnotificationlistitem.cpp607
-rw-r--r--indra/newview/llnotificationlistitem.h248
-rw-r--r--indra/newview/llnotificationlistview.cpp44
-rw-r--r--indra/newview/llnotificationlistview.h49
-rwxr-xr-xindra/newview/llsyswellwindow.cpp152
-rwxr-xr-xindra/newview/llsyswellwindow.h51
-rwxr-xr-xindra/newview/lltoastgroupnotifypanel.cpp2
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp4
-rwxr-xr-xindra/newview/llviewermessage.cpp2
-rwxr-xr-xindra/newview/skins/default/colors.xml7
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Large.pngbin0 -> 4182 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Attachment_Small.pngbin0 -> 3774 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Condense.pngbin0 -> 262 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Notification_Expand.pngbin0 -> 239 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Large.pngbin0 -> 1804 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/System_Notification_Small.pngbin0 -> 661 bytes
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml5
-rw-r--r--indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml153
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_sys_well.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification_list_item.xml148
-rw-r--r--indra/newview/skins/default/xui/en/widgets/notification_list_view.xml18
28 files changed, 2044 insertions, 216 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 536c7740bb..07c2c2d90f 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -275,6 +275,7 @@ set(viewer_SOURCE_FILES
llfloatermodeluploadbase.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
+ llfloaternotificationstabbed.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
llfloateroutbox.cpp
@@ -409,6 +410,8 @@ set(viewer_SOURCE_FILES
llnotificationgrouphandler.cpp
llnotificationhandlerutil.cpp
llnotificationhinthandler.cpp
+ llnotificationlistitem.cpp
+ llnotificationlistview.cpp
llnotificationmanager.cpp
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
@@ -895,6 +898,7 @@ set(viewer_HEADER_FILES
llfloatermodeluploadbase.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
+ llfloaternotificationstabbed.h
llfloaterobjectweights.h
llfloateropenobject.h
llfloateroutbox.h
@@ -1022,6 +1026,8 @@ set(viewer_HEADER_FILES
llnavigationbar.h
llnetmap.h
llnotificationhandler.h
+ llnotificationlistitem.h
+ llnotificationlistview.h
llnotificationmanager.h
llnotificationstorage.h
lloutfitslist.h
diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp
index 281e591b48..25a5df9781 100755
--- a/indra/newview/llavatariconctrl.cpp
+++ b/indra/newview/llavatariconctrl.cpp
@@ -311,6 +311,7 @@ bool LLAvatarIconCtrl::updateFromCache()
else
{
LLIconCtrl::setValue(mDefaultIconName);
+ return false;
}
return true;
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index b0537a83f1..d6240838b6 100755
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -35,6 +35,7 @@
#include "llviewerwindow.h"
#include "llrootview.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterreg.h"
#include <algorithm>
@@ -131,7 +132,7 @@ void LLChannelManager::onLoginCompleted()
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
- mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4));
+ mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime"));
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 46b7679915..dedb06c945 100755
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -35,6 +35,7 @@
#include "llscriptfloater.h"
#include "llsingleton.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
@@ -165,7 +166,7 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)
mNotificationChannel.reset(new ChicletNotificationChannel(this));
// ensure that notification well window exists, to synchronously
// handle toast add/delete events.
- LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
+ LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);
}
void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
@@ -173,7 +174,7 @@ void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
std::string action = user_data.asString();
if("close all" == action)
{
- LLNotificationWellWindow::getInstance()->closeAll();
+ LLFloaterNotificationsTabbed::getInstance()->closeAll();
LLIMWellWindow::getInstance()->closeAll();
}
}
@@ -224,7 +225,8 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo
bool displayNotification;
if ( (notification->getName() == "ScriptDialog") // special case for scripts
// if there is no toast window for the notification, filter it
- || (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ //|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
+ || (!LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
)
{
displayNotification = false;
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index d8b04f7004..254e3f61a8 100755
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -31,6 +31,7 @@
#include "lllayoutstack.h"
#include "llpaneltopinfobar.h"
#include "llsyswellwindow.h"
+#include "llfloaternotificationstabbed.h"
namespace
{
@@ -49,7 +50,7 @@ BOOL LLChicletBar::postBuild()
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
- showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+ showWellButton("notification_well", !LLFloaterNotificationsTabbed::getInstance()->isWindowEmpty());
LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
diff --git a/indra/newview/llfloaternotificationstabbed.cpp b/indra/newview/llfloaternotificationstabbed.cpp
new file mode 100644
index 0000000000..5823983b76
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.cpp
@@ -0,0 +1,571 @@
+/**
+ * @file llfloaternotificationstabbed.cpp
+ * @brief
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h" // must be first include
+#include "llfloaternotificationstabbed.h"
+
+#include "llchiclet.h"
+#include "llchicletbar.h"
+#include "llflatlistview.h"
+#include "llfloaterreg.h"
+#include "llnotificationmanager.h"
+#include "llnotificationsutil.h"
+#include "llscriptfloater.h"
+#include "llspeakers.h"
+#include "lltoastpanel.h"
+#include "lltoastnotifypanel.h"
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::LLFloaterNotificationsTabbed(const LLSD& key) : LLTransientDockableFloater(NULL, true, key),
+ mChannel(NULL),
+ mSysWellChiclet(NULL),
+ mGroupInviteMessageList(NULL),
+ mGroupNoticeMessageList(NULL),
+ mTransactionMessageList(NULL),
+ mSystemMessageList(NULL),
+ mNotificationsSeparator(NULL),
+ mNotificationsTabContainer(NULL),
+ NOTIFICATION_TABBED_ANCHOR_NAME("notification_well_panel"),
+ IM_WELL_ANCHOR_NAME("im_well_panel"),
+ mIsReshapedByUser(false)
+
+{
+ setOverlapsScreenChannel(true);
+ mNotificationUpdates.reset(new NotificationTabbedChannel(this));
+ mNotificationsSeparator = new LLNotificationSeparator();
+}
+
+//---------------------------------------------------------------------------------
+BOOL LLFloaterNotificationsTabbed::postBuild()
+{
+ mGroupInviteMessageList = getChild<LLNotificationListView>("group_invite_notification_list");
+ mGroupNoticeMessageList = getChild<LLNotificationListView>("group_notice_notification_list");
+ mTransactionMessageList = getChild<LLNotificationListView>("transaction_notification_list");
+ mSystemMessageList = getChild<LLNotificationListView>("system_notification_list");
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupInviteTypes(), mGroupInviteMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getGroupNoticeTypes(), mGroupNoticeMessageList);
+ mNotificationsSeparator->initTaggedList(LLNotificationListItem::getTransactionTypes(), mTransactionMessageList);
+ mNotificationsSeparator->initUnTaggedList(mSystemMessageList);
+ mNotificationsTabContainer = getChild<LLTabContainer>("notifications_tab_container");
+
+ mDeleteAllBtn = getChild<LLButton>("delete_all_button");
+ mDeleteAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickDeleteAllBtn,this));
+
+ mCollapseAllBtn = getChild<LLButton>("collapse_all_button");
+ mCollapseAllBtn->setClickedCallback(boost::bind(&LLFloaterNotificationsTabbed::onClickCollapseAllBtn,this));
+
+ // get a corresponding channel
+ initChannel();
+ BOOL rv = LLTransientDockableFloater::postBuild();
+
+ setTitle(getString("title_notification_tabbed_window"));
+ return rv;
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setMinimized(BOOL minimize)
+{
+ LLTransientDockableFloater::setMinimized(minimize);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::handleReshape(const LLRect& rect, bool by_user)
+{
+ mIsReshapedByUser |= by_user; // mark floater that it is reshaped by user
+ LLTransientDockableFloater::handleReshape(rect, by_user);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onStartUpToastClick(S32 x, S32 y, MASK mask)
+{
+ // just set floater visible. Screen channels will be cleared.
+ setVisible(TRUE);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setSysWellChiclet(LLSysWellChiclet* chiclet)
+{
+ mSysWellChiclet = chiclet;
+ if(NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::~LLFloaterNotificationsTabbed()
+{
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::removeItemByID(const LLUUID& id, std::string type)
+{
+ if(mNotificationsSeparator->removeItemByID(type, id))
+ {
+ if (NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+ reshapeWindow();
+ updateNotificationCounters();
+ }
+ else
+ {
+ LL_WARNS() << "Unable to remove notification from the list, ID: " << id
+ << LL_ENDL;
+ }
+
+ // hide chiclet window if there are no items left
+ if(isWindowEmpty())
+ {
+ setVisible(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::string type)
+{
+ return mNotificationsSeparator->findItemByID(type, id);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::initChannel()
+{
+ LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
+ LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
+ mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
+ if(NULL == mChannel)
+ {
+ LL_WARNS() << "LLSysWellWindow::initChannel() - could not get a requested screen channel" << LL_ENDL;
+ }
+
+ if(mChannel)
+ {
+ mChannel->addOnStoreToastCallback(boost::bind(&LLFloaterNotificationsTabbed::onStoreToast, this, _1, _2));
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setVisible(BOOL visible)
+{
+ if (visible)
+ {
+ // when Notification channel is cleared, storable toasts will be added into the list.
+ clearScreenChannels();
+ }
+ if (visible)
+ {
+ if (NULL == getDockControl() && getDockTongue().notNull())
+ {
+ setDockControl(new LLDockControl(
+ LLChicletBar::getInstance()->getChild<LLView>(getAnchorViewName()), this,
+ getDockTongue(), LLDockControl::BOTTOM));
+ }
+ }
+
+ // do not show empty window
+ if (NULL == mNotificationsSeparator || isWindowEmpty()) visible = FALSE;
+
+ LLTransientDockableFloater::setVisible(visible);
+
+ // update notification channel state
+ initChannel(); // make sure the channel still exists
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::setDocked(bool docked, bool pop_on_undock)
+{
+ LLTransientDockableFloater::setDocked(docked, pop_on_undock);
+
+ // update notification channel state
+ if(mChannel)
+ {
+ mChannel->updateShowToastsState();
+ mChannel->redrawToasts();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::reshapeWindow()
+{
+ // update notification channel state
+ // update on a window reshape is important only when a window is visible and docked
+ if(mChannel && getVisible() && isDocked())
+ {
+ mChannel->updateShowToastsState();
+ }
+}
+
+//---------------------------------------------------------------------------------
+bool LLFloaterNotificationsTabbed::isWindowEmpty()
+{
+ return mNotificationsSeparator->size() == 0;
+}
+
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed::NotificationTabbedChannel::NotificationTabbedChannel(LLFloaterNotificationsTabbed* notifications_tabbed_window)
+ : LLNotificationChannel(LLNotificationChannel::Params().name(notifications_tabbed_window->getPathname())),
+ mNotificationsTabbedWindow(notifications_tabbed_window)
+{
+ connectToChannel("Notifications");
+ connectToChannel("Group Notifications");
+ connectToChannel("Offer");
+}
+
+// static
+//---------------------------------------------------------------------------------
+LLFloaterNotificationsTabbed* LLFloaterNotificationsTabbed::getInstance(const LLSD& key /*= LLSD()*/)
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterNotificationsTabbed>("notification_well_window", key);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[COUNT]"] = llformat("%d", counterValue);
+ std::string label = getString(stringName, string_args);
+ mNotificationsTabContainer->setPanelTitle(panelIndex, label);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::updateNotificationCounters()
+{
+ updateNotificationCounter(0, mSystemMessageList->size(), "system_tab_title");
+ updateNotificationCounter(1, mTransactionMessageList->size(), "transactions_tab_title");
+ updateNotificationCounter(2, mGroupInviteMessageList->size(), "group_invitations_tab_title");
+ updateNotificationCounter(3, mGroupNoticeMessageList->size(), "group_notices_tab_title");
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::addItem(LLNotificationListItem::Params p)
+{
+ // do not add clones
+ if (mNotificationsSeparator->findItemByID(p.notification_name, p.notification_id))
+ return;
+ LLNotificationListItem* new_item = LLNotificationListItem::create(p);
+ if (new_item == NULL)
+ {
+ return;
+ }
+ if (mNotificationsSeparator->addItem(new_item->getNotificationName(), new_item))
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ reshapeWindow();
+ updateNotificationCounters();
+ new_item->setOnItemCloseCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClose, this, _1));
+ new_item->setOnItemClickCallback(boost::bind(&LLFloaterNotificationsTabbed::onItemClick, this, _1));
+ }
+ else
+ {
+ LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
+ << ", title: " << new_item->getTitle()
+ << LL_ENDL;
+
+ new_item->die();
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAll()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+
+ std::vector<LLNotificationListItem*> items;
+ mNotificationsSeparator->getItems(items);
+ std::vector<LLNotificationListItem*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ onItemClose(*iter);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const
+{
+ switch (mNotificationsTabContainer->getCurrentPanelIndex())
+ {
+ case 0:
+ mSystemMessageList->getItems(items);
+ break;
+ case 1:
+ mTransactionMessageList->getItems(items);
+ break;
+ case 2:
+ mGroupInviteMessageList->getItems(items);
+ break;
+ case 3:
+ mGroupNoticeMessageList->getItems(items);
+ break;
+ default:
+ break;
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::closeAllOnCurrentTab()
+{
+ // Need to clear notification channel, to add storable toasts into the list.
+ clearScreenChannels();
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ onItemClose(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::collapseAllOnCurrentTab()
+{
+ std::vector<LLPanel*> items;
+ getAllItemsOnCurrentTab(items);
+ std::vector<LLPanel*>::iterator iter = items.begin();
+ for (; iter != items.end(); ++iter)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*iter);
+ if (notify_item)
+ notify_item->setExpanded(FALSE);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::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 LLFloaterNotificationsTabbed::onStoreToast(LLPanel* info_panel, LLUUID id)
+{
+ LLNotificationListItem::Params p;
+ p.notification_id = id;
+ p.title = static_cast<LLToastPanel*>(info_panel)->getTitle();
+ LLNotificationPtr notify = mChannel->getToastByNotificationID(id)->getNotification();
+ LLSD payload = notify->getPayload();
+ p.notification_name = notify->getName();
+ p.transaction_id = payload["transaction_id"];
+ p.group_id = payload["group_id"];
+ p.fee = payload["fee"];
+ p.subject = payload["subject"].asString();
+ p.message = payload["message"].asString();
+ p.sender = payload["sender_name"].asString();
+ p.time_stamp = notify->getDate();
+ p.received_time = payload["received_time"].asDate();
+ p.paid_from_id = payload["from_id"];
+ p.paid_to_id = payload["dest_id"];
+ p.inventory_offer = payload["inventory_offer"];
+ p.notification_priority = notify->getPriority();
+ addItem(p);
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClick(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+ if (item->showPopup())
+ {
+ LLFloaterReg::showInstance("inspect_toast", id);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onItemClose(LLNotificationListItem* item)
+{
+ LLUUID id = item->getID();
+
+ if(mChannel)
+ {
+ // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
+ mChannel->killToastByNotificationID(id);
+ }
+ else
+ {
+ // removeItemByID() should be called one time for each item to remove it from notification well
+ removeItemByID(id, item->getNotificationName());
+ }
+
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onAdd( LLNotificationPtr notify )
+{
+ removeItemByID(notify->getID(), notify->getName());
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickDeleteAllBtn()
+{
+ closeAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLFloaterNotificationsTabbed::onClickCollapseAllBtn()
+{
+ collapseAllOnCurrentTab();
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::string& tag, LLNotificationListView* list)
+{
+ mNotificationListMap.insert(notification_list_map_t::value_type(tag, list));
+ mNotificationLists.push_back(list);
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list)
+{
+ std::set<std::string>::const_iterator it = tags.begin();
+ for(;it != tags.end();it++)
+ {
+ initTaggedList(*it, list);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::initUnTaggedList(LLNotificationListView* list)
+{
+ mUnTaggedList = list;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::addItem(std::string& tag, LLNotificationListItem* item)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->addNotification(item);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->addNotification(item);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+bool LLNotificationSeparator::removeItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->removeItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->removeItemByValue(id);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------
+U32 LLNotificationSeparator::size() const
+{
+ U32 size = 0;
+ notification_list_list_t::const_iterator it = mNotificationLists.begin();
+ for (; it != mNotificationLists.end(); it++)
+ {
+ size = size + (*it)->size();
+ }
+ if (mUnTaggedList != NULL)
+ {
+ size = size + mUnTaggedList->size();
+ }
+ return size;
+}
+
+//---------------------------------------------------------------------------------
+LLPanel* LLNotificationSeparator::findItemByID(std::string& tag, const LLUUID& id)
+{
+ notification_list_map_t::iterator it = mNotificationListMap.find(tag);
+ if (it != mNotificationListMap.end())
+ {
+ return it->second->getItemByValue(id);
+ }
+ else if (mUnTaggedList != NULL)
+ {
+ return mUnTaggedList->getItemByValue(id);
+ }
+
+ return NULL;
+}
+
+//static
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list)
+{
+ std::vector<LLPanel*> list_items;
+ list->getItems(list_items);
+ std::vector<LLPanel*>::iterator it = list_items.begin();
+ for (; it != list_items.end(); ++it)
+ {
+ LLNotificationListItem* notify_item = dynamic_cast<LLNotificationListItem*>(*it);
+ if (notify_item)
+ items.push_back(notify_item);
+ }
+}
+
+//---------------------------------------------------------------------------------
+void LLNotificationSeparator::getItems(std::vector<LLNotificationListItem*>& items) const
+{
+ items.clear();
+ notification_list_list_t::const_iterator lists_it = mNotificationLists.begin();
+ for (; lists_it != mNotificationLists.end(); lists_it++)
+ {
+ getItemsFromList(items, *lists_it);
+ }
+ if (mUnTaggedList != NULL)
+ {
+ getItemsFromList(items, mUnTaggedList);
+ }
+}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::LLNotificationSeparator()
+ : mUnTaggedList(NULL)
+{}
+
+//---------------------------------------------------------------------------------
+LLNotificationSeparator::~LLNotificationSeparator()
+{}
diff --git a/indra/newview/llfloaternotificationstabbed.h b/indra/newview/llfloaternotificationstabbed.h
new file mode 100644
index 0000000000..8dd20b18c4
--- /dev/null
+++ b/indra/newview/llfloaternotificationstabbed.h
@@ -0,0 +1,174 @@
+/**
+ * @file llfloaternotificationstabbed.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_FLOATERNOTIFICATIONSTABBED_H
+#define LL_FLOATERNOTIFICATIONSTABBED_H
+
+#include "llimview.h"
+#include "llnotifications.h"
+#include "llscreenchannel.h"
+#include "llsyswellitem.h"
+#include "lltransientdockablefloater.h"
+#include "llnotificationlistview.h"
+#include "lltabcontainer.h"
+
+class LLAvatarName;
+class LLChiclet;
+class LLFlatListView;
+class LLIMChiclet;
+class LLScriptChiclet;
+class LLSysWellChiclet;
+
+class LLNotificationSeparator
+{
+public:
+ LLNotificationSeparator();
+ ~LLNotificationSeparator();
+ void initTaggedList(const std::string& tag, LLNotificationListView* list);
+ void initTaggedList(const std::set<std::string>& tags, LLNotificationListView* list);
+ void initUnTaggedList(LLNotificationListView* list);
+ bool addItem(std::string& tag, LLNotificationListItem* item);
+ LLPanel* findItemByID(std::string& tag, const LLUUID& id);
+ bool removeItemByID(std::string& tag, const LLUUID& id);
+ void getItems(std::vector<LLNotificationListItem*>& items) const;
+ U32 size() const;
+private:
+ static void getItemsFromList(std::vector<LLNotificationListItem*>& items, LLNotificationListView* list);
+
+ typedef std::map<std::string, LLNotificationListView*> notification_list_map_t;
+ notification_list_map_t mNotificationListMap;
+ typedef std::list<LLNotificationListView*> notification_list_list_t;
+ notification_list_list_t mNotificationLists;
+ LLNotificationListView* mUnTaggedList;
+};
+
+class LLFloaterNotificationsTabbed : public LLTransientDockableFloater
+{
+public:
+ LOG_CLASS(LLFloaterNotificationsTabbed);
+
+ LLFloaterNotificationsTabbed(const LLSD& key);
+ virtual ~LLFloaterNotificationsTabbed();
+ BOOL postBuild();
+
+ // other interface functions
+ // check is window empty
+ bool isWindowEmpty();
+
+ // Operating with items
+ void removeItemByID(const LLUUID& id, std::string type);
+ LLPanel * findItemByID(const LLUUID& id, std::string type);
+ void updateNotificationCounters();
+ void updateNotificationCounter(S32 panelIndex, S32 counterValue, std::string stringName);
+
+ // Operating with outfit
+ virtual void setVisible(BOOL visible);
+
+ /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
+ // override LLFloater's minimization according to EXT-1216
+ /*virtual*/ void setMinimized(BOOL minimize);
+ /*virtual*/ void handleReshape(const LLRect& rect, bool by_user);
+
+ void onStartUpToastClick(S32 x, S32 y, MASK mask);
+ /*virtual*/ void onAdd(LLNotificationPtr notify);
+
+ void setSysWellChiclet(LLSysWellChiclet* chiclet);
+ void closeAll();
+
+ static LLFloaterNotificationsTabbed* getInstance(const LLSD& key = LLSD());
+
+ // size constants for the window and for its elements
+ static const S32 MAX_WINDOW_HEIGHT = 200;
+ static const S32 MIN_WINDOW_WIDTH = 318;
+
+private:
+ // init Window's channel
+ virtual void initChannel();
+
+ const std::string NOTIFICATION_TABBED_ANCHOR_NAME;
+ const std::string IM_WELL_ANCHOR_NAME;
+ //virtual const std::string& getAnchorViewName() = 0;
+
+ void reshapeWindow();
+
+ // pointer to a corresponding channel's instance
+ LLNotificationsUI::LLScreenChannel* mChannel;
+
+ /**
+ * Reference to an appropriate Well chiclet to release "new message" state. EXT-3147
+ */
+ LLSysWellChiclet* mSysWellChiclet;
+
+ bool mIsReshapedByUser;
+
+ struct NotificationTabbedChannel : public LLNotificationChannel
+ {
+ NotificationTabbedChannel(LLFloaterNotificationsTabbed*);
+ void onDelete(LLNotificationPtr notify)
+ {
+ mNotificationsTabbedWindow->removeItemByID(notify->getID(), notify->getName());
+ }
+
+ LLFloaterNotificationsTabbed* mNotificationsTabbedWindow;
+ };
+
+ LLNotificationChannelPtr mNotificationUpdates;
+ virtual const std::string& getAnchorViewName() { return NOTIFICATION_TABBED_ANCHOR_NAME; }
+
+ // init Window's channel
+ // void initChannel();
+ void clearScreenChannels();
+ // Operating with items
+ void addItem(LLNotificationListItem::Params p);
+ void getAllItemsOnCurrentTab(std::vector<LLPanel*>& items) const;
+
+ // Closes all notifications and removes them from the Notification Well
+ void closeAllOnCurrentTab();
+ void collapseAllOnCurrentTab();
+
+ void onStoreToast(LLPanel* info_panel, LLUUID id);
+ void onClickDeleteAllBtn();
+ void onClickCollapseAllBtn();
+ // Handlers
+ void onItemClick(LLNotificationListItem* item);
+ void onItemClose(LLNotificationListItem* item);
+ // ID of a toast loaded by user (by clicking notification well item)
+ LLUUID mLoadedToastId;
+
+ LLNotificationListView* mGroupInviteMessageList;
+ LLNotificationListView* mGroupNoticeMessageList;
+ LLNotificationListView* mTransactionMessageList;
+ LLNotificationListView* mSystemMessageList;
+ LLNotificationSeparator* mNotificationsSeparator;
+ LLTabContainer* mNotificationsTabContainer;
+ LLButton* mDeleteAllBtn;
+ LLButton* mCollapseAllBtn;
+};
+
+#endif // LL_FLOATERNOTIFICATIONSTABBED_H
+
+
+
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
new file mode 100644
index 0000000000..6e2cc39a06
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -0,0 +1,607 @@
+/**
+ * @file llnotificationlistitem.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h" // must be first include
+
+#include "llnotificationlistitem.h"
+
+#include "llagent.h"
+#include "llgroupactions.h"
+#include "llinventoryicon.h"
+#include "llwindow.h"
+#include "v4color.h"
+#include "lltrans.h"
+#include "lluicolortable.h"
+#include "message.h"
+#include "llnotificationsutil.h"
+LLNotificationListItem::LLNotificationListItem(const Params& p) : LLPanel(p),
+ mParams(p),
+ mTitleBox(NULL),
+ mExpandBtn(NULL),
+ mCondenseBtn(NULL),
+ mCloseBtn(NULL),
+ mCondensedViewPanel(NULL),
+ mExpandedViewPanel(NULL),
+ mCondensedHeight(0),
+ mExpandedHeight(0),
+ mExpandedHeightResize(0)
+{
+ mNotificationName = p.notification_name;
+}
+
+BOOL LLNotificationListItem::postBuild()
+{
+ BOOL rv = LLPanel::postBuild();
+ mTitleBox = getChild<LLTextBox>("notification_title");
+ mTitleBoxExp = getChild<LLTextBox>("notification_title_exp");
+ mNoticeTextExp = getChild<LLViewerTextEditor>("notification_text_exp");
+
+ mTimeBox = getChild<LLTextBox>("notification_time");
+ mTimeBoxExp = getChild<LLTextBox>("notification_time_exp");
+ mExpandBtn = getChild<LLButton>("expand_btn");
+ mCondenseBtn = getChild<LLButton>("condense_btn");
+ mCloseBtn = getChild<LLButton>("close_btn");
+ mCloseBtnExp = getChild<LLButton>("close_expanded_btn");
+
+ mTitleBox->setValue(mParams.title);
+ mTitleBoxExp->setValue(mParams.title);
+ mNoticeTextExp->setValue(mParams.title);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp));
+
+ mExpandBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickExpandBtn,this));
+ mCondenseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCondenseBtn,this));
+
+ //mCloseBtn and mCloseExpandedBtn share the same callback
+ mCloseBtn->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+ mCloseBtnExp->setClickedCallback(boost::bind(&LLNotificationListItem::onClickCloseBtn,this));
+
+ mCondensedViewPanel = getChild<LLPanel>("layout_panel_condensed_view");
+ mExpandedViewPanel = getChild<LLPanel>("layout_panel_expanded_view");
+
+ std::string expanded_height_str = getString("item_expanded_height");
+ std::string condensed_height_str = getString("item_condensed_height");
+
+ mExpandedHeight = (S32)atoi(expanded_height_str.c_str());
+ mCondensedHeight = (S32)atoi(condensed_height_str.c_str());
+
+ setExpanded(FALSE);
+
+ return rv;
+}
+
+LLNotificationListItem::~LLNotificationListItem()
+{
+}
+
+//static
+std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_stamp, ETimeType time_type)
+{
+ std::string timeStr;
+ switch(time_type)
+ {
+ case Local:
+ timeStr = "[" + LLTrans::getString("LTimeMthNum") + "]/["
+ +LLTrans::getString("LTimeDay")+"]/["
+ +LLTrans::getString("LTimeYear")+"] ["
+ +LLTrans::getString("LTimeHour")+"]:["
+ +LLTrans::getString("LTimeMin")+ "]";
+ break;
+ case UTC:
+ timeStr = "[" + LLTrans::getString("UTCTimeMth") + "]/["
+ +LLTrans::getString("UTCTimeDay")+"]/["
+ +LLTrans::getString("UTCTimeYr")+"] ["
+ +LLTrans::getString("UTCTimeHr")+"]:["
+ +LLTrans::getString("UTCTimeMin")+"] ["
+ +LLTrans::getString("UTCTimeTimezone")+"]";
+ break;
+ case SLT:
+ default:
+ timeStr = "[" + LLTrans::getString("TimeMonth") + "]/["
+ +LLTrans::getString("TimeDay")+"]/["
+ +LLTrans::getString("TimeYear")+"] ["
+ +LLTrans::getString("TimeHour")+"]:["
+ +LLTrans::getString("TimeMin")+"]";
+ break;
+ }
+ LLSD substitution;
+ substitution["datetime"] = time_stamp;
+ LLStringUtil::format(timeStr, substitution);
+ return timeStr;
+}
+
+void LLNotificationListItem::onClickCloseBtn()
+{
+ mOnItemClose(this);
+ close();
+}
+
+BOOL LLNotificationListItem::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ BOOL res = LLPanel::handleMouseUp(x, y, mask);
+ mOnItemClick(this);
+ return res;
+}
+
+void LLNotificationListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+}
+
+void LLNotificationListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+ mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
+}
+
+//static
+LLNotificationListItem* LLNotificationListItem::create(const Params& p)
+{
+ if (LLNotificationListItem::getGroupInviteTypes().count(p.notification_name))
+ {
+ return new LLGroupInviteNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getGroupNoticeTypes().count(p.notification_name))
+ {
+ return new LLGroupNoticeNotificationListItem(p);
+ }
+ else if (LLNotificationListItem::getTransactionTypes().count(p.notification_name))
+ {
+ return new LLTransactionNotificationListItem(p);
+ }
+ return new LLSystemNotificationListItem(p);
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getGroupInviteTypes()
+{
+ return LLGroupInviteNotificationListItem::getTypes();
+}
+
+
+std::set<std::string> LLNotificationListItem::getGroupNoticeTypes()
+{
+ return LLGroupNoticeNotificationListItem::getTypes();
+}
+
+//static
+std::set<std::string> LLNotificationListItem::getTransactionTypes()
+{
+ return LLTransactionNotificationListItem::getTypes();
+}
+
+void LLNotificationListItem::onClickExpandBtn()
+{
+ setExpanded(TRUE);
+}
+
+void LLNotificationListItem::onClickCondenseBtn()
+{
+ setExpanded(FALSE);
+}
+
+void LLNotificationListItem::setExpanded(BOOL value)
+{
+ mCondensedViewPanel->setVisible(!value);
+ mExpandedViewPanel->setVisible(value);
+ S32 width = this->getRect().getWidth();
+ if (value)
+ {
+ this->reshape(width, mExpandedHeight + mExpandedHeightResize, FALSE);
+ }
+ else
+ {
+ this->reshape(width, mCondensedHeight, FALSE);
+ }
+}
+
+std::set<std::string> LLGroupInviteNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("JoinGroup");
+ return types;
+}
+
+std::set<std::string> LLGroupNoticeNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("GroupNotice");
+ return types;
+}
+
+std::set<std::string> LLTransactionNotificationListItem::getTypes()
+{
+ std::set<std::string> types;
+ types.insert("PaymentReceived");
+ types.insert("PaymentSent");
+ return types;
+}
+
+LLGroupNotificationListItem::LLGroupNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSenderOrFeeBox(NULL)
+{
+}
+
+LLGroupInviteNotificationListItem::LLGroupInviteNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLGroupInviteNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+ setFee(mParams.fee);
+ mInviteButtonPanel = getChild<LLPanel>("button_panel");
+ mInviteButtonPanel->setVisible(TRUE);
+ mJoinBtn = getChild<LLButton>("join_btn");
+ mDeclineBtn = getChild<LLButton>("decline_btn");
+ mInfoBtn = getChild<LLButton>("info_btn");
+
+ mJoinBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickJoinBtn,this));
+ mDeclineBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickDeclineBtn,this));
+ mInfoBtn->setClickedCallback(boost::bind(&LLGroupInviteNotificationListItem::onClickInfoBtn,this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ return rv;
+}
+
+void LLGroupInviteNotificationListItem::onClickJoinBtn()
+{
+ if (!gAgent.canJoinGroups())
+ {
+ LLNotificationsUtil::add("JoinedTooManyGroups");
+ return;
+ }
+
+ if(mParams.fee > 0)
+ {
+ LLSD args;
+ args["COST"] = llformat("%d", mParams.fee);
+ // Set the fee for next time to 0, so that we don't keep
+ // asking about a fee.
+ LLSD next_payload;
+ next_payload["group_id"]= mParams.group_id;
+ next_payload["transaction_id"]= mParams.transaction_id;
+ next_payload["fee"] = 0;
+ LLNotificationsUtil::add("JoinGroupCanAfford", args, next_payload);
+ }
+ else
+ {
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_ACCEPT,
+ mParams.transaction_id);
+ }
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickDeclineBtn()
+{
+ send_improved_im(mParams.group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_DECLINE,
+ mParams.transaction_id);
+ LLNotificationListItem::onClickCloseBtn();
+}
+
+void LLGroupInviteNotificationListItem::onClickInfoBtn()
+{
+ LLGroupActions::show(mParams.group_id);
+}
+
+void LLGroupInviteNotificationListItem::setFee(S32 fee)
+{
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_FEE]"] = llformat("%d", fee);
+ std::string fee_text = getString("group_fee_text", string_args);
+ mSenderOrFeeBox->setValue(fee_text);
+ mSenderOrFeeBoxExp->setValue(fee_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+}
+
+LLGroupNoticeNotificationListItem::LLGroupNoticeNotificationListItem(const Params& p)
+ : LLGroupNotificationListItem(p),
+ mAttachmentPanel(NULL),
+ mAttachmentTextBox(NULL),
+ mAttachmentIcon(NULL),
+ mAttachmentIconExp(NULL),
+ mInventoryOffer(NULL)
+{
+ if (mParams.inventory_offer.isDefined())
+ {
+ mInventoryOffer = new LLOfferInfo(mParams.inventory_offer);
+ }
+
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+LLGroupNoticeNotificationListItem::~LLGroupNoticeNotificationListItem()
+{
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+BOOL LLGroupNoticeNotificationListItem::postBuild()
+{
+ BOOL rv = LLGroupNotificationListItem::postBuild();
+
+ mAttachmentTextBox = getChild<LLTextBox>("attachment_text");
+ mAttachmentIcon = getChild<LLIconCtrl>("attachment_icon");
+ mAttachmentIconExp = getChild<LLIconCtrl>("attachment_icon_exp");
+ mAttachmentPanel = getChild<LLPanel>("attachment_panel");
+ mAttachmentPanel->setVisible(FALSE);
+
+
+ mTitleBox->setValue(mParams.subject);
+ mTitleBoxExp->setValue(mParams.subject);
+ mNoticeTextExp->setValue(mParams.message);
+
+ mTimeBox->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp, UTC));
+ //Workaround: in case server timestamp is 0 - we use the time when notification was actually received
+ if (mParams.time_stamp.isNull())
+ {
+ mTimeBox->setValue(buildNotificationDate(mParams.received_time, UTC));
+ mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time, UTC));
+ }
+ setSender(mParams.sender);
+
+ if (mInventoryOffer != NULL)
+ {
+ mAttachmentTextBox->setValue(mInventoryOffer->mDesc);
+ mAttachmentTextBox->setVisible(TRUE);
+ mAttachmentIcon->setVisible(TRUE);
+
+ std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType,
+ LLInventoryType::IT_TEXTURE);
+ mAttachmentIconExp->setValue(icon_name);
+ mAttachmentIconExp->setVisible(TRUE);
+
+ mAttachmentTextBox->setClickedCallback(boost::bind(
+ &LLGroupNoticeNotificationListItem::onClickAttachment, this));
+
+ std::string expanded_height_resize_str = getString("expanded_height_resize_for_attachment");
+ mExpandedHeightResize = (S32)atoi(expanded_height_resize_str.c_str());
+
+ mAttachmentPanel->setVisible(TRUE);
+ }
+ return rv;
+}
+
+BOOL LLGroupNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+
+ mGroupIcon = getChild<LLGroupIconCtrl>("group_icon");
+ mGroupIconExp = getChild<LLGroupIconCtrl>("group_icon_exp");
+ mGroupNameBoxExp = getChild<LLTextBox>("group_name_exp");
+
+ mGroupIcon->setValue(mParams.group_id);
+ mGroupIconExp->setValue(mParams.group_id);
+
+ mGroupIcon->setVisible(TRUE);
+ mGroupIconExp->setVisible(TRUE);
+
+ mGroupId = mParams.group_id;
+
+ mSenderOrFeeBox = getChild<LLTextBox>("sender_or_fee_box");
+ mSenderOrFeeBoxExp = getChild<LLTextBox>("sender_or_fee_box_exp");
+
+ LLSD value(mParams.group_id);
+ setGroupId(value);
+
+ return rv;
+}
+
+void LLGroupNotificationListItem::changed(LLGroupChange gc)
+{
+ if (GC_PROPERTIES == gc)
+ {
+ updateFromCache();
+ LLGroupMgr::getInstance()->removeObserver(this);
+ }
+}
+
+bool LLGroupNotificationListItem::updateFromCache()
+{
+ LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mGroupId);
+ if (!group_data) return false;
+ setGroupName(group_data->mName);
+ return true;
+}
+
+void LLGroupNotificationListItem::setGroupId(const LLUUID& value)
+{
+ LLGroupMgr* gm = LLGroupMgr::getInstance();
+ if (mGroupId.notNull())
+ {
+ gm->removeObserver(this);
+
+
+ mID = mGroupId;
+
+ // Check if cache already contains image_id for that group
+ if (!updateFromCache())
+ {
+ gm->addObserver(this);
+ gm->sendGroupPropertiesRequest(mGroupId);
+ }
+ }
+}
+
+void LLGroupNotificationListItem::setGroupName(std::string name)
+{
+ if (!name.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[GROUP_NAME]"] = llformat("%s", name.c_str());
+ std::string group_box_str = getString("group_name_text", string_args);
+ mGroupNameBoxExp->setValue(group_box_str);
+ mGroupNameBoxExp->setVisible(TRUE);
+ }
+ else
+ {
+ mGroupNameBoxExp->setValue(LLStringUtil::null);
+ mGroupNameBoxExp->setVisible(FALSE);
+ }
+}
+
+void LLGroupNoticeNotificationListItem::setSender(std::string sender)
+{
+ if (!sender.empty())
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[SENDER_RESIDENT]"] = llformat("%s", sender.c_str());
+ std::string sender_text = getString("sender_resident_text", string_args);
+ mSenderOrFeeBox->setValue(sender_text);
+ mSenderOrFeeBoxExp->setValue(sender_text);
+ mSenderOrFeeBox->setVisible(TRUE);
+ mSenderOrFeeBoxExp->setVisible(TRUE);
+ } else {
+ mSenderOrFeeBox->setValue(LLStringUtil::null);
+ mSenderOrFeeBoxExp->setValue(LLStringUtil::null);
+ mSenderOrFeeBox->setVisible(FALSE);
+ mSenderOrFeeBoxExp->setVisible(FALSE);
+ }
+}
+void LLGroupNoticeNotificationListItem::close()
+{
+ // The group notice dialog may be an inventory offer.
+ // If it has an inventory save button and that button is still enabled
+ // Then we need to send the inventory declined message
+ if (mInventoryOffer != NULL)
+ {
+ mInventoryOffer->forceResponse(IOR_DECLINE);
+ mInventoryOffer = NULL;
+ }
+ LLGroupMgr::getInstance()->removeObserver(this);
+}
+
+void LLGroupNoticeNotificationListItem::onClickAttachment()
+{
+ if (mInventoryOffer != NULL) {
+ mInventoryOffer->forceResponse(IOR_ACCEPT);
+
+ static const LLUIColor textColor = LLUIColorTable::instance().getColor(
+ "GroupNotifyDimmedTextColor");
+ mAttachmentTextBox->setColor(textColor);
+ mAttachmentIconExp->setEnabled(FALSE);
+
+ //if attachment isn't openable - notify about saving
+ if (!isAttachmentOpenable(mInventoryOffer->mType)) {
+ LLNotifications::instance().add("AttachmentSaved", LLSD(), LLSD());
+ }
+
+ mInventoryOffer = NULL;
+ }
+}
+
+//static
+bool LLGroupNoticeNotificationListItem::isAttachmentOpenable(LLAssetType::EType type)
+{
+ switch (type)
+ {
+ case LLAssetType::AT_LANDMARK:
+ case LLAssetType::AT_NOTECARD:
+ case LLAssetType::AT_IMAGE_JPEG:
+ case LLAssetType::AT_IMAGE_TGA:
+ case LLAssetType::AT_TEXTURE:
+ case LLAssetType::AT_TEXTURE_TGA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+LLTransactionNotificationListItem::LLTransactionNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mAvatarIcon(NULL)
+{
+ buildFromFile("panel_notification_list_item.xml");
+}
+
+BOOL LLTransactionNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ mAvatarIconExp = getChild<LLAvatarIconCtrl>("avatar_icon_exp");
+ mAvatarIcon->setValue("System_Notification");
+ mAvatarIconExp->setValue("System_Notification");
+
+ if (mParams.notification_name == "PaymentReceived")
+ {
+ mAvatarIcon->setValue(mParams.paid_from_id);
+ mAvatarIconExp->setValue(mParams.paid_from_id);
+ }
+ else if (mParams.notification_name == "PaymentSent")
+ {
+ mAvatarIcon->setValue(mParams.paid_to_id);
+ mAvatarIconExp->setValue(mParams.paid_to_id);
+ }
+ mAvatarIcon->setVisible(TRUE);
+ mAvatarIconExp->setVisible(TRUE);
+ return rv;
+}
+
+LLSystemNotificationListItem::LLSystemNotificationListItem(const Params& p)
+ : LLNotificationListItem(p),
+ mSystemNotificationIcon(NULL),
+ mIsCaution(false)
+{
+ buildFromFile("panel_notification_list_item.xml");
+ mIsCaution = p.notification_priority >= NOTIFICATION_PRIORITY_HIGH;
+ if (mIsCaution)
+ {
+ mTitleBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTitleBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mNoticeTextExp->setReadOnlyColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBox->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ mTimeBoxExp->setColor(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+ }
+}
+
+BOOL LLSystemNotificationListItem::postBuild()
+{
+ BOOL rv = LLNotificationListItem::postBuild();
+ mSystemNotificationIcon = getChild<LLIconCtrl>("system_notification_icon");
+ mSystemNotificationIconExp = getChild<LLIconCtrl>("system_notification_icon_exp");
+ if (mSystemNotificationIcon)
+ mSystemNotificationIcon->setVisible(TRUE);
+ if (mSystemNotificationIconExp)
+ mSystemNotificationIconExp->setVisible(TRUE);
+ return rv;
+}
diff --git a/indra/newview/llnotificationlistitem.h b/indra/newview/llnotificationlistitem.h
new file mode 100644
index 0000000000..950b75c39a
--- /dev/null
+++ b/indra/newview/llnotificationlistitem.h
@@ -0,0 +1,248 @@
+/**
+ * @file llnotificationlistitem.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONLISTITEM_H
+#define LL_LLNOTIFICATIONLISTITEM_H
+
+#include "llpanel.h"
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "llviewertexteditor.h"
+#include "llbutton.h"
+#include "llgroupiconctrl.h"
+#include "llavatariconctrl.h"
+
+#include "llgroupmgr.h"
+#include "llviewermessage.h"
+
+#include <string>
+
+class LLNotificationListItem : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {
+ LLUUID notification_id;
+ LLUUID transaction_id;
+ LLUUID group_id;
+ LLUUID paid_from_id;
+ LLUUID paid_to_id;
+ std::string notification_name;
+ std::string title;
+ std::string subject;
+ std::string message;
+ std::string sender;
+ S32 fee;
+ LLDate time_stamp;
+ LLDate received_time;
+ LLSD inventory_offer;
+ e_notification_priority notification_priority;
+ Params() {};
+ };
+
+ static LLNotificationListItem* create(const Params& p);
+
+ static std::set<std::string> getTransactionTypes();
+ static std::set<std::string> getGroupInviteTypes();
+ static std::set<std::string> getGroupNoticeTypes();
+
+ // title
+ void setTitle( std::string title );
+
+ // get item's ID
+ LLUUID getID() { return mParams.notification_id; }
+ std::string& getTitle() { return mTitle; }
+ std::string& getNotificationName() { return mNotificationName; }
+
+ // handlers
+ virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+ virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
+ //callbacks
+ typedef boost::function<void (LLNotificationListItem* item)> item_callback_t;
+ typedef boost::signals2::signal<void (LLNotificationListItem* item)> item_signal_t;
+ item_signal_t mOnItemClose;
+ item_signal_t mOnItemClick;
+ boost::signals2::connection setOnItemCloseCallback(item_callback_t cb) { return mOnItemClose.connect(cb); }
+ boost::signals2::connection setOnItemClickCallback(item_callback_t cb) { return mOnItemClick.connect(cb); }
+
+ virtual bool showPopup() { return true; }
+ void setExpanded(BOOL value);
+ virtual BOOL postBuild();
+
+ typedef enum e_time_type
+ {
+ SLT = 1,
+ Local = 2,
+ UTC = 3,
+ }ETimeType;
+
+protected:
+ LLNotificationListItem(const Params& p);
+ virtual ~LLNotificationListItem();
+
+ static std::string buildNotificationDate(const LLDate& time_stamp, ETimeType time_type = SLT);
+ void onClickExpandBtn();
+ void onClickCondenseBtn();
+ void onClickCloseBtn();
+ virtual void close() {};
+
+ Params mParams;
+ LLTextBox* mTitleBox;
+ LLTextBox* mTitleBoxExp;
+ LLViewerTextEditor* mNoticeTextExp;
+ LLTextBox* mTimeBox;
+ LLTextBox* mTimeBoxExp;
+ LLButton* mExpandBtn;
+ LLButton* mCondenseBtn;
+ LLButton* mCloseBtn;
+ LLButton* mCloseBtnExp;
+ LLPanel* mCondensedViewPanel;
+ LLPanel* mExpandedViewPanel;
+ std::string mTitle;
+ std::string mNotificationName;
+ S32 mCondensedHeight;
+ S32 mExpandedHeight;
+ S32 mExpandedHeightResize;
+};
+
+class LLGroupNotificationListItem
+ : public LLNotificationListItem, public LLGroupMgrObserver
+{
+public:
+ virtual BOOL postBuild();
+
+ void setGroupId(const LLUUID& value);
+ // LLGroupMgrObserver observer trigger
+ virtual void changed(LLGroupChange gc);
+
+ friend class LLNotificationListItem;
+protected:
+ LLGroupNotificationListItem(const Params& p);
+
+ LLGroupIconCtrl* mGroupIcon;
+ LLGroupIconCtrl* mGroupIconExp;
+ LLUUID mGroupId;
+ LLTextBox* mSenderOrFeeBox;
+ LLTextBox* mSenderOrFeeBoxExp;
+ LLTextBox* mGroupNameBoxExp;
+
+private:
+ LLGroupNotificationListItem(const LLGroupNotificationListItem &);
+ LLGroupNotificationListItem & operator=(LLGroupNotificationListItem &);
+
+ void setGroupName(std::string name);
+ bool updateFromCache();
+};
+
+class LLGroupInviteNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupInviteNotificationListItem(const Params& p);
+ LLGroupInviteNotificationListItem(const LLGroupInviteNotificationListItem &);
+ LLGroupInviteNotificationListItem & operator=(LLGroupInviteNotificationListItem &);
+
+ void setFee(S32 fee);
+
+ void onClickJoinBtn();
+ void onClickDeclineBtn();
+ void onClickInfoBtn();
+
+ LLPanel* mInviteButtonPanel;
+ LLButton* mJoinBtn;
+ LLButton* mDeclineBtn;
+ LLButton* mInfoBtn;
+};
+
+class LLGroupNoticeNotificationListItem
+ : public LLGroupNotificationListItem
+{
+public:
+ ~LLGroupNoticeNotificationListItem();
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+
+ /*virtual*/ bool showPopup() { return false; }
+
+private:
+ friend class LLNotificationListItem;
+ LLGroupNoticeNotificationListItem(const Params& p);
+ LLGroupNoticeNotificationListItem(const LLGroupNoticeNotificationListItem &);
+ LLGroupNoticeNotificationListItem & operator=(LLGroupNoticeNotificationListItem &);
+
+ void setSender(std::string sender);
+ void onClickAttachment();
+ /*virtual*/ void close();
+
+ static bool isAttachmentOpenable(LLAssetType::EType);
+
+ LLPanel* mAttachmentPanel;
+ LLTextBox* mAttachmentTextBox;
+ LLIconCtrl* mAttachmentIcon;
+ LLIconCtrl* mAttachmentIconExp;
+ LLOfferInfo* mInventoryOffer;
+};
+
+class LLTransactionNotificationListItem : public LLNotificationListItem
+{
+public:
+ static std::set<std::string> getTypes();
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLTransactionNotificationListItem(const Params& p);
+ LLTransactionNotificationListItem(const LLTransactionNotificationListItem &);
+ LLTransactionNotificationListItem & operator=(LLTransactionNotificationListItem &);
+ LLAvatarIconCtrl* mAvatarIcon;
+ LLAvatarIconCtrl* mAvatarIconExp;
+};
+
+class LLSystemNotificationListItem : public LLNotificationListItem
+{
+public:
+ virtual BOOL postBuild();
+private:
+ friend class LLNotificationListItem;
+ LLSystemNotificationListItem(const Params& p);
+ LLSystemNotificationListItem(const LLSystemNotificationListItem &);
+ LLSystemNotificationListItem & operator=(LLSystemNotificationListItem &);
+ LLIconCtrl* mSystemNotificationIcon;
+ LLIconCtrl* mSystemNotificationIconExp;
+ bool mIsCaution;
+};
+
+#endif // LL_LLNOTIFICATIONLISTITEM_H
+
+
diff --git a/indra/newview/llnotificationlistview.cpp b/indra/newview/llnotificationlistview.cpp
new file mode 100644
index 0000000000..9dce68c9c6
--- /dev/null
+++ b/indra/newview/llnotificationlistview.cpp
@@ -0,0 +1,44 @@
+/**
+ * @file llnotificationlistview.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#include "llviewerprecompiledheaders.h"
+
+#include "llnotificationlistview.h"
+
+static const LLDefaultChildRegistry::Register<LLNotificationListView> notification_list_view("notification_list_view");
+
+LLNotificationListView::LLNotificationListView(const Params& p)
+ : LLFlatListView(p)
+{}
+
+LLNotificationListView::~LLNotificationListView()
+{}
+
+bool LLNotificationListView::addNotification(LLNotificationListItem * item)
+{
+ return LLFlatListView::addItem(item, item->getID(), ADD_TOP);
+}
+
+//EOF
diff --git a/indra/newview/llnotificationlistview.h b/indra/newview/llnotificationlistview.h
new file mode 100644
index 0000000000..307ad87789
--- /dev/null
+++ b/indra/newview/llnotificationlistview.h
@@ -0,0 +1,49 @@
+/**
+ * @file llnotificationlistview.h
+ * @brief LLNotificationListView class to support notifications list contained in enclosing floater.
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONLISTVIEW_H
+#define LL_LLNOTIFICATIONLISTVIEW_H
+
+#include "llflatlistview.h"
+#include "llnotificationlistitem.h"
+
+/**
+ * Notification list
+ */
+class LLNotificationListView : public LLFlatListView
+{
+ LOG_CLASS(LLNotificationListView);
+public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> {};
+
+ LLNotificationListView(const Params& p);
+ ~LLNotificationListView();
+ friend class LLUICtrlFactory;
+
+ virtual bool addNotification(LLNotificationListItem * item);
+};
+
+#endif
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 8babb874f8..8f64cff47c 100755
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -296,158 +296,6 @@ BOOL LLIMWellWindow::ObjectRowPanel::handleRightMouseDown(S32 x, S32 y, MASK mas
}
/************************************************************************/
-/* LLNotificationWellWindow implementation */
-/************************************************************************/
-
-//////////////////////////////////////////////////////////////////////////
-// PUBLIC METHODS
-LLNotificationWellWindow::WellNotificationChannel::WellNotificationChannel(LLNotificationWellWindow* well_window)
-: LLNotificationChannel(LLNotificationChannel::Params().name(well_window->getPathname())),
- mWellWindow(well_window)
-{
- connectToChannel("Notifications");
- connectToChannel("Group Notifications");
- connectToChannel("Offer");
-}
-
-LLNotificationWellWindow::LLNotificationWellWindow(const LLSD& key)
-: LLSysWellWindow(key)
-{
- mNotificationUpdates.reset(new WellNotificationChannel(this));
-}
-
-// static
-LLNotificationWellWindow* LLNotificationWellWindow::getInstance(const LLSD& key /*= LLSD()*/)
-{
- return LLFloaterReg::getTypedInstance<LLNotificationWellWindow>("notification_well_window", key);
-}
-
-// virtual
-BOOL LLNotificationWellWindow::postBuild()
-{
- BOOL rv = LLSysWellWindow::postBuild();
- setTitle(getString("title_notification_well_window"));
- return rv;
-}
-
-// virtual
-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))
- {
- mSysWellChiclet->updateWidget(isWindowEmpty());
- reshapeWindow();
- new_item->setOnItemCloseCallback(boost::bind(&LLNotificationWellWindow::onItemClose, this, _1));
- new_item->setOnItemClickCallback(boost::bind(&LLNotificationWellWindow::onItemClick, this, _1));
- }
- else
- {
- LL_WARNS() << "Unable to add Notification into the list, notification ID: " << p.notification_id
- << ", title: " << p.title
- << LL_ENDL;
-
- new_item->die();
- }
-}
-
-void LLNotificationWellWindow::closeAll()
-{
- // Need to clear notification channel, to add storable toasts into the list.
- clearScreenChannels();
- std::vector<LLPanel*> items;
- mMessageList->getItems(items);
- for (std::vector<LLPanel*>::iterator
- iter = items.begin(),
- iter_end = items.end();
- iter != iter_end; ++iter)
- {
- LLSysWellItem* sys_well_item = dynamic_cast<LLSysWellItem*>(*iter);
- if (sys_well_item)
- onItemClose(sys_well_item);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-// PRIVATE METHODS
-void LLNotificationWellWindow::initChannel()
-{
- LLSysWellWindow::initChannel();
- if(mChannel)
- {
- mChannel->addOnStoreToastCallback(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::onItemClick(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
- LLFloaterReg::showInstance("inspect_toast", id);
-}
-
-void LLNotificationWellWindow::onItemClose(LLSysWellItem* item)
-{
- LLUUID id = item->getID();
-
- if(mChannel)
- {
- // removeItemByID() is invoked from killToastByNotificationID() and item will removed;
- mChannel->killToastByNotificationID(id);
- }
- else
- {
- // removeItemByID() should be called one time for each item to remove it from notification well
- removeItemByID(id);
- }
-
-}
-
-void LLNotificationWellWindow::onAdd( LLNotificationPtr notify )
-{
- removeItemByID(notify->getID());
-}
-
-/************************************************************************/
/* LLIMWellWindow implementation */
/************************************************************************/
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 71b41476f5..d02293e6ff 100755
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -96,57 +96,6 @@ protected:
};
/**
- * Class intended to manage incoming notifications.
- *
- * It contains a list of notifications that have not been responded to.
- */
-class LLNotificationWellWindow : public LLSysWellWindow
-{
-public:
- LLNotificationWellWindow(const LLSD& key);
- static LLNotificationWellWindow* getInstance(const LLSD& key = LLSD());
-
- /*virtual*/ BOOL postBuild();
- /*virtual*/ void setVisible(BOOL visible);
- /*virtual*/ void onAdd(LLNotificationPtr notify);
- // Operating with items
- void addItem(LLSysWellItem::Params p);
-
- // Closes all notifications and removes them from the Notification Well
- void closeAll();
-
-protected:
- struct WellNotificationChannel : public LLNotificationChannel
- {
- WellNotificationChannel(LLNotificationWellWindow*);
- void onDelete(LLNotificationPtr notify)
- {
- mWellWindow->removeItemByID(notify->getID());
- }
-
- LLNotificationWellWindow* mWellWindow;
- };
-
- LLNotificationChannelPtr mNotificationUpdates;
- /*virtual*/ const std::string& getAnchorViewName() { return NOTIFICATION_WELL_ANCHOR_NAME; }
-
-private:
- // init Window's channel
- void initChannel();
- void clearScreenChannels();
-
- void onStoreToast(LLPanel* info_panel, LLUUID id);
-
- // Handlers
- void onItemClick(LLSysWellItem* item);
- void onItemClose(LLSysWellItem* item);
-
- // ID of a toast loaded by user (by clicking notification well item)
- LLUUID mLoadedToastId;
-
-};
-
-/**
* Class intended to manage incoming messages in IM chats.
*
* It contains a list list of all active IM sessions.
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index e00b18dedb..e22f527a65 100755
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -92,7 +92,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
+LLTrans::getString("UTCTimeSec")+"] ["
+LLTrans::getString("UTCTimeTimezone")+"]";
const LLDate timeStamp = notification->getDate();
- LLDate notice_date = timeStamp.notNull() ? timeStamp : LLDate::now();
+ LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate();
LLSD substitution;
substitution["datetime"] = (S32) notice_date.secondsSinceEpoch();
LLStringUtil::format(timeStr, substitution);
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 1178652408..14a2627f27 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -90,6 +90,7 @@
#include "llfloatermodelpreview.h"
#include "llfloaternamedesc.h"
#include "llfloaternotificationsconsole.h"
+#include "llfloaternotificationstabbed.h"
#include "llfloaterobjectweights.h"
#include "llfloateropenobject.h"
#include "llfloateroutbox.h"
@@ -268,7 +269,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>);
LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>);
- LLFloaterReg::add("notification_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNotificationWellWindow>);
+
+ LLFloaterReg::add("notification_well_window", "floater_notifications_tabbed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationsTabbed>);
LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 886725be79..fe94c068ee 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2681,6 +2681,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["sender_name"] = name;
payload["group_id"] = group_id;
payload["inventory_name"] = item_name;
+ payload["received_time"] = LLDate::now();
if(info && info->asLLSD())
{
payload["inventory_offer"] = info->asLLSD();
@@ -5635,6 +5636,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg)
}
}
final_args["MESSAGE"] = message;
+ payload["dest_id"] = dest_id;
notification = success ? "PaymentSent" : "PaymentFailure";
}
else {
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index bdc884885f..8533625e50 100755
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -873,8 +873,11 @@
<color
name="ToolbarDropZoneColor"
value=".48 .69 1 .5" />
-
- <!-- Generic color names (legacy) -->
+ <color
+ name="PanelNotificationListItem"
+ value="0.3 0.3 0.3 .3" />
+
+ <!-- Generic color names (legacy) -->
<color
name="white"
value="1 1 1 1"/>
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
new file mode 100644
index 0000000000..0732a33d93
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
new file mode 100644
index 0000000000..8124554902
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Attachment_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
new file mode 100644
index 0000000000..4d245eb57a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Condense.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
new file mode 100644
index 0000000000..186822da43
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Notification_Expand.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Large.png b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
new file mode 100644
index 0000000000..434ce3e8b6
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Large.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/System_Notification_Small.png b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
new file mode 100644
index 0000000000..027a8446d8
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/System_Notification_Small.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index a5f2ce1f84..e453d94883 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -804,4 +804,9 @@ with the same filename but different name
<texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
<texture name="NavBar Separator" file_name="navbar/separator.png"/>
+ <texture name="Notification_Condense" file_name="icons/Icon_Notification_Condense.png" preload="true"/>
+ <texture name="Notification_Expand" file_name="icons/Icon_Notification_Expand.png" preload="true"/>
+ <texture name="System_Notification" file_name="icons/SL_Logo.png" preload="true"/>
+ <texture name="Icon_Attachment_Small" file_name="icons/Icon_Attachment_Small.png" preload="true"/>
+ <texture name="Icon_Attachment_Large" file_name="icons/Icon_Attachment_Large.png" preload="true"/>
</textures>
diff --git a/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
new file mode 100644
index 0000000000..b18c6b1e82
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_notifications_tabbed.xml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater
+ legacy_header_height="18"
+ bevel_style="in"
+ layout="topleft"
+ name="floater_notifications_tabbed"
+ help_topic="notification_chiclet"
+ save_rect="true"
+ title="NOTIFICATIONS"
+ width="350"
+ min_width="320"
+ height="550"
+ can_minimize="false"
+ can_tear_off="false"
+ can_resize="true"
+ can_drag_on_left="false"
+ can_dock="true"
+ save_dock_state="true"
+ save_visibility="true"
+ single_instance="true"
+>
+ <floater.string
+ name="system_tab_title">
+ System ([COUNT])
+ </floater.string>
+ <floater.string
+ name="transactions_tab_title">
+ Transactions ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_invitations_tab_title">
+ Invitations ([COUNT])
+ </floater.string>
+ <floater.string
+ name="group_notices_tab_title">
+ Group ([COUNT])
+ </floater.string>
+
+ <string
+ name="title_notification_tabbed_window">
+ NOTIFICATIONS
+ </string>
+ <layout_stack
+ width="336"
+ height="533"
+ enabled="true"
+ orientation="vertical"
+ name="TabButtonsStack"
+ follows="left|top|right|bottom"
+ top="17">
+ <layout_panel
+ width="336"
+ height="530"
+ enabled="true"
+ name="TabButtonsLayoutPanel">
+ <tab_container
+ follows="left|top|right|bottom"
+ halign="center"
+ layout="topleft"
+ tab_position="top"
+ left="7"
+ top="7"
+ width="336"
+ height="491"
+ mouse_opaque="true"
+ name="notifications_tab_container">
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="System (0)"
+ layout="topleft"
+ name="system_notification_list_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="system_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="330"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Transactions (0)"
+ layout="topleft"
+ name="transaction_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="transaction_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Invitations (0)"
+ layout="topleft"
+ name="group_invite_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_invite_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ <panel
+ border="true"
+ bevel_style="none"
+ follows="left|top|right|bottom"
+ label="Group (0)"
+ layout="topleft"
+ name="group_notice_notifications_tab">
+ <notification_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="group_notice_notification_list"
+ left="0"
+ top="5"
+ height="0"
+ width="328"/>
+ </panel>
+ </tab_container>
+
+ <layout_stack width="336" height="26" enabled="true" orientation="horizontal" follows="left|right" name="ButtonsStack">
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="CondenseAllButtonPanel">
+ <button width="93" height="21" left="2" label="Collapse all" name="collapse_all_button">
+ </button>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="GapLayoutPanel">
+ <panel width="90" height="21" left="2" label="Gap Panel" border="false" name="GapPanel">
+ </panel>
+ </layout_panel>
+ <layout_panel width="336" height="30" enabled="true" orientation="horizontal" name="DeleteAllButtonPanel">
+ <button width="93" height="21" left="2" label="Delete all" name="delete_all_button">
+ </button>
+ </layout_panel>
+ </layout_stack>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml
index ecedb27438..2c5176cf01 100755
--- a/indra/newview/skins/default/xui/en/floater_sys_well.xml
+++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml
@@ -23,10 +23,6 @@
name="title_im_well_window">
CONVERSATIONS
</string>
- <string
- name="title_notification_well_window">
- NOTIFICATIONS
- </string>
<flat_list_view
color="FloaterDefaultBackgroundColor"
diff --git a/indra/newview/skins/default/xui/en/panel_notification_list_item.xml b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
new file mode 100644
index 0000000000..73f90f73aa
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- All our XML is utf-8 encoded. -->
+<panel
+ translate="false"
+ name="main_panel"
+ title="panel_notification_list_item"
+ visible="true"
+ top="0"
+ left="0"
+ width="331"
+ height="202"
+ can_resize="true"
+ layout="topleft"
+ follows="left|top|right|bottom" >
+ <!-- background_opaque="false" -->
+ <!-- background_visible="true"> -->
+ <!-- bg_alpha_color="PanelNotificationListItem"> -->
+ <panel.string
+ name="sender_resident_text">
+ Sender: "[SENDER_RESIDENT]"
+ </panel.string>
+ <panel.string
+ name="group_name_text">
+ Group: "[GROUP_NAME]"
+ </panel.string>
+ <panel.string
+ name="group_fee_text">
+ Fee: [GROUP_FEE]
+ </panel.string>
+ <panel.string
+ name="item_condensed_height">
+ 50
+ </panel.string>
+ <panel.string
+ name="item_expanded_height">
+ 175
+ </panel.string>
+ <panel.string
+ name="expanded_height_resize_for_attachment">
+ 27
+ </panel.string>
+
+ <panel top="0" left="0" width="331" height="196" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_total_view">
+ <layout_stack top="0" left="0" width="331" height="196" orientation="vertical" follows="left|top|right|bottom" name="item_vertical_stack">
+ <layout_panel top="0" left="0" height="30" follows="left|top|right|bottom" layout="topleft" name="layout_panel_condensed_view" visible="false" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="30" bevel_style="none" layout="topleft" follows="left|top|right|bottom" name="panel_condensed_view">
+ <layout_stack top="0" left="0" width="325" height="50" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="39" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_right">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ </layout_panel>
+ <layout_panel width="260" height="50" orientation="horizontal" name="layout_panel_middle">
+ <panel border="false" top="0" width="260" height="38" bevel_style="none" follows="left|top|right" layout="topleft" name="main_info_panel">
+ <panel border="false" top="0" left="0" width="260" height="19" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="notification_title_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="6" left="0" width="260" height="12" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="true" mouse_opaque="false" name="notification_title" >
+ Group Name:Notice Title N o t i c e T i t l e N o t i c e T i t l e N o t i c e T i t l e N oticeTitle
+ </text>
+ <icon top="1" left="242" width="21" height="21" image_name="Icon_Attachment_Small" follows="right" mouse_opaque="true" name="attachment_icon" tool_tip="Attachment" visible="false"/>
+ </panel>
+ <panel border="false" top="23" left="0" width="260" height="15" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="sender_time_panel">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="170" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-5" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time" value="2014/12/24 23:30" />
+ </panel>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" height="48" orientation="horizontal" follows="right|top|bottom" name="layout_panel_right">
+ <panel top="0" left="0" width="17" height="39" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel">
+ <button top="0" left="0" width="17" height="17" layout="topleft" follows="top" name="close_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="-16" right="15" width="17" height="17" layout="topleft" follows="bottom" name="expand_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Expand" image_selected="Notification_Expand" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ <layout_panel top="0" left="0" height="196" follows="left|top|right|bottom" layout="topleft" name="layout_panel_expanded_view" visible="true" background_opaque="false" background_visible="true" bg_alpha_color="SysWellItemUnselected">
+ <panel border="true" top="0" left="5" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="panel_expanded_view">
+ <layout_stack top="0" left="0" width="325" height="196" orientation="horizontal" follows="left|top|right|bottom" name="horizontal_stack">
+ <layout_panel width="30" height="170" orientation="horizontal" follows="left|top|bottom" name="layout_panel_right_exp">
+ <group_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="group_icon_exp" tool_tip="Group" default_icon_name="Generic_Group" visible="true"/>
+ <avatar_icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="avatar_icon_exp" tool_tip="Avatar" default_icon_name="Generic_Person" visible="false"/>
+ <icon left="5" top="6" width="25" height="25" mouse_opaque="true" name="system_notification_icon_exp" tool_tip="Icon" image_name="System_Notification" visible="false"/>
+ <icon left="12" top="144" width="20" height="20" name="attachment_icon_exp" tool_tip="Attachment" image_name="Icon_Attachment_Large" follows="left" mouse_opaque="true" visible="false"/>
+ </layout_panel>
+ <layout_panel width="230" height="196" orientation="horizontal" follows="left|top|right|bottom" name="layout_panel_middle_exp">
+ <panel border="false" top="0" width="230" height="196" bevel_style="none" follows="left|top|right|bottom" layout="topleft" name="main_info_panel_expanded">
+ <layout_stack top="0" left="0" width="230" height="196" orientation="vertical" follows="left|top|right|bottom" name="main_info_panel_vertical_stack">
+ <layout_panel top="0" left="0" width="230" height="30" layout="topleft" follows="left|top|right|bottom" name="notification_title_layout_panel" visible="true">
+ <panel border="false" top="0" left="0" width="230" height="30" bevel_style="none" follows="left|top|right" layout="topleft" name="notification_title_panel_exp" >
+ <text allow_scroll="false" font="SansSerif" top="6" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="notification_title_exp">
+ Notice Title Notice Title N o t i c e T i t l e N o t i c e T i t l e
+ </text>
+ <text allow_scroll="false" font="SansSerif" left="0" width="233" height="10" layout="topleft" follows="right|left" text_color="White"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="group_name_exp" visible="false">
+ Group Name Group Name Group Na m e e
+ </text>
+ </panel>
+ <panel border="false" left="0" width="230" height="12" bevel_style="none" follows="left|top|right" layout="topleft" name="sender_time_panel_exp">
+ <text allow_scroll="false" font="SansSerifSmall" top="0" left="0" width="145" height="13" layout="topleft" follows="right|left"
+ use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box_exp" visible="false">
+ Sender: "Resident R e s i d e n t R e s i d e n t"
+ </text>
+ <text allow_scroll="false" font="SansSerifSmall" top="0" right="-1" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ name="notification_time_exp" value="2014/12/24 23:30" />
+ </panel>
+ <panel border="false" left="0" height="115" width="230" bevel_style="none" follows="left|top|right" layout="topleft" name="notification_text_panel_exp" visible="true">
+ <text_editor enabled="false" top="0" left="0" width="230" height="110" layout="topleft" follows="left|top|right|bottom"
+ word_wrap="true" max_length="65536" name="notification_text_exp" parse_urls="true">
+ Notice text goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </text_editor>
+ </panel>
+ <panel border="false" left="1" bottom="-5" width="230" height="22" bevel_style="none" follows="left|right|bottom" layout="topleft" name="attachment_panel" visible="false">
+ <text allow_scroll="false" font="SansSerifSmall" top="4" left="5" width="220" height="12" layout="topleft" follows="left|top|right|bottom"
+ use_ellipses="true" word_wrap="true" max_length="96" name="attachment_text">
+ Attachment goes here b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a b l a bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla. bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla .
+ </text>
+ </panel>
+ <panel border="false" left="0" bottom="-4" height="30" bevel_style="none" follows="left|right|bottom" layout="topleft" name="button_panel" visible="false">
+ <button top="2" left="0" width="65" height="23" layout="topleft" follows="left|top|bottom" name="join_btn" mouse_opaque="true" tab_stop="false" label = "Join"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="decline_btn" mouse_opaque="true" tab_stop="false" label = "Decline"/>
+ <button top="2" left_pad="12" width="65" height="23" layout="topleft" follows="left|top|bottom" name="info_btn" mouse_opaque="true" tab_stop="false" label = "Info"/>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ <layout_panel width="18" orientation="horizontal" follows="right|top|bottom" name="layout_panel_left_exp">
+ <panel top="0" left="0" width="17" follows="left|top|right|bottom" layout="topleft" name="close_expand_panel_exp">
+ <button top="0" left="2" width="17" height="17" layout="topleft" follows="top" name="close_expanded_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Icon_Close_Foreground" image_selected="Icon_Close_Press" />
+ <button bottom="5" left="0" width="17" height="17" layout="topleft" follows="bottom" name="condense_btn" mouse_opaque="true"
+ tab_stop="false" image_unselected="Notification_Condense" image_selected="Notification_Condense" />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
new file mode 100644
index 0000000000..150225af27
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/notification_list_view.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<notification_list_view
+ allow_select="false"
+ color="PanelFocusBackgroundColor"
+ item_pad="0"
+ keep_one_selected="false"
+ multi_select="false"
+ opaque="true">
+ <flat_list_view
+ color="FloaterDefaultBackgroundColor"
+ follows="all"
+ layout="topleft"
+ name="notification_list"
+ left="1"
+ top="20"
+ height="0"
+ width="318"/>
+</notification_list_view> \ No newline at end of file