summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/llbutton.cpp67
-rw-r--r--indra/llui/llfolderview.cpp5
-rw-r--r--indra/llui/llfolderview.h1
-rwxr-xr-xindra/llui/llfolderviewitem.cpp57
-rwxr-xr-xindra/llui/llfolderviewitem.h5
-rw-r--r--indra/llui/lllayoutstack.cpp6
-rw-r--r--indra/llui/lllayoutstack.h2
-rw-r--r--indra/llui/llmultifloater.cpp4
-rw-r--r--indra/llui/llnotifications.cpp5
-rw-r--r--indra/llui/llnotifications.h9
-rw-r--r--indra/llui/llnotificationslistener.cpp354
-rw-r--r--indra/llui/llnotificationslistener.h69
-rw-r--r--indra/llui/llnotificationtemplate.h1
-rw-r--r--indra/llui/llresizebar.cpp8
-rw-r--r--indra/llui/llresizebar.h2
-rw-r--r--indra/llui/llview.cpp21
-rwxr-xr-xindra/newview/CMakeLists.txt6
-rwxr-xr-xindra/newview/app_settings/settings.xml4
-rw-r--r--indra/newview/app_settings/settings_per_account.xml2
-rwxr-xr-xindra/newview/llagent.cpp72
-rw-r--r--indra/newview/llbrowsernotification.cpp5
-rw-r--r--indra/newview/llchannelmanager.cpp6
-rw-r--r--indra/newview/llchatbar.cpp44
-rw-r--r--indra/newview/llchiclet.cpp216
-rw-r--r--indra/newview/llchiclet.h208
-rw-r--r--indra/newview/llchicletbar.cpp3
-rw-r--r--indra/newview/llcommunicationchannel.cpp79
-rw-r--r--indra/newview/llcommunicationchannel.h61
-rw-r--r--indra/newview/llconversationlog.cpp67
-rw-r--r--indra/newview/llconversationmodel.cpp67
-rwxr-xr-xindra/newview/llconversationmodel.h2
-rwxr-xr-xindra/newview/llconversationview.cpp46
-rwxr-xr-xindra/newview/llconversationview.h7
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.cpp162
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.h57
-rw-r--r--indra/newview/llflexibleobject.cpp2
-rw-r--r--indra/newview/llfloaterconversationlog.cpp3
-rw-r--r--indra/newview/llfloaterimcontainer.cpp123
-rw-r--r--indra/newview/llfloaterimcontainer.h6
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp24
-rw-r--r--indra/newview/llfloaterimnearbychat.h4
-rw-r--r--indra/newview/llfloaterimsession.cpp42
-rw-r--r--indra/newview/llfloaterimsession.h7
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp162
-rw-r--r--indra/newview/llfloaterimsessiontab.h8
-rw-r--r--indra/newview/llfloateroutbox.cpp17
-rw-r--r--indra/newview/llhudobject.cpp2
-rw-r--r--indra/newview/llhudobject.h4
-rw-r--r--indra/newview/llimhandler.cpp2
-rw-r--r--indra/newview/llimview.cpp91
-rw-r--r--indra/newview/llnotificationalerthandler.cpp28
-rw-r--r--indra/newview/llnotificationgrouphandler.cpp2
-rw-r--r--indra/newview/llnotificationhandler.h142
-rw-r--r--indra/newview/llnotificationhandlerutil.cpp12
-rw-r--r--indra/newview/llnotificationhinthandler.cpp27
-rw-r--r--indra/newview/llnotificationofferhandler.cpp2
-rw-r--r--indra/newview/llnotificationscripthandler.cpp2
-rw-r--r--indra/newview/llnotificationstorage.cpp228
-rw-r--r--indra/newview/llnotificationstorage.h35
-rw-r--r--indra/newview/llnotificationtiphandler.cpp2
-rw-r--r--indra/newview/llpanelblockedlist.cpp1
-rw-r--r--indra/newview/llpersistentnotificationstorage.cpp145
-rw-r--r--indra/newview/llpersistentnotificationstorage.h63
-rw-r--r--indra/newview/llsyswellwindow.cpp15
-rw-r--r--indra/newview/llsyswellwindow.h7
-rw-r--r--indra/newview/llviewermenu.cpp15
-rwxr-xr-xindra/newview/llviewermessage.cpp11
-rwxr-xr-xindra/newview/llviewerwindow.cpp30
-rw-r--r--indra/newview/llviewerwindow.h8
-rwxr-xr-xindra/newview/llvoavatar.cpp16
-rw-r--r--indra/newview/llvoiceclient.cpp1
-rw-r--r--indra/newview/llvoicevisualizer.cpp32
-rw-r--r--indra/newview/llvoicevisualizer.h27
-rw-r--r--indra/newview/skins/default/colors.xml6
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Notices_Unread.pngbin0 -> 3693 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml2
-rw-r--r--indra/newview/skins/default/xui/da/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/de/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_conversation_log.xml161
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_container.xml39
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml26
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation.xml7
-rw-r--r--indra/newview/skins/default/xui/en/menu_im_conversation.xml94
-rw-r--r--indra/newview/skins/default/xui/en/menu_notification_well_button.xml16
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml53
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_chiclet_bar.xml44
-rw-r--r--indra/newview/skins/default/xui/en/widgets/toolbar.xml12
-rw-r--r--indra/newview/skins/default/xui/es/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/fr/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/it/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/pl/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/pt/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/ru/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/tr/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/default/xui/zh/menu_notification_well_button.xml4
98 files changed, 2250 insertions, 1345 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index ccc7aa8cec..9c961d67d6 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -71,7 +71,6 @@ set(llui_SOURCE_FILES
llmultislider.cpp
llmultisliderctrl.cpp
llnotifications.cpp
- llnotificationslistener.cpp
llnotificationsutil.cpp
llpanel.cpp
llprogressbar.cpp
@@ -181,7 +180,6 @@ set(llui_HEADER_FILES
llmultislider.h
llnotificationptr.h
llnotifications.h
- llnotificationslistener.h
llnotificationsutil.h
llnotificationtemplate.h
llnotificationvisibilityrule.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index f82cdc64a9..a8149a9a1d 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -613,30 +613,6 @@ void LLButton::draw()
static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);
F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
- bool flash = false;
- if (mFlashingTimer)
- {
- mFlashing = mFlashingTimer->isFlashingInProgress();
- flash = mFlashing && (!sEnableButtonFlashing || mFlashingTimer->isCurrentlyHighlighted());
- }
- else
- {
- if(mFlashing)
- {
- if ( sEnableButtonFlashing)
- {
- F32 elapsed = mFrameTimer.getElapsedTimeF32();
- S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f);
- // flash on or off?
- flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f);
- }
- else
- { // otherwise just highlight button in flash color
- flash = true;
- }
- }
- }
-
bool pressed_by_keyboard = FALSE;
if (hasFocus())
{
@@ -660,9 +636,21 @@ void LLButton::draw()
bool selected = getToggleState();
bool use_glow_effect = FALSE;
- LLColor4 glow_color = LLColor4::white;
+ LLColor4 highlighting_color = LLColor4::white;
+ LLColor4 glow_color;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
LLUIImage* imagep = NULL;
+
+ // Cancel sticking of color, if the button is pressed,
+ // or when a flashing of the previously selected button is ended
+ if (mFlashingTimer
+ && ((selected && !mFlashingTimer->isFlashingInProgress()) || pressed))
+ {
+ mFlashing = false;
+ }
+
+ bool flash = mFlashing && sEnableButtonFlashing;
+
if (pressed && mDisplayPressedState)
{
imagep = selected ? mImagePressedSelected : mImagePressed;
@@ -728,15 +716,20 @@ void LLButton::draw()
imagep = mImageFlash;
}
// else use usual flashing via flash_color
- else
+ else if (mFlashingTimer)
{
LLColor4 flash_color = mFlashBgColor.get();
use_glow_effect = TRUE;
glow_type = LLRender::BT_ALPHA; // blend the glow
- if (mNeedsHighlight) // highlighted AND flashing
- glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
- else
+
+ if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress())
+ {
glow_color = flash_color;
+ }
+ else if (mNeedsHighlight)
+ {
+ glow_color = highlighting_color;
+ }
}
}
@@ -785,8 +778,7 @@ void LLButton::draw()
if (use_glow_effect)
{
mCurGlowStrength = lerp(mCurGlowStrength,
- mFlashing ? (flash? 1.0 : 0.0)
- : mHoverGlowStrength,
+ mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.0 : 0.0) : mHoverGlowStrength,
LLCriticalDamp::getInterpolant(0.05f));
}
else
@@ -973,23 +965,18 @@ void LLButton::setToggleState(BOOL b)
{
setControlValue(b); // will fire LLControlVariable callbacks (if any)
setValue(b); // may or may not be redundant
+ setFlashing(false); // stop flash state whenever the selected/unselected state if reset
// Unselected label assignments
autoResize();
}
}
-void LLButton::setFlashing( bool b )
+void LLButton::setFlashing(bool b)
{
if (mFlashingTimer)
{
- if (b)
- {
- mFlashingTimer->startFlashing();
- }
- else
- {
- mFlashingTimer->stopFlashing();
- }
+ mFlashing = b;
+ (b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing());
}
else if (b != mFlashing)
{
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index a33ffc4240..7ae79d94fe 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -1913,14 +1913,15 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu)
// Successively filter out invalid options
- U32 flags = FIRST_SELECTED_ITEM;
+ U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0);
+ U32 flags = multi_select_flag | FIRST_SELECTED_ITEM;
for (selected_items_t::iterator item_itor = mSelectedItems.begin();
item_itor != mSelectedItems.end();
++item_itor)
{
LLFolderViewItem* selected_item = (*item_itor);
selected_item->buildContextMenu(*menu, flags);
- flags = 0x0;
+ flags = multi_select_flag;
}
addNoOptions(menu);
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index d4a1434c73..2ee7417240 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -400,5 +400,6 @@ public:
// Flags for buildContextMenu()
const U32 SUPPRESS_OPEN_ITEM = 0x1;
const U32 FIRST_SELECTED_ITEM = 0x2;
+const U32 ITEM_IN_MULTI_SELECTION = 0x4;
#endif // LL_LLFOLDERVIEW_H
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 0a06ce66aa..1281d6bd66 100755
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -50,6 +50,7 @@ std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts
bool LLFolderViewItem::sColorSetInitialized = false;
LLUIColor LLFolderViewItem::sFgColor;
LLUIColor LLFolderViewItem::sHighlightBgColor;
+LLUIColor LLFolderViewItem::sFlashBgColor;
LLUIColor LLFolderViewItem::sFocusOutlineColor;
LLUIColor LLFolderViewItem::sMouseOverColor;
LLUIColor LLFolderViewItem::sFilterBGColor;
@@ -151,6 +152,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
{
sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
+ sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
@@ -686,26 +688,31 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
return mIsCurSelection;
}
-void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &bgColor,
+void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor,
const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor)
{
-
- //--------------------------------------------------------------------------------//
- // Draw highlight for selected items
- //
-
const S32 focus_top = getRect().getHeight();
const S32 focus_bottom = getRect().getHeight() - mItemHeight;
const bool folder_open = (getRect().getHeight() > mItemHeight + 4);
const S32 FOCUS_LEFT = 1;
+
+ // Determine which background color to use for highlighting
+ LLUIColor bgColor = (isFlashing() ? flashColor : selectColor);
- if (isHighlightAllowed()) // always render "current" item (only render other selected items if
- // mShowSingleSelection is FALSE) or flashing item
+ //--------------------------------------------------------------------------------//
+ // Draw highlight for selected items
+ // Note: Always render "current" item or flashing item, only render other selected
+ // items if mShowSingleSelection is FALSE.
+ //
+ if (isHighlightAllowed())
+
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLColor4 bg_color = bgColor;
- if (!isHighlightActive())
+
+ // Highlight for selected but not current items
+ if (!isHighlightActive() && !isFlashing())
{
+ LLColor4 bg_color = bgColor;
// do time-based fade of extra objects
F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f);
if (getRoot() && getRoot()->getShowSingleSelection())
@@ -718,25 +725,30 @@ void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeybo
// fading in
bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]);
}
+ gl_rect_2d(FOCUS_LEFT,
+ focus_top,
+ getRect().getWidth() - 2,
+ focus_bottom,
+ bg_color, hasKeyboardFocus);
}
- if (isHighlightAllowed() || isHighlightActive())
+ // Highlight for currently selected or flashing item
+ if (isHighlightActive())
{
+ // Background
gl_rect_2d(FOCUS_LEFT,
focus_top,
getRect().getWidth() - 2,
focus_bottom,
- bg_color, hasKeyboardFocus);
- }
-
- if (isHighlightActive())
- {
+ bgColor, hasKeyboardFocus);
+ // Outline
gl_rect_2d(FOCUS_LEFT,
focus_top,
getRect().getWidth() - 2,
focus_bottom,
focusOutlineColor, FALSE);
}
+
if (folder_open)
{
gl_rect_2d(FOCUS_LEFT,
@@ -810,7 +822,7 @@ void LLFolderViewItem::draw()
drawOpenFolderArrow(default_params, sFgColor);
- drawHighlight(show_context, filled, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
+ drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
//--------------------------------------------------------------------------------//
// Draw open icon
@@ -1481,17 +1493,20 @@ void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection)
void LLFolderViewFolder::destroyView()
{
- std::for_each(mItems.begin(), mItems.end(), DeletePointer());
- mItems.clear();
+ while (!mItems.empty())
+ {
+ LLFolderViewItem *itemp = mItems.back();
+ itemp->destroyView(); // LLFolderViewItem::destroyView() removes entry from mItems
+ }
while (!mFolders.empty())
{
LLFolderViewFolder *folderp = mFolders.back();
- folderp->destroyView(); // removes entry from mFolders
+ folderp->destroyView(); // LLFolderVievFolder::destroyView() removes entry from mFolders
}
LLFolderViewItem::destroyView();
- }
+}
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index d7f5e86aea..ca31931e19 100755
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -128,6 +128,7 @@ protected:
static LLUIColor sFgColor;
static LLUIColor sFgDisabledColor;
static LLUIColor sHighlightBgColor;
+ static LLUIColor sFlashBgColor;
static LLUIColor sFocusOutlineColor;
static LLUIColor sMouseOverColor;
static LLUIColor sFilterBGColor;
@@ -141,6 +142,8 @@ protected:
virtual void addFolder(LLFolderViewFolder*) { }
virtual bool isHighlightAllowed();
virtual bool isHighlightActive();
+ virtual bool isFlashing() { return false; }
+ virtual void setFlashState(bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
@@ -269,7 +272,7 @@ public:
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color);
- void drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &bgColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor);
+ void drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor);
void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 0674275612..e642883991 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -32,7 +32,6 @@
#include "lllocalcliprect.h"
#include "llpanel.h"
-#include "llresizebar.h"
#include "llcriticaldamp.h"
#include "boost/foreach.hpp"
@@ -796,6 +795,11 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
}
else
{
+ if (new_auto_resize_headroom < 1.f)
+ {
+ new_auto_resize_headroom = 1.f;
+ }
+
F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)
/ new_auto_resize_headroom,
MIN_FRACTIONAL_SIZE,
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 883331c792..02c664f1a0 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -29,6 +29,7 @@
#define LL_LLLAYOUTSTACK_H
#include "llpanel.h"
+#include "llresizebar.h"
class LLLayoutPanel;
@@ -178,6 +179,7 @@ public:
F32 getAutoResizeFactor() const;
F32 getVisibleAmount() const;
S32 getVisibleDim() const;
+ LLResizeBar* getResizeBar() { return mResizeBar; }
bool isCollapsed() const { return mCollapsed;}
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
index 02ff64dbc6..179b251cdb 100644
--- a/indra/llui/llmultifloater.cpp
+++ b/indra/llui/llmultifloater.cpp
@@ -41,8 +41,8 @@ LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params)
mTabContainer(NULL),
mTabPos(LLTabContainer::TOP),
mAutoResize(TRUE),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
+ mOrigMinWidth(params.min_width),
+ mOrigMinHeight(params.min_height)
{
}
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 8fb7a9d864..89fb5ed30c 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -39,7 +39,6 @@
#include "lldir.h"
#include "llsdserialize.h"
#include "lltrans.h"
-#include "llnotificationslistener.h"
#include "llstring.h"
#include "llsdparam.h"
#include "llsdutil.h"
@@ -993,10 +992,12 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
bool abortProcessing = false;
if (passesFilter)
{
+ onFilterPass(pNotification);
abortProcessing = mPassedFilter(payload);
}
else
{
+ onFilterFail(pNotification);
abortProcessing = mFailedFilter(payload);
}
@@ -1168,8 +1169,6 @@ LLNotifications::LLNotifications()
mIgnoreAllNotifications(false)
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
-
- mListener.reset(new LLNotificationsListener(*this));
}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 372b9ce46f..42dee4c3e9 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -92,7 +92,6 @@
#include "llevents.h"
#include "llfunctorregistry.h"
#include "llinitparam.h"
-#include "llnotificationslistener.h"
#include "llnotificationptr.h"
#include "llpointer.h"
#include "llrefcount.h"
@@ -681,7 +680,6 @@ namespace LLNotificationComparators
};
typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
-typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
typedef std::set<LLNotificationPtr, LLNotificationComparators::orderByUUID> LLNotificationSet;
typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
@@ -776,6 +774,9 @@ protected:
virtual void onDelete(LLNotificationPtr p) {}
virtual void onChange(LLNotificationPtr p) {}
+ virtual void onFilterPass(LLNotificationPtr p) {}
+ virtual void onFilterFail(LLNotificationPtr p) {}
+
bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
LLNotificationFilter mFilter;
};
@@ -831,7 +832,6 @@ public:
private:
std::string mName;
std::string mParent;
- LLNotificationComparator mComparator;
};
// An interface class to provide a clean linker seam to the LLNotifications class.
@@ -951,7 +951,6 @@ private:
bool mIgnoreAllNotifications;
- boost::scoped_ptr<LLNotificationsListener> mListener;
std::vector<LLNotificationChannelPtr> mDefaultChannels;
};
@@ -1030,7 +1029,7 @@ protected:
// Stores only persistent notifications.
// Class users can use connectChanged() to process persistent notifications
-// (see LLNotificationStorage for example).
+// (see LLPersistentNotificationStorage for example).
class LLPersistentNotificationChannel : public LLNotificationChannel
{
LOG_CLASS(LLPersistentNotificationChannel);
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
deleted file mode 100644
index e4e127336b..0000000000
--- a/indra/llui/llnotificationslistener.cpp
+++ /dev/null
@@ -1,354 +0,0 @@
-/**
- * @file llnotificationslistener.cpp
- * @author Brad Kittenbrink
- * @date 2009-07-08
- * @brief Implementation for llnotificationslistener.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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 "linden_common.h"
-#include "llnotificationslistener.h"
-#include "llnotifications.h"
-#include "llnotificationtemplate.h"
-#include "llsd.h"
-#include "llui.h"
-
-LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
- LLEventAPI("LLNotifications",
- "LLNotifications listener to (e.g.) pop up a notification"),
- mNotifications(notifications)
-{
- add("requestAdd",
- "Add a notification with specified [\"name\"], [\"substitutions\"] and [\"payload\"].\n"
- "If optional [\"reply\"] specified, arrange to send user response on that LLEventPump.",
- &LLNotificationsListener::requestAdd);
- add("listChannels",
- "Post to [\"reply\"] a map of info on existing channels",
- &LLNotificationsListener::listChannels,
- LLSD().with("reply", LLSD()));
- add("listChannelNotifications",
- "Post to [\"reply\"] an array of info on notifications in channel [\"channel\"]",
- &LLNotificationsListener::listChannelNotifications,
- LLSD().with("reply", LLSD()).with("channel", LLSD()));
- add("respond",
- "Respond to notification [\"uuid\"] with data in [\"response\"]",
- &LLNotificationsListener::respond,
- LLSD().with("uuid", LLSD()));
- add("cancel",
- "Cancel notification [\"uuid\"]",
- &LLNotificationsListener::cancel,
- LLSD().with("uuid", LLSD()));
- add("ignore",
- "Ignore future notification [\"name\"]\n"
- "(from <notification name= > in notifications.xml)\n"
- "according to boolean [\"ignore\"].\n"
- "If [\"name\"] is omitted or undefined, [un]ignore all future notifications.\n"
- "Note that ignored notifications are not forwarded unless intercepted before\n"
- "the \"Ignore\" channel.",
- &LLNotificationsListener::ignore);
- add("forward",
- "Forward to [\"pump\"] future notifications on channel [\"channel\"]\n"
- "according to boolean [\"forward\"]. When enabled, only types matching\n"
- "[\"types\"] are forwarded, as follows:\n"
- "omitted or undefined: forward all notifications\n"
- "string: forward only the specific named [sig]type\n"
- "array of string: forward any notification matching any named [sig]type.\n"
- "When boolean [\"respond\"] is true, we auto-respond to each forwarded\n"
- "notification.",
- &LLNotificationsListener::forward,
- LLSD().with("channel", LLSD()));
-}
-
-// This is here in the .cpp file so we don't need the definition of class
-// Forwarder in the header file.
-LLNotificationsListener::~LLNotificationsListener()
-{
-}
-
-void LLNotificationsListener::requestAdd(const LLSD& event_data) const
-{
- if(event_data.has("reply"))
- {
- mNotifications.add(event_data["name"],
- event_data["substitutions"],
- event_data["payload"],
- boost::bind(&LLNotificationsListener::NotificationResponder,
- this,
- event_data["reply"].asString(),
- _1, _2
- )
- );
- }
- else
- {
- mNotifications.add(event_data["name"],
- event_data["substitutions"],
- event_data["payload"]);
- }
-}
-
-void LLNotificationsListener::NotificationResponder(const std::string& reply_pump,
- const LLSD& notification,
- const LLSD& response) const
-{
- LLSD reponse_event;
- reponse_event["notification"] = notification;
- reponse_event["response"] = response;
- LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
-}
-
-void LLNotificationsListener::listChannels(const LLSD& params) const
-{
- LLReqID reqID(params);
- LLSD response(reqID.makeResponse());
- for (LLNotificationChannel::instance_iter cmi(LLNotificationChannel::beginInstances()),
- cmend(LLNotificationChannel::endInstances());
- cmi != cmend; ++cmi)
- {
- LLSD channelInfo;
- //channelInfo["parent"] = cmi->second->getParentChannelName();
- response[cmi->getName()] = channelInfo;
- }
- LLEventPumps::instance().obtain(params["reply"]).post(response);
-}
-
-void LLNotificationsListener::listChannelNotifications(const LLSD& params) const
-{
- LLReqID reqID(params);
- LLSD response(reqID.makeResponse());
- LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"]));
- if (channel)
- {
- LLSD notifications(LLSD::emptyArray());
- for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end());
- ni != nend; ++ni)
- {
- notifications.append(asLLSD(*ni));
- }
- response["notifications"] = notifications;
- }
- LLEventPumps::instance().obtain(params["reply"]).post(response);
-}
-
-void LLNotificationsListener::respond(const LLSD& params) const
-{
- LLNotificationPtr notification(mNotifications.find(params["uuid"]));
- if (notification)
- {
- notification->respond(params["response"]);
- }
-}
-
-void LLNotificationsListener::cancel(const LLSD& params) const
-{
- LLNotificationPtr notification(mNotifications.find(params["uuid"]));
- if (notification)
- {
- mNotifications.cancel(notification);
- }
-}
-
-void LLNotificationsListener::ignore(const LLSD& params) const
-{
- // Calling a method named "ignore", but omitting its "ignore" Boolean
- // argument, should by default cause something to be ignored. Explicitly
- // pass ["ignore"] = false to cancel ignore.
- bool ignore = true;
- if (params.has("ignore"))
- {
- ignore = params["ignore"].asBoolean();
- }
- // This method can be used to affect either a single notification name or
- // all future notifications. The two use substantially different mechanisms.
- if (params["name"].isDefined())
- {
- // ["name"] was passed: ignore just that notification
- LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]);
- if (templatep)
- {
- templatep->mForm->setIgnored(ignore);
- }
- }
- else
- {
- // no ["name"]: ignore all future notifications
- mNotifications.setIgnoreAllNotifications(ignore);
- }
-}
-
-class LLNotificationsListener::Forwarder: public LLEventTrackable
-{
- LOG_CLASS(LLNotificationsListener::Forwarder);
-public:
- Forwarder(LLNotifications& llnotifications, const std::string& channel):
- mNotifications(llnotifications),
- mRespond(false)
- {
- // Connect to the specified channel on construction. Because
- // LLEventTrackable is a base, we should automatically disconnect when
- // destroyed.
- LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
- if (channelptr)
- {
- // Insert our processing as a "passed filter" listener. This way
- // we get to run before all the "changed" listeners, and we get to
- // swipe it (hide it from the other listeners) if desired.
- channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1));
- }
- }
-
- void setPumpName(const std::string& name) { mPumpName = name; }
- void setTypes(const LLSD& types) { mTypes = types; }
- void setRespond(bool respond) { mRespond = respond; }
-
-private:
- bool handle(const LLSD& notification) const;
- bool matchType(const LLSD& filter, const std::string& type) const;
-
- LLNotifications& mNotifications;
- std::string mPumpName;
- LLSD mTypes;
- bool mRespond;
-};
-
-void LLNotificationsListener::forward(const LLSD& params)
-{
- std::string channel(params["channel"]);
- // First decide whether we're supposed to start forwarding or stop it.
- // Default to true.
- bool forward = true;
- if (params.has("forward"))
- {
- forward = params["forward"].asBoolean();
- }
- if (! forward)
- {
- // This is a request to stop forwarding notifications on the specified
- // channel. The rest of the params don't matter.
- // Because mForwarders contains scoped_ptrs, erasing the map entry
- // DOES delete the heap Forwarder object. Because Forwarder derives
- // from LLEventTrackable, destroying it disconnects it from the
- // channel.
- mForwarders.erase(channel);
- return;
- }
- // From here on, we know we're being asked to start (or modify) forwarding
- // on the specified channel. Find or create an appropriate Forwarder.
- ForwarderMap::iterator
- entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first);
- if (! entry->second)
- {
- entry->second.reset(new Forwarder(mNotifications, channel));
- }
- // Now, whether this Forwarder is brand-new or not, update it with the new
- // request info.
- Forwarder& fwd(*entry->second);
- fwd.setPumpName(params["pump"]);
- fwd.setTypes(params["types"]);
- fwd.setRespond(params["respond"]);
-}
-
-bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const
-{
- LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL;
- if (notification["sigtype"].asString() == "delete")
- {
- LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL;
- // let other listeners see the "delete" operation
- return false;
- }
- LLNotificationPtr note(mNotifications.find(notification["id"]));
- if (! note)
- {
- LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL;
- return false;
- }
- if (! matchType(mTypes, note->getType()))
- {
- LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL;
- // We're not supposed to intercept this particular notification. Let
- // other listeners process it.
- return false;
- }
- LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL;
- // This is a notification we care about. Forward it through specified
- // LLEventPump.
- LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note));
- // Are we also being asked to auto-respond?
- if (mRespond)
- {
- LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL;
- note->respond(LLSD::emptyMap());
- // Did that succeed in removing the notification? Only cancel() if
- // it's still around -- otherwise we get an LL_ERRS crash!
- note = mNotifications.find(notification["id"]);
- if (note)
- {
- LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL;
- mNotifications.cancel(note);
- }
- }
- // If we've auto-responded to this notification, then it's going to be
- // deleted. Other listeners would get the change operation, try to look it
- // up and be baffled by lookup failure. So when we auto-respond, suppress
- // this notification: don't pass it to other listeners.
- return mRespond;
-}
-
-bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const
-{
- // Decide whether this notification matches filter:
- // undefined: forward all notifications
- if (filter.isUndefined())
- {
- return true;
- }
- // array of string: forward any notification matching any named type
- if (filter.isArray())
- {
- for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray());
- ti != tend; ++ti)
- {
- if (ti->asString() == type)
- {
- return true;
- }
- }
- // Didn't match any entry in the array
- return false;
- }
- // string: forward only the specific named type
- return (filter.asString() == type);
-}
-
-LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note)
-{
- LLSD notificationInfo(note->asLLSD());
- // For some reason the following aren't included in LLNotification::asLLSD().
- notificationInfo["summary"] = note->summarize();
- notificationInfo["id"] = note->id();
- notificationInfo["type"] = note->getType();
- notificationInfo["message"] = note->getMessage();
- notificationInfo["label"] = note->getLabel();
- return notificationInfo;
-}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
deleted file mode 100644
index f9f7641de6..0000000000
--- a/indra/llui/llnotificationslistener.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * @file llnotificationslistener.h
- * @author Brad Kittenbrink
- * @date 2009-07-08
- * @brief Wrap subset of LLNotifications API in event API for test scripts.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_LLNOTIFICATIONSLISTENER_H
-#define LL_LLNOTIFICATIONSLISTENER_H
-
-#include "lleventapi.h"
-#include "llnotificationptr.h"
-#include <boost/shared_ptr.hpp>
-#include <map>
-#include <string>
-
-class LLNotifications;
-class LLSD;
-
-class LLNotificationsListener : public LLEventAPI
-{
-public:
- LLNotificationsListener(LLNotifications & notifications);
- ~LLNotificationsListener();
-
-private:
- void requestAdd(LLSD const & event_data) const;
-
- void NotificationResponder(const std::string& replypump,
- const LLSD& notification,
- const LLSD& response) const;
-
- void listChannels(const LLSD& params) const;
- void listChannelNotifications(const LLSD& params) const;
- void respond(const LLSD& params) const;
- void cancel(const LLSD& params) const;
- void ignore(const LLSD& params) const;
- void forward(const LLSD& params);
-
- static LLSD asLLSD(LLNotificationPtr);
-
- class Forwarder;
- typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
- ForwarderMap mForwarders;
- LLNotifications & mNotifications;
-};
-
-#endif // LL_LLNOTIFICATIONSLISTENER_H
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
index 906b83a400..18a82190b5 100644
--- a/indra/llui/llnotificationtemplate.h
+++ b/indra/llui/llnotificationtemplate.h
@@ -49,7 +49,6 @@
//#include "llfunctorregistry.h"
//#include "llpointer.h"
#include "llinitparam.h"
-//#include "llnotificationslistener.h"
//#include "llnotificationptr.h"
//#include "llcachename.h"
#include "llnotifications.h"
diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp
index 87aeb4d7a7..4b9add820f 100644
--- a/indra/llui/llresizebar.cpp
+++ b/indra/llui/llresizebar.cpp
@@ -45,7 +45,8 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)
mSide( p.side ),
mSnappingEnabled(p.snapping_enabled),
mAllowDoubleClickSnapping(p.allow_double_click_snapping),
- mResizingView(p.resizing_view)
+ mResizingView(p.resizing_view),
+ mResizeListener(NULL)
{
setFollowsNone();
// set up some generically good follow code.
@@ -261,6 +262,11 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
}
}
+ if (mResizeListener)
+ {
+ mResizeListener(NULL);
+ }
+
return handled;
} // end LLResizeBar::handleHover
diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h
index 6daf191918..8190a95a71 100644
--- a/indra/llui/llresizebar.h
+++ b/indra/llui/llresizebar.h
@@ -71,6 +71,7 @@ public:
void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; }
void setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; }
bool canResize() { return getEnabled() && mMaxSize > mMinSize; }
+ void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;}
private:
S32 mDragLastScreenX;
@@ -84,6 +85,7 @@ private:
BOOL mSnappingEnabled;
BOOL mAllowDoubleClickSnapping;
LLView* mResizingView;
+ boost::function<void(void*)> mResizeListener;
};
#endif // LL_RESIZEBAR_H
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 5bcdae921d..3613a40e2c 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -55,6 +55,8 @@
#include "lltexteditor.h"
#include "lltextbox.h"
+static const S32 LINE_HEIGHT = 15;
+
S32 LLView::sDepth = 0;
bool LLView::sDebugRects = false;
bool LLView::sDebugRectsShowNames = true;
@@ -1203,11 +1205,24 @@ void LLView::drawDebugRect()
&& preview_iter == sPreviewHighlightedElements.end()
&& sDebugRectsShowNames)
{
- //char temp[256];
S32 x, y;
gGL.color4fv( border_color.mV );
- x = debug_rect.getWidth()/2;
- y = debug_rect.getHeight()/2;
+
+ x = debug_rect.getWidth() / 2;
+
+ S32 rect_height = debug_rect.getHeight();
+ S32 lines = rect_height / LINE_HEIGHT + 1;
+
+ S32 depth = 0;
+ LLView * viewp = this;
+ while (NULL != viewp)
+ {
+ viewp = viewp->getParent();
+ depth++;
+ }
+
+ y = rect_height - LINE_HEIGHT * (depth % lines + 1);
+
std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
debug_rect.getWidth(), debug_rect.getHeight());
LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c9176d71fb..d43f9e9988 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -137,6 +137,7 @@ set(viewer_SOURCE_FILES
llcommanddispatcherlistener.cpp
llcommandhandler.cpp
llcommandlineparser.cpp
+ llcommunicationchannel.cpp
llcompilequeue.cpp
llconfirmationmanager.cpp
llconversationlog.cpp
@@ -152,6 +153,7 @@ set(viewer_SOURCE_FILES
lldebugview.cpp
lldelayedgestureerror.cpp
lldirpicker.cpp
+ lldonotdisturbnotificationstorage.cpp
lldndbutton.cpp
lldrawable.cpp
lldrawpool.cpp
@@ -448,6 +450,7 @@ set(viewer_SOURCE_FILES
llpathfindingobject.cpp
llpathfindingobjectlist.cpp
llpathfindingpathtool.cpp
+ llpersistentnotificationstorage.cpp
llphysicsmotion.cpp
llphysicsshapebuilderutil.cpp
llplacesinventorybridge.cpp
@@ -722,6 +725,7 @@ set(viewer_HEADER_FILES
llcommanddispatcherlistener.h
llcommandhandler.h
llcommandlineparser.h
+ llcommunicationchannel.h
llcompilequeue.h
llconfirmationmanager.h
llconversationlog.h
@@ -737,6 +741,7 @@ set(viewer_HEADER_FILES
lldebugview.h
lldelayedgestureerror.h
lldirpicker.h
+ lldonotdisturbnotificationstorage.h
lldndbutton.h
lldrawable.h
lldrawpool.h
@@ -1021,6 +1026,7 @@ set(viewer_HEADER_FILES
llpathfindingobject.h
llpathfindingobjectlist.h
llpathfindingpathtool.h
+ llpersistentnotificationstorage.h
llphysicsmotion.h
llphysicsshapebuilderutil.h
llplacesinventorybridge.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 24fa0a0cd4..507eb33f2d 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4676,7 +4676,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
<key>LandBrushSize</key>
<map>
@@ -13173,7 +13173,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>0.25</real>
+ <real>0.5</real>
</map>
<key>WindLightUseAtmosShaders</key>
<map>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index ca22041671..4ff494fbfb 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -53,7 +53,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
- <integer>268</integer>
+ <integer>205</integer>
</map>
<key>ConversationsMessagePaneCollapsed</key>
<map>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 22a21ffaeb..fc3be9ca21 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -41,6 +41,7 @@
#include "llchannelmanager.h"
#include "llchicletbar.h"
#include "llconsole.h"
+#include "lldonotdisturbnotificationstorage.h"
#include "llenvmanager.h"
#include "llfirstuse.h"
#include "llfloatercamera.h"
@@ -1389,11 +1390,16 @@ BOOL LLAgent::getAFK() const
//-----------------------------------------------------------------------------
// setDoNotDisturb()
//-----------------------------------------------------------------------------
-void LLAgent::setDoNotDisturb(bool pIsDotNotDisturb)
+void LLAgent::setDoNotDisturb(bool pIsDoNotDisturb)
{
- mIsDoNotDisturb = pIsDotNotDisturb;
- sendAnimationRequest(ANIM_AGENT_DO_NOT_DISTURB, (pIsDotNotDisturb ? ANIM_REQUEST_START : ANIM_REQUEST_STOP));
- LLNotificationsUI::LLChannelManager::getInstance()->muteAllChannels(pIsDotNotDisturb);
+ bool isDoNotDisturbSwitchedOff = (mIsDoNotDisturb && !pIsDoNotDisturb);
+ mIsDoNotDisturb = pIsDoNotDisturb;
+ sendAnimationRequest(ANIM_AGENT_DO_NOT_DISTURB, (pIsDoNotDisturb ? ANIM_REQUEST_START : ANIM_REQUEST_STOP));
+ LLNotificationsUI::LLChannelManager::getInstance()->muteAllChannels(pIsDoNotDisturb);
+ if (isDoNotDisturbSwitchedOff)
+ {
+ LLDoNotDisturbNotificationStorage::getInstance()->loadNotifications();
+ }
}
//-----------------------------------------------------------------------------
@@ -2541,51 +2547,21 @@ void LLMaturityPreferencesResponder::error(U32 pStatus, const std::string& pReas
U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent)
{
- // stinson 05/24/2012 Pathfinding regions have re-defined the response behavior. In the old server code,
- // if you attempted to change the preferred maturity to the same value, the response content would be an
- // undefined LLSD block. In the new server code with pathfinding, the response content should always be
- // defined. Thus, the check for isUndefined() can be replaced with an assert after pathfinding is merged
- // into server trunk and fully deployed.
U8 maturity = SIM_ACCESS_MIN;
- if (pContent.isUndefined())
- {
- maturity = mPreferredMaturity;
- }
- else
- {
- llassert(!pContent.isUndefined());
- llassert(pContent.isMap());
-
- if (!pContent.isUndefined() && pContent.isMap())
- {
- // stinson 05/24/2012 Pathfinding regions have re-defined the response syntax. The if statement catches
- // the new syntax, and the else statement catches the old syntax. After pathfinding is merged into
- // server trunk and fully deployed, we can remove the else statement.
- if (pContent.has("access_prefs"))
- {
- llassert(pContent.has("access_prefs"));
- llassert(pContent.get("access_prefs").isMap());
- llassert(pContent.get("access_prefs").has("max"));
- llassert(pContent.get("access_prefs").get("max").isString());
- if (pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") &&
- pContent.get("access_prefs").get("max").isString())
- {
- LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString();
- LLStringUtil::trim(actualPreference);
- maturity = LLViewerRegion::shortStringToAccess(actualPreference);
- }
- }
- else if (pContent.has("max"))
- {
- llassert(pContent.get("max").isString());
- if (pContent.get("max").isString())
- {
- LLSD::String actualPreference = pContent.get("max").asString();
- LLStringUtil::trim(actualPreference);
- maturity = LLViewerRegion::shortStringToAccess(actualPreference);
- }
- }
- }
+
+ llassert(!pContent.isUndefined());
+ llassert(pContent.isMap());
+ llassert(pContent.has("access_prefs"));
+ llassert(pContent.get("access_prefs").isMap());
+ llassert(pContent.get("access_prefs").has("max"));
+ llassert(pContent.get("access_prefs").get("max").isString());
+ if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs")
+ && pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max")
+ && pContent.get("access_prefs").get("max").isString())
+ {
+ LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString();
+ LLStringUtil::trim(actualPreference);
+ maturity = LLViewerRegion::shortStringToAccess(actualPreference);
}
return maturity;
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index 9e608d2c8b..19747757db 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -35,6 +35,11 @@
using namespace LLNotificationsUI;
+LLBrowserNotification::LLBrowserNotification()
+ : LLSystemNotificationHandler("Browser", "browser")
+{
+}
+
bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification)
{
LLUUID media_id = notification->getPayload()["media_id"].asUUID();
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 987651fc80..43757d0174 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -29,7 +29,8 @@
#include "llchannelmanager.h"
#include "llappviewer.h"
-#include "llnotificationstorage.h"
+#include "lldonotdisturbnotificationstorage.h"
+#include "llpersistentnotificationstorage.h"
#include "llviewercontrol.h"
#include "llviewerwindow.h"
#include "llrootview.h"
@@ -138,6 +139,9 @@ void LLChannelManager::onLoginCompleted()
}
LLPersistentNotificationStorage::getInstance()->loadNotifications();
+
+ LLDoNotDisturbNotificationStorage::getInstance()->initialize();
+ LLDoNotDisturbNotificationStorage::getInstance()->loadNotifications();
}
//--------------------------------------------------------------------------
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 27138e6c06..7d0331757b 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -669,47 +669,3 @@ void LLChatBar::onCommitGesture(LLUICtrl* ctrl)
mGestureCombo->setFocus(FALSE);
}
}
-
-
-/* Cruft - global gChatHandler declared below has been commented out,
- so this class is never used. See similar code in llfloaterimnearbychatbar.cpp
-class LLChatHandler : public LLCommandHandler
-{
-public:
- // not allowed from outside the app
- LLChatHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { }
-
- // Your code here
- bool handle(const LLSD& tokens, const LLSD& query_map,
- LLMediaCtrl* web)
- {
- bool retval = false;
- // Need at least 2 tokens to have a valid message.
- if (tokens.size() < 2)
- {
- retval = false;
- }
- else
- {
- S32 channel = tokens[0].asInteger();
- // VWR-19499 Restrict function to chat channels greater than 0.
- if ((channel > 0) && (channel < CHAT_CHANNEL_DEBUG))
- {
- retval = true;
- // Say mesg on channel
- std::string mesg = tokens[1].asString();
- send_chat_from_viewer(mesg, CHAT_TYPE_NORMAL, channel);
- }
- else
- {
- retval = false;
- // Tell us this is an unsupported SLurl.
- }
- }
- return retval;
- }
-};
-
-// Creating the object registers with the dispatcher.
-//LLChatHandler gChatHandler;
-cruft */
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 1acbdd32b7..3dbb43c657 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -27,15 +27,17 @@
#include "llviewerprecompiledheaders.h" // must be first include
#include "llchiclet.h"
+#include "llchicletbar.h"
#include "llfloaterimsession.h"
#include "llfloaterimcontainer.h"
#include "llfloaterreg.h"
#include "lllocalcliprect.h"
-#include "llnotifications.h"
#include "llscriptfloater.h"
#include "llsingleton.h"
+#include "llsyswellwindow.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
+static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");
static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer");
@@ -46,6 +48,195 @@ boost::signals2::signal<LLChiclet* (const LLUUID&),
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+LLSysWellChiclet::Params::Params()
+ : button("button")
+ , unread_notifications("unread_notifications")
+ , max_displayed_count("max_displayed_count", 99)
+{
+ button.name = "button";
+ button.tab_stop = FALSE;
+ button.label = LLStringUtil::null;
+}
+
+LLSysWellChiclet::LLSysWellChiclet(const Params& p)
+ : LLChiclet(p)
+ , mButton(NULL)
+ , mCounter(0)
+ , mMaxDisplayedCount(p.max_displayed_count)
+ , mIsNewMessagesState(false)
+ , mFlashToLitTimer(NULL)
+ , mContextMenu(NULL)
+{
+ LLButton::Params button_params = p.button;
+ mButton = LLUICtrlFactory::create<LLButton>(button_params);
+ addChild(mButton);
+
+ mFlashToLitTimer = new LLFlashTimer(boost::bind(&LLSysWellChiclet::changeLitState, this, _1));
+}
+
+LLSysWellChiclet::~LLSysWellChiclet()
+{
+ mFlashToLitTimer->unset();
+}
+
+void LLSysWellChiclet::setCounter(S32 counter)
+{
+ // do nothing if the same counter is coming. EXT-3678.
+ if (counter == mCounter) return;
+
+ // note same code in LLChicletNotificationCounterCtrl::setCounter(S32 counter)
+ std::string s_count;
+ if(counter != 0)
+ {
+ static std::string more_messages_exist("+");
+ std::string more_messages(counter > mMaxDisplayedCount ? more_messages_exist : "");
+ s_count = llformat("%d%s"
+ , llmin(counter, mMaxDisplayedCount)
+ , more_messages.c_str()
+ );
+ }
+
+ mButton->setLabel(s_count);
+
+ mCounter = counter;
+}
+
+boost::signals2::connection LLSysWellChiclet::setClickCallback(
+ const commit_callback_t& cb)
+{
+ return mButton->setClickedCallback(cb);
+}
+
+void LLSysWellChiclet::setToggleState(BOOL toggled) {
+ mButton->setToggleState(toggled);
+}
+
+void LLSysWellChiclet::changeLitState(bool blink)
+{
+ setNewMessagesState(!mIsNewMessagesState);
+}
+
+void LLSysWellChiclet::setNewMessagesState(bool new_messages)
+{
+ /*
+ Emulate 4 states of button by background images, see detains in EXT-3147
+ xml attribute Description
+ image_unselected "Unlit" - there are no new messages
+ image_selected "Unlit" + "Selected" - there are no new messages and the Well is open
+ image_pressed "Lit" - there are new messages
+ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well is open
+ */
+ mButton->setForcePressedState(new_messages);
+
+ mIsNewMessagesState = new_messages;
+}
+
+void LLSysWellChiclet::updateWidget(bool is_window_empty)
+{
+ mButton->setEnabled(!is_window_empty);
+
+ if (LLChicletBar::instanceExists())
+ {
+ LLChicletBar::getInstance()->showWellButton(getName(), !is_window_empty);
+ }
+}
+// virtual
+BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ if(!mContextMenu)
+ {
+ createMenu();
+ }
+ if (mContextMenu)
+ {
+ mContextMenu->show(x, y);
+ LLMenuGL::showPopup(this, mContextMenu, x, y);
+ }
+ return TRUE;
+}
+
+/************************************************************************/
+/* LLNotificationChiclet implementation */
+/************************************************************************/
+LLNotificationChiclet::LLNotificationChiclet(const Params& p)
+: LLSysWellChiclet(p),
+ mUreadSystemNotifications(0)
+{
+ mNotificationChannel.reset(new ChicletNotificationChannel(this));
+ // ensure that notification well window exists, to synchronously
+ // handle toast add/delete events.
+ LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
+}
+
+void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string action = user_data.asString();
+ if("close all" == action)
+ {
+ LLNotificationWellWindow::getInstance()->closeAll();
+ }
+}
+
+bool LLNotificationChiclet::enableMenuItem(const LLSD& user_data)
+{
+ std::string item = user_data.asString();
+ if (item == "can close all")
+ {
+ return mUreadSystemNotifications != 0;
+ }
+ return true;
+}
+
+void LLNotificationChiclet::createMenu()
+{
+ if(mContextMenu)
+ {
+ llwarns << "Menu already exists" << llendl;
+ return;
+ }
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("NotificationWellChicletMenu.Action",
+ boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2));
+
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ enable_registrar.add("NotificationWellChicletMenu.EnableItem",
+ boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2));
+
+ mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
+ ("menu_notification_well_button.xml",
+ LLMenuGL::sMenuContainer,
+ LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
+/*virtual*/
+void LLNotificationChiclet::setCounter(S32 counter)
+{
+ LLSysWellChiclet::setCounter(counter);
+ updateWidget(getCounter() == 0);
+
+}
+
+bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
+{
+ if (notification->getName() == "ScriptDialog")
+ {
+ return false;
+ }
+
+ if( !(notification->canLogToIM() && notification->hasFormElements())
+ && (!notification->getPayload().has("give_inventory_notification")
+ || notification->getPayload()["give_inventory_notification"]))
+ {
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
LLChiclet::Params::Params()
: show_counter("show_counter", true)
, enable_counter("enable_counter", false)
@@ -57,12 +248,6 @@ LLChiclet::LLChiclet(const Params& p)
, mSessionId(LLUUID::null)
, mShowCounter(p.show_counter)
{
-
-}
-
-LLChiclet::~LLChiclet()
-{
-
}
boost::signals2::connection LLChiclet::setLeftButtonClickCallback(
@@ -125,6 +310,15 @@ BOOL LLIMChiclet::postBuild()
return TRUE;
}
+void LLIMChiclet::enableCounterControl(bool enable)
+{
+ mCounterEnabled = enable;
+ if(!enable)
+ {
+ LLChiclet::setShowCounter(false);
+ }
+}
+
void LLIMChiclet::setRequiredWidth()
{
S32 required_width = mDefaultWidth;
@@ -791,13 +985,19 @@ bool LLChicletPanel::isAnyIMFloaterDoked()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+LLChicletNotificationCounterCtrl::Params::Params()
+ : max_displayed_count("max_displayed_count", 99)
+{
+}
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
LLChicletAvatarIconCtrl::LLChicletAvatarIconCtrl(const Params& p)
: LLAvatarIconCtrl(p)
{
}
-
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index bd6c1a3e71..efaf03384a 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -29,11 +29,71 @@
#include "llavatariconctrl.h"
#include "llbutton.h"
+#include "llnotifications.h"
+#include "lltextbox.h"
class LLMenuGL;
class LLFloaterIMSession;
/**
+ * Class for displaying amount of messages/notifications(unread).
+ */
+class LLChicletNotificationCounterCtrl : public LLTextBox
+{
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLTextBox::Params>
+ {
+ /**
+ * Contains maximum displayed count of unread messages. Default value is 9.
+ *
+ * If count is less than "max_unread_count" will be displayed as is.
+ * Otherwise 9+ will be shown (for default value).
+ */
+ Optional<S32> max_displayed_count;
+
+ Params();
+ };
+
+ /**
+ * Sets number of notifications
+ */
+ virtual void setCounter(S32 counter);
+
+ /**
+ * Returns number of notifications
+ */
+ virtual S32 getCounter() const { return mCounter; }
+
+ /**
+ * Returns width, required to display amount of notifications in text form.
+ * Width is the only valid value.
+ */
+ /*virtual*/ LLRect getRequiredRect();
+
+ /**
+ * Sets number of notifications using LLSD
+ */
+ /*virtual*/ void setValue(const LLSD& value);
+
+ /**
+ * Returns number of notifications wrapped in LLSD
+ */
+ /*virtual*/ LLSD getValue() const;
+
+protected:
+
+ LLChicletNotificationCounterCtrl(const Params& p);
+ friend class LLUICtrlFactory;
+
+private:
+
+ S32 mCounter;
+ S32 mInitialWidth;
+ S32 mMaxDisplayedCount;
+};
+
+/**
* Class for displaying avatar's icon in P2P chiclet.
*/
class LLChicletAvatarIconCtrl : public LLAvatarIconCtrl
@@ -104,7 +164,7 @@ public:
Params();
};
- /*virtual*/ ~LLChiclet();
+ virtual ~LLChiclet() {}
/**
* Associates chat session id with chiclet.
@@ -117,6 +177,11 @@ public:
virtual const LLUUID& getSessionId() const { return mSessionId; }
/**
+ * Sets show counter state.
+ */
+ virtual void setShowCounter(bool show) { mShowCounter = show; }
+
+ /**
* Connects chiclet clicked event with callback.
*/
/*virtual*/ boost::signals2::connection setLeftButtonClickCallback(
@@ -195,6 +260,22 @@ public:
BOOL postBuild();
/**
+ * Sets IM session name. This name will be displayed in chiclet tooltip.
+ */
+ virtual void setIMSessionName(const std::string& name) { setToolTip(name); }
+
+ /**
+ * Sets id of person/group user is chatting with.
+ * Session id should be set before calling this
+ */
+ virtual void setOtherParticipantId(const LLUUID& other_participant_id) { mOtherParticipantId = other_participant_id; }
+
+ /**
+ * Enables/disables the counter control for a chiclet.
+ */
+ virtual void enableCounterControl(bool enable);
+
+ /**
* Sets required width for a chiclet according to visible controls.
*/
virtual void setRequiredWidth();
@@ -367,6 +448,131 @@ private:
};
/**
+ * Implements notification chiclet. Used to display total amount of unread messages
+ * across all IM sessions, total amount of system notifications. See EXT-3147 for details
+ */
+class LLSysWellChiclet : public LLChiclet
+{
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLChiclet::Params>
+ {
+ Optional<LLButton::Params> button;
+
+ Optional<LLChicletNotificationCounterCtrl::Params> unread_notifications;
+
+ /**
+ * Contains maximum displayed count of unread messages. Default value is 9.
+ *
+ * If count is less than "max_unread_count" will be displayed as is.
+ * Otherwise 9+ will be shown (for default value).
+ */
+ Optional<S32> max_displayed_count;
+
+ Params();
+ };
+
+ /*virtual*/ void setCounter(S32 counter);
+
+ // *TODO: mantipov: seems getCounter is not necessary for LLNotificationChiclet
+ // but inherited interface requires it to implement.
+ // Probably it can be safe removed.
+ /*virtual*/S32 getCounter() { return mCounter; }
+
+ boost::signals2::connection setClickCallback(const commit_callback_t& cb);
+
+ /*virtual*/ ~LLSysWellChiclet();
+
+ void setToggleState(BOOL toggled);
+
+ void setNewMessagesState(bool new_messages);
+ //this method should change a widget according to state of the SysWellWindow
+ virtual void updateWidget(bool is_window_empty);
+
+protected:
+
+ LLSysWellChiclet(const Params& p);
+ friend class LLUICtrlFactory;
+
+ /**
+ * Change Well 'Lit' state from 'Lit' to 'Unlit' and vice-versa.
+ *
+ * There is an assumption that it will be called 2*N times to do not change its start state.
+ * @see FlashToLitTimer
+ */
+ void changeLitState(bool blink);
+
+ /**
+ * Displays menu.
+ */
+ virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+
+ virtual void createMenu() = 0;
+
+protected:
+ class FlashToLitTimer;
+ LLButton* mButton;
+ S32 mCounter;
+ S32 mMaxDisplayedCount;
+ bool mIsNewMessagesState;
+
+ LLFlashTimer* mFlashToLitTimer;
+ LLContextMenu* mContextMenu;
+};
+
+class LLNotificationChiclet : public LLSysWellChiclet
+{
+ LOG_CLASS(LLNotificationChiclet);
+
+ friend class LLUICtrlFactory;
+public:
+ struct Params : public LLInitParam::Block<Params, LLSysWellChiclet::Params>{};
+
+protected:
+ struct ChicletNotificationChannel : public LLNotificationChannel
+ {
+ ChicletNotificationChannel(LLNotificationChiclet* chiclet)
+ : LLNotificationChannel(LLNotificationChannel::Params().filter(filterNotification).name(chiclet->getSessionId().asString()))
+ , mChiclet(chiclet)
+ {
+ // connect counter handlers to the signals
+ connectToChannel("Group Notifications");
+ connectToChannel("Offer");
+ connectToChannel("Notifications");
+ }
+
+ static bool filterNotification(LLNotificationPtr notify);
+ // connect counter updaters to the corresponding signals
+ /*virtual*/ void onAdd(LLNotificationPtr p) { mChiclet->setCounter(++mChiclet->mUreadSystemNotifications); }
+ /*virtual*/ void onDelete(LLNotificationPtr p) { mChiclet->setCounter(--mChiclet->mUreadSystemNotifications); }
+
+ LLNotificationChiclet* const mChiclet;
+ };
+
+ boost::scoped_ptr<ChicletNotificationChannel> mNotificationChannel;
+
+ LLNotificationChiclet(const Params& p);
+
+ /**
+ * Processes clicks on chiclet menu.
+ */
+ void onMenuItemClicked(const LLSD& user_data);
+
+ /**
+ * Enables chiclet menu items.
+ */
+ bool enableMenuItem(const LLSD& user_data);
+
+ /**
+ * Creates menu.
+ */
+ /*virtual*/ void createMenu();
+
+ /*virtual*/ void setCounter(S32 counter);
+ S32 mUreadSystemNotifications;
+};
+
+/**
* Storage class for all IM chiclets. Provides mechanism to display,
* scroll, create, remove chiclets.
*/
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index fde7764129..a51c844775 100644
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -30,6 +30,7 @@
#include "llchiclet.h"
#include "lllayoutstack.h"
#include "llpaneltopinfobar.h"
+#include "llsyswellwindow.h"
namespace
{
@@ -58,6 +59,8 @@ BOOL LLChicletBar::postBuild()
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
+ showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+
LLPanelTopInfoBar::instance().setResizeCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
LLPanelTopInfoBar::instance().setVisibleCallback(boost::bind(&LLChicletBar::fitWithTopInfoBar, this));
diff --git a/indra/newview/llcommunicationchannel.cpp b/indra/newview/llcommunicationchannel.cpp
new file mode 100644
index 0000000000..4b0a70ffd8
--- /dev/null
+++ b/indra/newview/llcommunicationchannel.cpp
@@ -0,0 +1,79 @@
+/**
+* @file llcommunicationchannel.cpp
+* @brief Implementation of llcommunicationchannel
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 "llcommunicationchannel.h"
+
+#include <string>
+#include <map>
+
+#include "llagent.h"
+#include "lldate.h"
+#include "llnotifications.h"
+
+
+LLCommunicationChannel::LLCommunicationChannel(const std::string& pName, const std::string& pParentName)
+ : LLNotificationChannel(pName, pParentName, filterByDoNotDisturbStatus)
+ , mHistory()
+{
+}
+
+LLCommunicationChannel::~LLCommunicationChannel()
+{
+}
+
+bool LLCommunicationChannel::filterByDoNotDisturbStatus(LLNotificationPtr)
+{
+ return !gAgent.isDoNotDisturb();
+}
+
+LLCommunicationChannel::history_list_t::const_iterator LLCommunicationChannel::beginHistory() const
+{
+ return mHistory.begin();
+}
+
+LLCommunicationChannel::history_list_t::const_iterator LLCommunicationChannel::endHistory() const
+{
+ return mHistory.end();
+}
+
+void LLCommunicationChannel::clearHistory()
+{
+ mHistory.clear();
+}
+
+void LLCommunicationChannel::onFilterFail(LLNotificationPtr pNotificationPtr)
+{
+ std::string notificationType = pNotificationPtr->getType();
+ if ((notificationType == "groupnotify")
+ || (notificationType == "offer")
+ || (notificationType == "notifytoast"))
+ {
+ mHistory.insert(std::make_pair<LLDate, LLNotificationPtr>(pNotificationPtr->getDate(), pNotificationPtr));
+ }
+}
diff --git a/indra/newview/llcommunicationchannel.h b/indra/newview/llcommunicationchannel.h
new file mode 100644
index 0000000000..0e15e1cd15
--- /dev/null
+++ b/indra/newview/llcommunicationchannel.h
@@ -0,0 +1,61 @@
+/**
+* @file llcommunicationchannel.h
+* @brief Header file for llcommunicationchannel
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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_LLCOMMUNICATIONCHANNEL_H
+#define LL_LLCOMMUNICATIONCHANNEL_H
+
+#include <string>
+#include <map>
+
+#include "lldate.h"
+#include "llerror.h"
+#include "llnotifications.h"
+
+class LLCommunicationChannel : public LLNotificationChannel
+{
+ LOG_CLASS(LLCommunicationChannel);
+public:
+ LLCommunicationChannel(const std::string& pName, const std::string& pParentName);
+ virtual ~LLCommunicationChannel();
+
+ static bool filterByDoNotDisturbStatus(LLNotificationPtr);
+
+ typedef std::multimap<LLDate, LLNotificationPtr> history_list_t;
+ history_list_t::const_iterator beginHistory() const;
+ history_list_t::const_iterator endHistory() const;
+
+ void clearHistory();
+
+protected:
+ virtual void onFilterFail(LLNotificationPtr pNotificationPtr);
+
+private:
+
+ history_list_t mHistory;
+};
+
+#endif // LL_LLCOMMUNICATIONCHANNEL_H
+
diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp
index 3b75cd8203..ff1f819d7d 100644
--- a/indra/newview/llconversationlog.cpp
+++ b/indra/newview/llconversationlog.cpp
@@ -188,15 +188,23 @@ void LLConversationLogFriendObserver::changed(U32 mask)
LLConversationLog::LLConversationLog() :
mAvatarNameCacheConnection()
{
- LLControlVariable* ctrl = gSavedPerAccountSettings.getControl("LogInstantMessages").get();
- if (ctrl)
+ LLControlVariable* log_instant_message = gSavedPerAccountSettings.getControl("LogInstantMessages").get();
+ LLControlVariable* keep_convers_log = gSavedSettings.getControl("KeepConversationLogTranscripts").get();
+ bool is_log_message = false;
+ bool is_keep_log = false;
+
+ if (log_instant_message)
{
- ctrl->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2));
- if (ctrl->getValue().asBoolean())
- {
- enableLogging(true);
- }
+ log_instant_message->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2));
+ is_log_message = log_instant_message->getValue().asBoolean();
}
+ if (keep_convers_log)
+ {
+ keep_convers_log->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2));
+ is_keep_log = keep_convers_log->getValue().asBoolean();
+ }
+
+ enableLogging(is_log_message && is_keep_log);
}
void LLConversationLog::enableLogging(bool enable)
@@ -229,17 +237,20 @@ void LLConversationLog::logConversation(const LLUUID& session_id, BOOL has_offli
const LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
LLConversation* conversation = findConversation(session);
- if (session && conversation)
+ if (session)
{
- if(has_offline_msg)
+ if (conversation)
{
- updateOfflineIMs(session, has_offline_msg);
+ if(has_offline_msg)
+ {
+ updateOfflineIMs(session, has_offline_msg);
+ }
+ updateConversationTimestamp(conversation);
+ }
+ else
+ {
+ createConversation(session);
}
- updateConversationTimestamp(conversation);
- }
- else if (session && !conversation)
- {
- createConversation(session);
}
}
@@ -304,19 +315,17 @@ void LLConversationLog::updateConversationTimestamp(LLConversation* conversation
LLConversation* LLConversationLog::findConversation(const LLIMModel::LLIMSession* session)
{
- if (!session)
+ if (session)
{
- return NULL;
- }
+ const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgouigAdHocHash() : session->mSessionID;
- const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgouigAdHocHash() : session->mSessionID;
-
- conversations_vec_t::iterator conv_it = mConversations.begin();
- for(; conv_it != mConversations.end(); ++conv_it)
- {
- if (conv_it->getSessionID() == session_id)
+ conversations_vec_t::iterator conv_it = mConversations.begin();
+ for(; conv_it != mConversations.end(); ++conv_it)
{
- return &*conv_it;
+ if (conv_it->getSessionID() == session_id)
+ {
+ return &*conv_it;
+ }
}
}
@@ -408,8 +417,8 @@ bool LLConversationLog::saveToFile(const std::string& filename)
// [1343221177] 0 1 0 John Doe| 7e4ec5be-783f-49f5-71dz-16c58c64c145 4ec62a74-c246-0d25-2af6-846beac2aa55 john.doe|
// [1343222639] 2 0 0 Ad-hoc Conference| c3g67c89-c479-4c97-b21d-32869bcfe8rc 68f1c33e-4135-3e3e-a897-8c9b23115c09 Ad-hoc Conference hash597394a0-9982-766d-27b8-c75560213b9a|
- fprintf(fp, "[%d] %d %d %d %s| %s %s %s|\n",
- (S32)conv_it->getTime(),
+ fprintf(fp, "[%lld] %d %d %d %s| %s %s %s|\n",
+ (S64)conv_it->getTime(),
(S32)conv_it->getConversationType(),
(S32)0,
(S32)conv_it->hasOfflineMessages(),
@@ -443,7 +452,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename)
char history_file_name[MAX_STRING];
int has_offline_ims;
int stype;
- S32 time;
+ time_t time;
// before CHUI-348 it was a flag of conversation voice state
int prereserved_unused;
@@ -453,7 +462,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename)
part_id_buffer[0] = '\0';
conv_id_buffer[0] = '\0';
- sscanf(buffer, "[%d] %d %d %d %[^|]| %s %s %[^|]|",
+ sscanf(buffer, "[%ld] %d %d %d %[^|]| %s %s %[^|]|",
&time,
&stype,
&prereserved_unused,
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index bc5b72e029..0243fb1c97 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -102,35 +102,44 @@ void LLConversationItem::showProperties(void)
{
}
-void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items)
-{
- items.push_back(std::string("view_profile"));
- items.push_back(std::string("im"));
- items.push_back(std::string("offer_teleport"));
- items.push_back(std::string("voice_call"));
- items.push_back(std::string("chat_history"));
- items.push_back(std::string("separator_chat_history"));
- items.push_back(std::string("add_friend"));
- items.push_back(std::string("remove_friend"));
- items.push_back(std::string("invite_to_group"));
- items.push_back(std::string("separator_invite_to_group"));
- items.push_back(std::string("map"));
- items.push_back(std::string("share"));
- items.push_back(std::string("pay"));
- items.push_back(std::string("block_unblock"));
- items.push_back(std::string("MuteText"));
-
- if(this->getType() != CONV_SESSION_1_ON_1 && mDisplayModeratorOptions)
+void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32 flags)
+{
+ if (flags & ITEM_IN_MULTI_SELECTION)
{
- items.push_back(std::string("Moderator Options Separator"));
- items.push_back(std::string("Moderator Options"));
- items.push_back(std::string("AllowTextChat"));
- items.push_back(std::string("moderate_voice_separator"));
- items.push_back(std::string("ModerateVoiceToggleMuteSelected"));
- items.push_back(std::string("ModerateVoiceMute"));
- items.push_back(std::string("ModerateVoiceUnmute"));
+ items.push_back(std::string("im"));
+ items.push_back(std::string("offer_teleport"));
+ items.push_back(std::string("voice_call"));
+ items.push_back(std::string("remove_friends"));
+ }
+ else
+ {
+ items.push_back(std::string("view_profile"));
+ items.push_back(std::string("im"));
+ items.push_back(std::string("offer_teleport"));
+ items.push_back(std::string("voice_call"));
+ items.push_back(std::string("chat_history"));
+ items.push_back(std::string("separator_chat_history"));
+ items.push_back(std::string("add_friend"));
+ items.push_back(std::string("remove_friend"));
+ items.push_back(std::string("invite_to_group"));
+ items.push_back(std::string("separator_invite_to_group"));
+ items.push_back(std::string("map"));
+ items.push_back(std::string("share"));
+ items.push_back(std::string("pay"));
+ items.push_back(std::string("block_unblock"));
+ items.push_back(std::string("MuteText"));
+
+ if ((getType() != CONV_SESSION_1_ON_1) && mDisplayModeratorOptions)
+ {
+ items.push_back(std::string("Moderator Options Separator"));
+ items.push_back(std::string("Moderator Options"));
+ items.push_back(std::string("AllowTextChat"));
+ items.push_back(std::string("moderate_voice_separator"));
+ items.push_back(std::string("ModerateVoiceToggleMuteSelected"));
+ items.push_back(std::string("ModerateVoiceMute"));
+ items.push_back(std::string("ModerateVoiceUnmute"));
+ }
}
-
}
//
@@ -306,7 +315,7 @@ void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)
{
items.push_back(std::string("close_conversation"));
items.push_back(std::string("separator_disconnect_from_voice"));
- buildParticipantMenuOptions(items);
+ buildParticipantMenuOptions(items, flags);
}
else if(this->getType() == CONV_SESSION_GROUP)
{
@@ -475,7 +484,7 @@ void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t items;
menuentry_vec_t disabled_items;
- buildParticipantMenuOptions(items);
+ buildParticipantMenuOptions(items, flags);
hide_context_entries(menu, items, disabled_items);
}
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 6ae891203d..01b3850f5e 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -130,7 +130,7 @@ public:
void postEvent(const std::string& event_type, LLConversationItemSession* session, LLConversationItemParticipant* participant);
- void buildParticipantMenuOptions(menuentry_vec_t& items);
+ void buildParticipantMenuOptions(menuentry_vec_t& items, U32 flags);
protected:
std::string mName; // Name of the session or the participant
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index c0a209f22d..903dd2a407 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -81,7 +81,9 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes
mSpeakingIndicator(NULL),
mVoiceClientObserver(NULL),
mCollapsedMode(false),
- mHasArrow(true)
+ mHasArrow(true),
+ mFlashStateOn(false),
+ mFlashStarted(false)
{
mFlashTimer = new LLFlashTimer();
}
@@ -101,7 +103,17 @@ LLConversationViewSession::~LLConversationViewSession()
void LLConversationViewSession::setFlashState(bool flash_state)
{
mFlashStateOn = flash_state;
- (flash_state ? mFlashTimer->startFlashing() : mFlashTimer->stopFlashing());
+ mFlashStarted = false;
+ mFlashTimer->stopFlashing();
+}
+
+void LLConversationViewSession::startFlashing()
+{
+ if (mFlashStateOn && !mFlashStarted)
+ {
+ mFlashStarted = true;
+ mFlashTimer->startFlashing();
+ }
}
bool LLConversationViewSession::isHighlightAllowed()
@@ -198,8 +210,11 @@ void LLConversationViewSession::draw()
drawOpenFolderArrow(default_params, sFgColor);
}
+ // Indicate that flash can start (moot operation if already started, done or not flashing)
+ startFlashing();
+
// draw highlight for selected items
- drawHighlight(show_context, true, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
+ drawHighlight(show_context, true, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
// Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap.
bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this) || isOpen();
@@ -231,6 +246,7 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )
if(result && getRoot()->getCurSelectedItem() == this)
{
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+ im_container->clearAllFlashStates();
im_container->selectConversationPair(session_id, false);
im_container->collapseMessagesPane(false);
}
@@ -427,6 +443,7 @@ void LLConversationViewParticipant::draw()
static LLUIColor sFgDisabledColor = LLUIColorTable::instance().getColor("MenuItemDisabledColor", DEFAULT_WHITE);
static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
+ static LLUIColor sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE);
static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
@@ -450,7 +467,7 @@ void LLConversationViewParticipant::draw()
color = mIsSelected ? sHighlightFgColor : sFgColor;
}
- drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
+ drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor);
drawLabel(font, text_left, y, color, right_x);
refresh();
@@ -530,27 +547,6 @@ void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask)
LLFolderViewItem::onMouseLeave(x, y, mask);
}
-BOOL LLConversationViewParticipant::handleMouseDown( S32 x, S32 y, MASK mask )
-{
- LLConversationItem* item = NULL;
- LLConversationViewSession* session_widget =
- dynamic_cast<LLConversationViewSession *>(this->getParentFolder());
- if (session_widget)
- {
- item = dynamic_cast<LLConversationItem*>(session_widget->getViewModelItem());
- }
- LLUUID session_id = item? item->getUUID() : LLUUID();
- BOOL result = LLFolderViewItem::handleMouseDown(x, y, mask);
-
- if(result)
- {
- (LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"))->
- selectConversationPair(session_id, false);
- }
-
- return result;
-}
-
S32 LLConversationViewParticipant::getLabelXPos()
{
return getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad;
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 1e20fb8b7e..5f6acfb9ab 100755
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -58,6 +58,7 @@ protected:
/*virtual*/ bool isHighlightAllowed();
/*virtual*/ bool isHighlightActive();
+ /*virtual*/ bool isFlashing() { return mFlashStateOn; }
LLFloaterIMContainer* mContainer;
@@ -83,11 +84,12 @@ public:
virtual void refresh();
- void setFlashState(bool flash_state);
+ /*virtual*/ void setFlashState(bool flash_state);
private:
void onCurrentVoiceSessionChanged(const LLUUID& session_id);
+ void startFlashing();
LLPanel* mItemPanel;
LLPanel* mCallIconLayoutPanel;
@@ -95,6 +97,7 @@ private:
LLOutputMonitorCtrl* mSpeakingIndicator;
LLFlashTimer* mFlashTimer;
bool mFlashStateOn;
+ bool mFlashStarted;
bool mCollapsedMode;
bool mHasArrow;
@@ -129,8 +132,6 @@ public:
void addToFolder(LLFolderViewFolder* folder);
void addToSession(const LLUUID& session_id);
- /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
-
void onMouseEnter(S32 x, S32 y, MASK mask);
void onMouseLeave(S32 x, S32 y, MASK mask);
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
new file mode 100644
index 0000000000..f4560d5668
--- /dev/null
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -0,0 +1,162 @@
+/**
+* @file lldonotdisturbnotificationstorage.cpp
+* @brief Implementation of lldonotdisturbnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 "lldonotdisturbnotificationstorage.h"
+
+#include "llcommunicationchannel.h"
+#include "lldir.h"
+#include "llerror.h"
+#include "llfasttimer_class.h"
+#include "llnotifications.h"
+#include "llnotificationhandler.h"
+#include "llnotificationstorage.h"
+#include "llscriptfloater.h"
+#include "llsd.h"
+#include "llsingleton.h"
+#include "lluuid.h"
+
+LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()
+ : LLSingleton<LLDoNotDisturbNotificationStorage>()
+ , LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"))
+{
+}
+
+LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage()
+{
+}
+
+void LLDoNotDisturbNotificationStorage::initialize()
+{
+ getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1));
+}
+
+static LLFastTimer::DeclareTimer FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications");
+
+void LLDoNotDisturbNotificationStorage::saveNotifications()
+{
+ LLFastTimer _(FTM_SAVE_DND_NOTIFICATIONS);
+
+ LLNotificationChannelPtr channelPtr = getCommunicationChannel();
+ const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
+ llassert(commChannel != NULL);
+
+ LLSD output = LLSD::emptyMap();
+ LLSD& data = output["data"];
+ data = LLSD::emptyArray();
+
+ for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory();
+ historyIter != commChannel->endHistory(); ++historyIter)
+ {
+ LLNotificationPtr notificationPtr = historyIter->second;
+
+ if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() && !notificationPtr->isExpired())
+ {
+ data.append(notificationPtr->asLLSD());
+ }
+ }
+
+ writeNotifications(output);
+}
+
+static LLFastTimer::DeclareTimer FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifications");
+
+void LLDoNotDisturbNotificationStorage::loadNotifications()
+{
+ LLFastTimer _(FTM_LOAD_DND_NOTIFICATIONS);
+
+ LLSD input;
+ if (!readNotifications(input) ||input.isUndefined())
+ {
+ return;
+ }
+
+ LLSD& data = input["data"];
+ if (data.isUndefined())
+ {
+ return;
+ }
+
+ LLNotifications& instance = LLNotifications::instance();
+
+ for (LLSD::array_const_iterator notification_it = data.beginArray();
+ notification_it != data.endArray();
+ ++notification_it)
+ {
+ LLSD notification_params = *notification_it;
+ LLNotificationPtr notification(new LLNotification(notification_params));
+
+ const LLUUID& notificationID = notification->id();
+ if (instance.find(notificationID))
+ {
+ instance.update(notification);
+ }
+ else
+ {
+ LLNotificationResponderInterface* responder = createResponder(notification_params["name"], notification_params["responder"]);
+ if (responder == NULL)
+ {
+ LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '"
+ << notification->getType() << "'" << LL_ENDL;
+ }
+ else
+ {
+ LLNotificationResponderPtr responderPtr(responder);
+ notification->setResponseFunctor(responderPtr);
+ }
+
+ instance.add(notification);
+ }
+ }
+
+ // Clear the communication channel history and rewrite the save file to empty it as well
+ LLNotificationChannelPtr channelPtr = getCommunicationChannel();
+ LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
+ llassert(commChannel != NULL);
+ commChannel->clearHistory();
+
+ saveNotifications();
+}
+
+LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const
+{
+ LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication");
+ llassert(channelPtr);
+ return channelPtr;
+}
+
+
+bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload)
+{
+ if (pPayload["sigtype"].asString() != "load")
+ {
+ saveNotifications();
+ }
+
+ return false;
+}
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
new file mode 100644
index 0000000000..60bcd89ec3
--- /dev/null
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -0,0 +1,57 @@
+/**
+* @file lldonotdisturbnotificationstorage.h
+* @brief Header file for lldonotdisturbnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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_LLDONOTDISTURBNOTIFICATIONSTORAGE_H
+#define LL_LLDONOTDISTURBNOTIFICATIONSTORAGE_H
+
+#include "llerror.h"
+#include "llnotifications.h"
+#include "llnotificationstorage.h"
+#include "llsingleton.h"
+
+class LLSD;
+
+class LLDoNotDisturbNotificationStorage : public LLSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage
+{
+ LOG_CLASS(LLDoNotDisturbNotificationStorage);
+public:
+ LLDoNotDisturbNotificationStorage();
+ ~LLDoNotDisturbNotificationStorage();
+
+ void initialize();
+
+ void saveNotifications();
+ void loadNotifications();
+
+protected:
+
+private:
+ LLNotificationChannelPtr getCommunicationChannel() const;
+ bool onChannelChanged(const LLSD& pPayload);
+};
+
+#endif // LL_LLDONOTDISTURBNOTIFICATIONSTORAGE_H
+
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index aae0990e4b..c2b9c77307 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -444,7 +444,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
return ;
}
- // stinson 11/12/2012: Need to check with davep on the following.
+ // Fix for MAINT-1894
// Skipping the flexible update if render res is negative. If we were to continue with a negative value,
// the subsequent S32 num_render_sections = 1<<mRenderRes; code will specify a really large number of
// render sections which will then create a length exception in the std::vector::resize() method.
diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp
index 089aec1905..a40a000bab 100644
--- a/indra/newview/llfloaterconversationlog.cpp
+++ b/indra/newview/llfloaterconversationlog.cpp
@@ -67,7 +67,8 @@ BOOL LLFloaterConversationLog::postBuild()
if (ctrl)
{
ctrl->getSignal()->connect(boost::bind(&LLFloaterConversationLog::onCallLoggingEnabledDisabled, this, _2));
- onCallLoggingEnabledDisabled(ctrl->getValue().asBoolean());
+ onCallLoggingEnabledDisabled(ctrl->getValue().asBoolean()
+ && gSavedSettings.getBOOL("KeepConversationLogTranscripts"));
}
return LLFloater::postBuild();
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index e1288a763c..ae243d6495 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -51,8 +51,8 @@
#include "llconversationview.h"
#include "llcallbacklist.h"
#include "llworld.h"
-
#include "llsdserialize.h"
+
//
// LLFloaterIMContainer
//
@@ -171,6 +171,9 @@ BOOL LLFloaterIMContainer::postBuild()
// Open IM session with selected participant on double click event
mConversationsListPanel->setDoubleClickCallback(boost::bind(&LLFloaterIMContainer::doToSelected, this, LLSD("im")));
+ // The resize limits for LLFloaterIMContainer should be updated, based on current values of width of conversation and message panels
+ mConversationsPane->getResizeBar()->setResizeListener(boost::bind(&LLFloaterIMContainer::assignResizeLimits, this));
+
// Create the root model and view for all conversation sessions
LLConversationItem* base_item = new LLConversationItem(getRootViewModel());
@@ -247,6 +250,7 @@ void LLFloaterIMContainer::onOpen(const LLSD& key)
{
LLMultiFloater::onOpen(key);
openNearbyChat();
+ assignResizeLimits();
}
// virtual
@@ -308,26 +312,6 @@ void LLFloaterIMContainer::onCloseFloater(LLUUID& id)
setFocus(TRUE);
}
-// virtual
-void LLFloaterIMContainer::computeResizeLimits(S32& new_min_width, S32& new_min_height)
-{
- // possibly increase floater's minimum height according to children's minimums
- for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
- {
- LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getPanelByIndex(tab_idx));
- if (floaterp)
- {
- new_min_height = llmax(new_min_height, floaterp->getMinHeight());
- }
- }
-
- S32 conversations_pane_min_dim = mConversationsPane->getRelevantMinDim();
- S32 messages_pane_min_dim = mMessagesPane->getRelevantMinDim();
-
- // set floater's minimum width according to relevant minimal children's dimensionals
- new_min_width = conversations_pane_min_dim + messages_pane_min_dim + LLPANEL_BORDER_WIDTH*2;
-}
-
void LLFloaterIMContainer::onNewMessageReceived(const LLSD& data)
{
LLUUID session_id = data["session_id"].asUUID();
@@ -621,6 +605,12 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
LLMultiFloater::setVisible(visible);
}
+void LLFloaterIMContainer::updateResizeLimits()
+{
+ LLMultiFloater::updateResizeLimits();
+ assignResizeLimits();
+}
+
void LLFloaterIMContainer::collapseMessagesPane(bool collapse)
{
if (mMessagesPane->isCollapsed() == collapse)
@@ -694,6 +684,7 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse)
{
widget->setOpen(false);
}
+ widget->requestArrange();
}
}
}
@@ -728,6 +719,15 @@ void LLFloaterIMContainer::updateState(bool collapse, S32 delta_width)
setResizeLimits(expanded_min_size, expanded_min_size);
}
+ assignResizeLimits();
+}
+
+void LLFloaterIMContainer::assignResizeLimits()
+{
+ const LLRect& conv_rect = mConversationsPane->isCollapsed() ? LLRect() : mConversationsPane->getRect();
+ S32 msg_limits = mMessagesPane->isCollapsed() ? 0 : mMessagesPane->getExpandedMinDim();
+ S32 x_limits = conv_rect.getWidth() + msg_limits;
+ setResizeLimits(x_limits + LLPANEL_BORDER_WIDTH * 3, getMinHeight());
}
void LLFloaterIMContainer::onAddButtonClicked()
@@ -1108,7 +1108,27 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
uuid_vec_t uuids;
getParticipantUUIDs(uuids);
- if("can_activate_group" == item)
+ if ("conversation_log" == item)
+ {
+ return gSavedSettings.getBOOL("KeepConversationLogTranscripts");
+ }
+
+ //Enable Chat history item for ad-hoc and group conversations
+ if ("can_chat_history" == item)
+ {
+ if (getCurSelectedViewModelItem()->getType() != LLConversationItem::CONV_PARTICIPANT)
+ {
+ return isConversationLoggingAllowed();
+ }
+ }
+
+ // If nothing is selected(and selected item is not group chat), everything needs to be disabled
+ if (uuids.size() <= 0)
+ {
+ return getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP;
+ }
+
+ if("can_activate_group" == item)
{
LLUUID selected_group_id = getCurSelectedViewModelItem()->getUUID();
return gAgent.getGroupID() != selected_group_id;
@@ -1119,17 +1139,6 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_vec_t& uuids)
{
- if ("conversation_log" == item)
- {
- return gSavedSettings.getBOOL("KeepConversationLogTranscripts");
- }
-
- // If nothing is selected, everything needs to be disabled
- if (uuids.size() <= 0)
- {
- return false;
- }
-
// Extract the single select info
bool is_single_select = (uuids.size() == 1);
const LLUUID& single_id = uuids.front();
@@ -1236,6 +1245,19 @@ void LLFloaterIMContainer::showConversation(const LLUUID& session_id)
selectConversationPair(session_id, true);
}
+void LLFloaterIMContainer::clearAllFlashStates()
+{
+ conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
+ for (;widget_it != mConversationsWidgets.end(); ++widget_it)
+ {
+ LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
+ if (widget)
+ {
+ widget->setFlashState(false);
+ }
+ }
+}
+
void LLFloaterIMContainer::selectConversation(const LLUUID& session_id)
{
selectConversationPair(session_id, true);
@@ -1247,17 +1269,6 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool
BOOL handled = TRUE;
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
- // On selection, stop the flash state on all conversation widgets
- conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
- for (;widget_it != mConversationsWidgets.end(); ++widget_it)
- {
- LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
- if (widget)
- {
- widget->setFlashState(false);
- }
- }
-
/* widget processing */
if (select_widget)
{
@@ -1419,14 +1430,14 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
// Delete the widget and the associated conversation item
// Note : since the mConversationsItems is also the listener to the widget, deleting
// the widget will also delete its listener
- bool isWidgetSelected = false;
+ bool is_widget_selected = false;
LLFolderViewItem* new_selection = NULL;
LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid);
if (widget)
{
- isWidgetSelected = widget->isSelected();
+ is_widget_selected = widget->isSelected();
new_selection = mConversationsRoot->getNextFromChild(widget);
- if(new_selection == NULL)
+ if (!new_selection)
{
new_selection = mConversationsRoot->getPreviousFromChild(widget);
}
@@ -1441,18 +1452,24 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
if (change_focus)
{
setFocus(TRUE);
- if(new_selection != NULL)
+ if (new_selection)
{
if (mConversationsWidgets.size() == 1)
- new_selection = new_selection->getParentFolder();
- LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(new_selection->getViewModelItem());
- if(vmi != NULL)
{
- selectConversationPair(vmi->getUUID(), true);
+ // If only one widget is left, it has to be the Nearby Chat. Select it directly.
+ selectConversationPair(LLUUID(NULL), true);
+ }
+ else
+ {
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(new_selection->getViewModelItem());
+ if (vmi)
+ {
+ selectConversationPair(vmi->getUUID(), true);
+ }
}
}
}
- return isWidgetSelected;
+ return is_widget_selected;
}
LLConversationViewSession* LLFloaterIMContainer::createConversationItemWidget(LLConversationItem* item)
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 1a3e64f759..0cd1b6759b 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -60,6 +60,7 @@ public:
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void draw();
/*virtual*/ void setVisible(BOOL visible);
+ /*virtual*/ void updateResizeLimits();
void onCloseFloater(LLUUID& id);
/*virtual*/ void addFloater(LLFloater* floaterp,
@@ -69,6 +70,7 @@ public:
void showConversation(const LLUUID& session_id);
void selectConversation(const LLUUID& session_id);
BOOL selectConversationPair(const LLUUID& session_id, bool select_widget);
+ void clearAllFlashStates();
/*virtual*/ void tabClose();
void showStub(bool visible);
@@ -105,12 +107,14 @@ public:
bool enableContextMenuItem(const std::string& item, uuid_vec_t& selectedIDS);
void doToParticipants(const std::string& item, uuid_vec_t& selectedIDS);
+ void assignResizeLimits();
+
private:
typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t;
avatarID_panel_map_t mSessions;
boost::signals2::connection mNewMessageConnection;
- /*virtual*/ void computeResizeLimits(S32& new_min_width, S32& new_min_height);
+ /*virtual*/ void computeResizeLimits(S32& new_min_width, S32& new_min_height) {}
void onNewMessageReceived(const LLSD& data);
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index a9a3611970..797d590e1f 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -113,8 +113,8 @@ BOOL LLFloaterIMNearbyChat::postBuild()
BOOL result = LLFloaterIMSessionTab::postBuild();
mInputEditor->setCommitCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxCommit, this));
- mInputEditor->setKeystrokeCallback(boost::bind(&onChatBoxKeystroke, _1, this));
- mInputEditor->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this));
+ mInputEditor->setKeystrokeCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxKeystroke, this));
+ mInputEditor->setFocusLostCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusLost, this));
mInputEditor->setFocusReceivedCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusReceived, this));
mInputEditor->setLabel(LLTrans::getString("NearbyChatTitle"));
@@ -354,13 +354,11 @@ BOOL LLFloaterIMNearbyChat::matchChatTypeTrigger(const std::string& in_str, std:
return string_was_found;
}
-void LLFloaterIMNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userdata)
+void LLFloaterIMNearbyChat::onChatBoxKeystroke()
{
LLFirstUse::otherAvatarChatFirst(false);
- LLFloaterIMNearbyChat* self = (LLFloaterIMNearbyChat *)userdata;
-
- LLWString raw_text = self->mInputEditor->getWText();
+ LLWString raw_text = mInputEditor->getWText();
// Can't trim the end, because that will cause autocompletion
// to eat trailing spaces that might be part of a gesture.
@@ -386,8 +384,8 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userd
// the selection will already be deleted, but we need to trim
// off the character before
std::string new_text = raw_text.substr(0, length-1);
- self->mInputEditor->setText( new_text );
- self->mInputEditor->setCursorToEnd();
+ mInputEditor->setText( new_text );
+ mInputEditor->setCursorToEnd();
length = length - 1;
}
*/
@@ -407,17 +405,17 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userd
if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str))
{
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
- self->mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
+ mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
// Select to end of line, starting from the character
// after the last one the user typed.
- self->mInputEditor->selectNext(rest_of_match, false);
+ mInputEditor->selectNext(rest_of_match, false);
}
else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
{
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
- self->mInputEditor->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
- self->mInputEditor->endOfDoc();
+ mInputEditor->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
+ mInputEditor->endOfDoc();
}
//llinfos << "GESTUREDEBUG " << trigger
@@ -428,7 +426,7 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userd
}
// static
-void LLFloaterIMNearbyChat::onChatBoxFocusLost(LLFocusableElement* caller, void* userdata)
+void LLFloaterIMNearbyChat::onChatBoxFocusLost()
{
// stop typing animation
gAgent.stopTyping();
diff --git a/indra/newview/llfloaterimnearbychat.h b/indra/newview/llfloaterimnearbychat.h
index a38824dc78..f4213eda5a 100644
--- a/indra/newview/llfloaterimnearbychat.h
+++ b/indra/newview/llfloaterimnearbychat.h
@@ -83,8 +83,8 @@ public:
protected:
static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str);
- static void onChatBoxKeystroke(LLTextEditor* caller, void* userdata);
- static void onChatBoxFocusLost(LLFocusableElement* caller, void* userdata);
+ void onChatBoxKeystroke();
+ void onChatBoxFocusLost();
void onChatBoxFocusReceived();
void sendChat( EChatType type );
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index a0ca7286f1..d36b138c21 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -73,8 +73,7 @@ LLFloaterIMSession::LLFloaterIMSession(const LLUUID& session_id)
mTypingTimer(),
mTypingTimeoutTimer(),
mPositioned(false),
- mSessionInitialized(false),
- mStartConferenceInSameFloater(false)
+ mSessionInitialized(false)
{
mIsNearbyChat = false;
@@ -83,8 +82,11 @@ LLFloaterIMSession::LLFloaterIMSession(const LLUUID& session_id)
setOverlapsScreenChannel(true);
LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this);
+ mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&LLFloaterIMSession::enableGearMenuItem, this, _2));
+ mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&LLFloaterIMSession::GearDoToSelected, this, _2));
+ mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&LLFloaterIMSession::checkGearMenuItem, this, _2));
- setDocked(true);
+ setDocked(true);
}
@@ -190,6 +192,36 @@ void LLFloaterIMSession::onSendMsg( LLUICtrl* ctrl, void* userdata )
self->setTyping(false);
}
+bool LLFloaterIMSession::enableGearMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(mOtherParticipantUUID);
+
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ return floater_container->enableContextMenuItem(command, selected_uuids);
+}
+
+void LLFloaterIMSession::GearDoToSelected(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(mOtherParticipantUUID);
+
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ floater_container->doToParticipants(command, selected_uuids);
+}
+
+bool LLFloaterIMSession::checkGearMenuItem(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(mOtherParticipantUUID);
+
+ LLFloaterIMContainer* floater_container = LLFloaterIMContainer::getInstance();
+ return floater_container->checkContextMenuItem(command, selected_uuids);
+}
+
void LLFloaterIMSession::sendMsgFromInputEditor()
{
if (gAgent.isGodlike()
@@ -429,8 +461,6 @@ void LLFloaterIMSession::addP2PSessionParticipants(const LLSD& notification, con
return;
}
- mStartConferenceInSameFloater = true;
-
LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
// first check whether this is a voice session
@@ -724,7 +754,7 @@ void LLFloaterIMSession::sessionInitReplyReceived(const LLUUID& im_session_id)
}
initIMFloater();
-
+ LLFloaterIMSessionTab::updateGearBtn();
//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB)
//need to send delayed messages collected while waiting for session initialization
diff --git a/indra/newview/llfloaterimsession.h b/indra/newview/llfloaterimsession.h
index 1d8957b1d9..6a2f4b29eb 100644
--- a/indra/newview/llfloaterimsession.h
+++ b/indra/newview/llfloaterimsession.h
@@ -99,6 +99,9 @@ public:
void setPositioned(bool b) { mPositioned = b; };
void onVisibilityChange(const LLSD& new_visibility);
+ bool enableGearMenuItem(const LLSD& userdata);
+ void GearDoToSelected(const LLSD& userdata);
+ bool checkGearMenuItem(const LLSD& userdata);
// Implements LLVoiceClientStatusObserver::onChange() to enable the call
// button when voice is available
@@ -124,8 +127,6 @@ public:
//used as a callback on receiving new IM message
static void sRemoveTypingIndicator(const LLSD& data);
static void onIMChicletCreated(const LLUUID& session_id);
-
- bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; }
const LLUUID& getOtherParticipantUUID() {return mOtherParticipantUUID;}
static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb);
@@ -185,8 +186,6 @@ private:
bool mSessionInitialized;
LLSD mQueuedMsgsForInit;
- bool mStartConferenceInSameFloater;
-
uuid_vec_t mInvitedParticipants;
// connection to voice channel state change signal
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index ea99a1c5bf..d4eb03f95d 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -82,6 +82,13 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
{
delete mRefreshTimer;
+
+ // Select Nearby Chat session
+ LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("im_container");
+ if (container)
+ {
+ container->selectConversationPair(LLUUID(NULL), true);
+ }
}
//static
@@ -177,6 +184,7 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id)
// LLFloater::mLastHostHandle = floater_container (a "future" host)
conversp->setHost(floater_container);
conversp->setHost(NULL);
+ conversp->forceReshape();
}
// Added floaters share some state (like sort order) with their host
conversp->setSortOrder(floater_container->getSortOrder());
@@ -197,6 +205,8 @@ BOOL LLFloaterIMSessionTab::postBuild()
mTearOffBtn = getChild<LLButton>("tear_off_btn");
mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this));
+ mGearBtn = getChild<LLButton>("gear_btn");
+
mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");
// Add a scroller for the folder (participant) view
@@ -224,7 +234,8 @@ BOOL LLFloaterIMSessionTab::postBuild()
setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE);
- mSaveRect = isTornOff();
+ mSaveRect = isNearbyChat()
+ && !gSavedSettings.getBOOL("NearbyChatIsNotTornOff");
initRectControl();
if (isChatMultiTab())
@@ -236,14 +247,31 @@ BOOL LLFloaterIMSessionTab::postBuild()
result = LLDockableFloater::postBuild();
}
- // Now ready to build the conversation and participants list
+ // Create the root using an ad-hoc base item
+ LLConversationItem* base_item = new LLConversationItem(mSessionID, mConversationViewModel);
+ LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>());
+ p.rect = LLRect(0, 0, getRect().getWidth(), 0);
+ p.parent_panel = mParticipantListPanel;
+ p.listener = base_item;
+ p.view_model = &mConversationViewModel;
+ p.root = NULL;
+ p.use_ellipses = true;
+ p.options_menu = "menu_conversation.xml";
+ mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
+ mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ // Attach that root to the scroller
+ mScroller->addChild(mConversationsRoot);
+ mConversationsRoot->setScrollContainer(mScroller);
+ mConversationsRoot->setFollowsAll();
+ mConversationsRoot->addChild(mConversationsRoot->mStatusTextBox);
+
buildConversationViewParticipant();
refreshConversation();
-
+
// Zero expiry time is set only once to allow initial update.
mRefreshTimer->setTimerExpirySec(0);
mRefreshTimer->start();
-
+ initBtns();
return result;
}
@@ -301,10 +329,10 @@ void LLFloaterIMSessionTab::onFocusReceived()
LLTransientDockableFloater::onFocusReceived();
- LLFloaterIMContainer* container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+ LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("im_container");
if (container)
{
- container->selectConversationPair(mSessionID, ! getHost());
+ container->selectConversationPair(mSessionID, true);
container->showStub(! getHost());
}
}
@@ -384,31 +412,6 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant()
return;
}
- // Create or recreate the root folder: this is a dummy folder (not shown) but required by the LLFolderView architecture
- // We need to redo this when rebuilding as the session id (mSessionID) *may* have changed
- if (mConversationsRoot)
- {
- // Remove the old root if any
- mScroller->removeChild(mConversationsRoot);
- }
- // Create the root using an ad-hoc base item
- LLConversationItem* base_item = new LLConversationItem(mSessionID, mConversationViewModel);
- LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>());
- p.rect = LLRect(0, 0, getRect().getWidth(), 0);
- p.parent_panel = mParticipantListPanel;
- p.listener = base_item;
- p.view_model = &mConversationViewModel;
- p.root = NULL;
- p.use_ellipses = true;
- p.options_menu = "menu_conversation.xml";
- mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
- mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
- // Attach that root to the scroller
- mScroller->addChild(mConversationsRoot);
- mConversationsRoot->setScrollContainer(mScroller);
- mConversationsRoot->setFollowsAll();
- mConversationsRoot->addChild(mConversationsRoot->mStatusTextBox);
-
// Create the participants widgets now
LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin();
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd();
@@ -610,8 +613,8 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
// prevent start conversation before its container
LLFloaterIMContainer::getInstance();
- bool is_torn_off = checkIfTornOff();
- if (!is_torn_off)
+ bool is_not_torn_off = !checkIfTornOff();
+ if (is_not_torn_off)
{
hideAllStandardButtons();
}
@@ -620,7 +623,7 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
// Participant list should be visible only in torn off floaters.
bool is_participant_list_visible =
- is_torn_off
+ !is_not_torn_off
&& gSavedSettings.getBOOL("IMShowControlPanel")
&& !mIsP2PChat;
@@ -628,27 +631,42 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
// Display collapse image (<<) if the floater is hosted
// or if it is torn off but has an open control panel.
- bool is_expanded = !is_torn_off || is_participant_list_visible;
+ bool is_expanded = is_not_torn_off || is_participant_list_visible;
mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon"));
+ mExpandCollapseBtn->setToolTip(
+ is_not_torn_off?
+ getString("expcol_button_not_tearoff_tooltip") :
+ (is_expanded?
+ getString("expcol_button_tearoff_and_expanded_tooltip") :
+ getString("expcol_button_tearoff_and_collapsed_tooltip")));
// toggle floater's drag handle and title visibility
if (mDragHandle)
{
- mDragHandle->setTitleVisible(is_torn_off);
+ mDragHandle->setTitleVisible(!is_not_torn_off);
}
// The button (>>) should be disabled for torn off P2P conversations.
- mExpandCollapseBtn->setEnabled(!is_torn_off || !mIsP2PChat);
+ mExpandCollapseBtn->setEnabled(is_not_torn_off || !mIsP2PChat);
- mTearOffBtn->setImageOverlay(getString(is_torn_off? "return_icon" : "tear_off_icon"));
- mTearOffBtn->setToolTip(getString(!is_torn_off? "tooltip_to_separate_window" : "tooltip_to_main_window"));
+ mTearOffBtn->setImageOverlay(getString(is_not_torn_off? "tear_off_icon" : "return_icon"));
+ mTearOffBtn->setToolTip(getString(is_not_torn_off? "tooltip_to_separate_window" : "tooltip_to_main_window"));
- mCloseBtn->setVisible(!is_torn_off && !mIsNearbyChat);
+ mCloseBtn->setVisible(is_not_torn_off && !mIsNearbyChat);
enableDisableCallBtn();
showTranslationCheckbox();
}
+
+void LLFloaterIMSessionTab::forceReshape()
+{
+ LLRect floater_rect = getRect();
+ reshape(llmax(floater_rect.getWidth(), this->getMinWidth()),
+ llmax(floater_rect.getHeight(), this->getMinHeight()),
+ true);
+}
+
void LLFloaterIMSessionTab::reshapeChatHistory()
{
@@ -735,19 +753,6 @@ void LLFloaterIMSessionTab::onOpen(const LLSD& key)
}
}
-// virtual
-void LLFloaterIMSessionTab::onClose(bool app_quitting)
-{
- // Always suppress the IM from the conversations list on close if present for any reason
- if (LLFloaterIMSessionTab::isChatMultiTab())
- {
- LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance();
- if (im_box)
- {
- im_box->removeConversationListItem(mKey);
- }
- }
-}
void LLFloaterIMSessionTab::onTearOffClicked()
{
@@ -755,7 +760,58 @@ void LLFloaterIMSessionTab::onTearOffClicked()
mSaveRect = isTornOff();
initRectControl();
LLFloater::onClickTearOff(this);
+ if (isTornOff())
+ {
+ forceReshape();
+ }
refreshConversation();
+ updateGearBtn();
+}
+
+void LLFloaterIMSessionTab::updateGearBtn()
+{
+
+ BOOL prevVisibility = mGearBtn->getVisible();
+ mGearBtn->setVisible(checkIfTornOff() && mIsP2PChat);
+
+
+ // Move buttons if Gear button changed visibility
+ if(prevVisibility != mGearBtn->getVisible())
+ {
+ LLRect gear_btn_rect = mGearBtn->getRect();
+ LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect();
+ LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect();
+ S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;
+ S32 right_shift = gear_btn_rect.getWidth() + gap_width;
+ if(mGearBtn->getVisible())
+ {
+ // Move buttons to the right to give space for Gear button
+ add_btn_rect.translate(right_shift,0);
+ call_btn_rect.translate(right_shift,0);
+ }
+ else
+ {
+ add_btn_rect.translate(-right_shift,0);
+ call_btn_rect.translate(-right_shift,0);
+ }
+ getChild<LLButton>("add_btn")->setRect(add_btn_rect);
+ getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect);
+ }
+}
+
+void LLFloaterIMSessionTab::initBtns()
+{
+ LLRect gear_btn_rect = mGearBtn->getRect();
+ LLRect add_btn_rect = getChild<LLButton>("add_btn")->getRect();
+ LLRect call_btn_rect = getChild<LLButton>("voice_call_btn")->getRect();
+ S32 gap_width = call_btn_rect.mLeft - add_btn_rect.mRight;
+ S32 right_shift = gear_btn_rect.getWidth() + gap_width;
+
+ add_btn_rect.translate(-right_shift,0);
+ call_btn_rect.translate(-right_shift,0);
+
+ getChild<LLButton>("add_btn")->setRect(add_btn_rect);
+ getChild<LLButton>("voice_call_btn")->setRect(call_btn_rect);
}
// static
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index cd0bcd481c..0fa99a46be 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -77,7 +77,6 @@ public:
// LLFloater overrides
/*virtual*/ void onOpen(const LLSD& key);
- /*virtual*/ void onClose(bool app_quitting);
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
/*virtual*/ void setVisible(BOOL visible);
@@ -92,10 +91,13 @@ public:
void setSortOrder(const LLConversationSort& order);
virtual void onTearOffClicked();
-
+ void updateGearBtn();
+ void initBtns();
virtual void updateMessages() {}
LLConversationItem* getCurSelectedViewModelItem();
+ void forceReshape();
+
protected:
// callback for click on any items of the visual states menu
@@ -157,6 +159,8 @@ protected:
LLButton* mExpandCollapseBtn;
LLButton* mTearOffBtn;
LLButton* mCloseBtn;
+ LLButton* mGearBtn;
+
private:
// Handling selection and contextual menu
diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp
index 18ed36d0f3..29a3e6ac3a 100644
--- a/indra/newview/llfloateroutbox.cpp
+++ b/indra/newview/llfloateroutbox.cpp
@@ -49,6 +49,11 @@
/// LLOutboxNotification class
///----------------------------------------------------------------------------
+LLNotificationsUI::LLOutboxNotification::LLOutboxNotification()
+ : LLSystemNotificationHandler("Outbox", "outbox")
+{
+}
+
bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLNotificationPtr& notify)
{
LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox");
@@ -60,10 +65,10 @@ bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLNotifi
void LLNotificationsUI::LLOutboxNotification::onDelete(LLNotificationPtr p)
{
- LLNotificationsUI::LLSysHandler * sys_handler = dynamic_cast<LLNotificationsUI::LLSysHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- if (sys_handler)
+ LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
+ if (notification_handler)
{
- sys_handler->onDelete(p);
+ notification_handler->onDelete(p);
}
}
@@ -524,9 +529,9 @@ void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content)
void LLFloaterOutbox::showNotification(const LLNotificationPtr& notification)
{
- LLNotificationsUI::LLSysHandler * sys_handler = dynamic_cast<LLNotificationsUI::LLSysHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- llassert(sys_handler);
+ LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
+ llassert(notification_handler);
- sys_handler->processNotification(notification);
+ notification_handler->processNotification(notification);
}
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 0960846510..95d57d08d8 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -232,11 +232,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_LOOKAT:
hud_objectp = new LLHUDEffectLookAt(type);
break;
-#ifdef XXX_STINSON_CHUI_REWORK
case LL_HUD_EFFECT_VOICE_VISUALIZER:
hud_objectp = new LLVoiceVisualizer(type);
break;
-#endif // XXX_STINSON_CHUI_REWORK
case LL_HUD_EFFECT_POINTAT:
hud_objectp = new LLHUDEffectPointAt(type);
break;
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 32cffe6839..2f7a98c86c 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -39,8 +39,6 @@
#include "lldrawpool.h" // TODO: eliminate, unused below
#include <list>
-#define XXX_STINSON_CHUI_REWORK // temporarily re-enabling the in-world voice-dot
-
class LLViewerCamera;
class LLFontGL;
class LLFace;
@@ -96,9 +94,7 @@ public:
LL_HUD_EFFECT_EDIT,
LL_HUD_EFFECT_LOOKAT,
LL_HUD_EFFECT_POINTAT,
-#ifdef XXX_STINSON_CHUI_REWORK
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
-#endif // XXX_STINSON_CHUI_REWORK
LL_HUD_NAME_TAG,
LL_HUD_EFFECT_BLOB
};
diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp
index 047472a282..72967eb6c7 100644
--- a/indra/newview/llimhandler.cpp
+++ b/indra/newview/llimhandler.cpp
@@ -38,7 +38,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLIMHandler::LLIMHandler()
-: LLSysHandler("IM Notifications", "notifytoast")
+: LLCommunicationNotificationHandler("IM Notifications", "notifytoast")
{
// Getting a Channel for our notifications
mChannel = LLChannelManager::getInstance()->createNotificationChannel()->getHandle();
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 9195ea2344..2bb79a39e8 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -122,7 +122,7 @@ void on_new_message(const LLSD& msg)
LLUUID session_id = msg["session_id"].asUUID();
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
- // determine action for this session
+ // determine action for this session
if (session_id.isNull())
{
@@ -148,8 +148,8 @@ void on_new_message(const LLSD& msg)
action = gSavedSettings.getString("NotificationGroupChatOptions");
}
- // do not show notification in "do not disturb" mode or it goes from agent
- if (gAgent.isDoNotDisturb() || gAgent.getID() == participant_id)
+ // do not show notification which goes from agent
+ if (gAgent.getID() == participant_id)
{
return;
}
@@ -160,67 +160,69 @@ void on_new_message(const LLSD& msg)
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
//session floater not focused (visible or not)
- bool sessionFloaterNotFocused = session_floater && !session_floater->hasFocus();
+ bool session_floater_not_focused = session_floater && !session_floater->hasFocus();
+
+ //conv. floater is closed
+ bool conversation_floater_is_closed =
+ !( im_box
+ && im_box->isInVisibleChain()
+ && !im_box->isMinimized());
//conversation floater not focused (visible or not)
- bool conversationFloaterNotFocused = im_box && !im_box->hasFocus();
+ bool conversation_floater_not_focused =
+ conversation_floater_is_closed || !im_box->hasFocus();
if ("toast" == action)
{
- // Skip toasting if we have open window of IM with this session id
- if (
- session_floater
+ // Skip toasting and flashing if we have open window of IM with this session id
+ if (session_floater
&& session_floater->isInVisibleChain()
&& session_floater->hasFocus()
&& !session_floater->isMinimized()
- && !(session_floater->getHost()
- && session_floater->getHost()->isMinimized())
+ && !(session_floater->getHost() && session_floater->getHost()->isMinimized())
)
{
return;
}
- // Skip toasting for system messages and for nearby chat
- if (participant_id.isNull())
- {
- return;
- }
-
//User is not focused on conversation containing the message
- if(sessionFloaterNotFocused)
+ if(session_floater_not_focused)
{
im_box->flashConversationItemWidget(session_id, true);
//The conversation floater isn't focused/open
- if(conversationFloaterNotFocused)
+ if(conversation_floater_not_focused)
{
gToolBarView->flashCommand(LLCommandId("chat"), true);
//Show IM toasts (upper right toasts)
- if(session_id.notNull())
+ // Skip toasting for system messages and for nearby chat
+ if(session_id.notNull() && participant_id.notNull())
{
LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
}
}
}
}
+
else if ("flash" == action)
{
- //User is not focused on conversation containing the message
- if(sessionFloaterNotFocused && conversationFloaterNotFocused)
- {
- gToolBarView->flashCommand(LLCommandId("chat"), true);
- }
- //conversation floater is open but a different conversation is focused
- else if(sessionFloaterNotFocused)
- {
+ if (conversation_floater_not_focused)
+ {
+ if(session_floater_not_focused)
+ {
+ //User is not focused on conversation containing the message
+ gToolBarView->flashCommand(LLCommandId("chat"), true);
+ }
+
im_box->flashConversationItemWidget(session_id, true);
}
}
+
else if("openconversations" == action)
{
//User is not focused on conversation containing the message
- if(sessionFloaterNotFocused)
+ if(session_floater_not_focused)
{
//Flash line item
im_box->flashConversationItemWidget(session_id, true);
@@ -863,7 +865,8 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
{
- if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
+ if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")
+ && gSavedSettings.getBOOL("KeepConversationLogTranscripts"))
{
std::string from_name = from;
@@ -960,7 +963,7 @@ const std::string LLIMModel::getName(const LLUUID& session_id) const
{
LLIMSession* session = findIMSession(session_id);
- if (!session)
+ if (!session)
{
llwarns << "session " << session_id << "does not exist " << llendl;
return LLTrans::getString("no_session_message");
@@ -2487,17 +2490,24 @@ void LLIMMgr::addMessage(
new_session_id = computeSessionID(dialog, other_participant_id);
}
- // Open conversation log if offline messages are present
+ // Open conversation log if offline messages are present and user allows a Call Log
if (is_offline_msg)
- {
- LLFloaterConversationLog* floater_log =
- LLFloaterReg::getTypedInstance<LLFloaterConversationLog>("conversation");
- if (floater_log && !(floater_log->isFrontmost()))
+ {
+ if (gSavedSettings.getBOOL("KeepConversationLogTranscripts"))
{
- floater_log->openFloater();
- floater_log->setFrontmost(TRUE);
+ LLFloaterConversationLog* floater_log =
+ LLFloaterReg::getTypedInstance<LLFloaterConversationLog>("conversation");
+ if (floater_log && !(floater_log->isFrontmost()))
+ {
+ floater_log->openFloater();
+ floater_log->setFrontmost(TRUE);
+ }
}
- }
+ else
+ {
+ gToolBarView->flashCommand(LLCommandId("chat"), true);
+ }
+ }
//*NOTE session_name is empty in case of incoming P2P sessions
std::string fixed_session_name = from;
@@ -2552,7 +2562,7 @@ void LLIMMgr::addMessage(
}
//Play sound for new conversations
- if(gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)
+ if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -2708,12 +2718,13 @@ LLUUID LLIMMgr::addSession(
{
LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id);
- if (im_floater && im_floater->getStartConferenceInSameFloater())
+ if (im_floater)
{
// The IM floater should be initialized with a new session_id
// so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated,
// and a new floater is not created.
im_floater->initIMSession(session_id);
+ im_floater->reloadMessages();
}
}
diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp
index 2bc9cdd3c1..58a9b01a45 100644
--- a/indra/newview/llnotificationalerthandler.cpp
+++ b/indra/newview/llnotificationalerthandler.cpp
@@ -29,6 +29,7 @@
#include "llnotificationhandler.h"
+#include "llagentcamera.h"
#include "llnotifications.h"
#include "llprogressview.h"
#include "lltoastnotifypanel.h"
@@ -41,7 +42,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLAlertHandler::LLAlertHandler(const std::string& name, const std::string& notification_type, bool is_modal)
-: LLSysHandler(name, notification_type),
+: LLSystemNotificationHandler(name, notification_type),
mIsModal(is_modal)
{
LLScreenChannelBase::Params p;
@@ -123,3 +124,28 @@ void LLAlertHandler::onChange( LLNotificationPtr notification )
if(channel)
channel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog);
}
+
+//--------------------------------------------------------------------------
+LLViewerAlertHandler::LLViewerAlertHandler(const std::string& name, const std::string& notification_type)
+ : LLSystemNotificationHandler(name, notification_type)
+{
+}
+
+bool LLViewerAlertHandler::processNotification(const LLNotificationPtr& p)
+{
+ if (gHeadlessClient)
+ {
+ LL_INFOS("LLViewerAlertHandler") << "Alert: " << p->getName() << LL_ENDL;
+ }
+
+ // If we're in mouselook, the mouse is hidden and so the user can't click
+ // the dialog buttons. In that case, change to First Person instead.
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ return false;
+}
+
+
diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp
index 18cd94e685..8fef102cf8 100644
--- a/indra/newview/llnotificationgrouphandler.cpp
+++ b/indra/newview/llnotificationgrouphandler.cpp
@@ -38,7 +38,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLGroupHandler::LLGroupHandler()
-: LLSysHandler("Group Notifications", "groupnotify")
+: LLCommunicationNotificationHandler("Group Notifications", "groupnotify")
{
// Getting a Channel for our notifications
LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 4bded6ab30..bff4efa9ea 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -27,6 +27,7 @@
#ifndef LL_LLNOTIFICATIONHANDLER_H
#define LL_LLNOTIFICATIONHANDLER_H
+#include <boost/intrusive_ptr.hpp>
#include "llwindow.h"
@@ -86,22 +87,37 @@ protected:
/**
* Handler for system notifications.
*/
-class LLSysHandler : public LLEventHandler, public LLNotificationChannel
+class LLNotificationHandler : public LLEventHandler, public LLNotificationChannel
{
public:
- LLSysHandler(const std::string& name, const std::string& notification_type);
- virtual ~LLSysHandler() {};
+ LLNotificationHandler(const std::string& name, const std::string& notification_type, const std::string& parentName);
+ virtual ~LLNotificationHandler() {};
// base interface functions
- /*virtual*/ void onAdd(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ void onLoad(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ void onDelete(LLNotificationPtr p) { if (mChannel.get()) mChannel.get()->removeToastByNotificationID(p->getID());}
+ virtual void onAdd(LLNotificationPtr p) { processNotification(p); }
+ virtual void onChange(LLNotificationPtr p) { processNotification(p); }
+ virtual void onLoad(LLNotificationPtr p) { processNotification(p); }
+ virtual void onDelete(LLNotificationPtr p) { if (mChannel.get()) mChannel.get()->removeToastByNotificationID(p->getID());}
- virtual bool processNotification(const LLNotificationPtr& notify)=0;
+ virtual bool processNotification(const LLNotificationPtr& notify) = 0;
+};
+
+class LLSystemNotificationHandler : public LLNotificationHandler
+{
+public:
+ LLSystemNotificationHandler(const std::string& name, const std::string& notification_type);
+ virtual ~LLSystemNotificationHandler() {};
+};
+
+class LLCommunicationNotificationHandler : public LLNotificationHandler
+{
+public:
+ LLCommunicationNotificationHandler(const std::string& name, const std::string& notification_type);
+ virtual ~LLCommunicationNotificationHandler() {};
};
/**
- * Handler for chat message notifications.
+ * Handler for chat message notifications.
*/
class LLChatHandler : public LLEventHandler
{
@@ -115,67 +131,62 @@ public:
* Handler for IM notifications.
* It manages life time of IMs, group messages.
*/
-class LLIMHandler : public LLSysHandler
+class LLIMHandler : public LLCommunicationNotificationHandler
{
public:
LLIMHandler();
virtual ~LLIMHandler();
+ bool processNotification(const LLNotificationPtr& p);
protected:
- bool processNotification(const LLNotificationPtr& p);
- /*virtual*/ void initChannel();
+ virtual void initChannel();
};
/**
* Handler for system informational notices.
* It manages life time of tip notices.
*/
-class LLTipHandler : public LLSysHandler
+class LLTipHandler : public LLSystemNotificationHandler
{
public:
LLTipHandler();
virtual ~LLTipHandler();
- // base interface functions
- /*virtual*/ void onChange(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ bool processNotification(const LLNotificationPtr& p);
+ virtual bool processNotification(const LLNotificationPtr& p);
protected:
- /*virtual*/ void initChannel();
+ virtual void initChannel();
};
/**
* Handler for system informational notices.
* It manages life time of script notices.
*/
-class LLScriptHandler : public LLSysHandler
+class LLScriptHandler : public LLSystemNotificationHandler
{
public:
LLScriptHandler();
virtual ~LLScriptHandler();
- /*virtual*/ void onDelete(LLNotificationPtr p);
- // base interface functions
- /*virtual*/ bool processNotification(const LLNotificationPtr& p);
+ virtual void onDelete(LLNotificationPtr p);
+ virtual bool processNotification(const LLNotificationPtr& p);
protected:
- /*virtual*/ void onDeleteToast(LLToast* toast);
- /*virtual*/ void initChannel();
+ virtual void onDeleteToast(LLToast* toast);
+ virtual void initChannel();
};
/**
* Handler for group system notices.
*/
-class LLGroupHandler : public LLSysHandler
+class LLGroupHandler : public LLCommunicationNotificationHandler
{
public:
LLGroupHandler();
virtual ~LLGroupHandler();
- // base interface functions
- /*virtual*/ void onChange(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ bool processNotification(const LLNotificationPtr& p);
+ virtual bool processNotification(const LLNotificationPtr& p);
protected:
virtual void initChannel();
@@ -184,15 +195,14 @@ protected:
/**
* Handler for alert system notices.
*/
-class LLAlertHandler : public LLSysHandler
+class LLAlertHandler : public LLSystemNotificationHandler
{
public:
LLAlertHandler(const std::string& name, const std::string& notification_type, bool is_modal);
virtual ~LLAlertHandler();
- /*virtual*/ void onChange(LLNotificationPtr p);
- /*virtual*/ void onLoad(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ bool processNotification(const LLNotificationPtr& p);
+ virtual void onChange(LLNotificationPtr p);
+ virtual bool processNotification(const LLNotificationPtr& p);
protected:
virtual void initChannel();
@@ -200,67 +210,85 @@ protected:
bool mIsModal;
};
+class LLViewerAlertHandler : public LLSystemNotificationHandler
+{
+ LOG_CLASS(LLViewerAlertHandler);
+public:
+ LLViewerAlertHandler(const std::string& name, const std::string& notification_type);
+ virtual ~LLViewerAlertHandler() {};
+
+ virtual void onDelete(LLNotificationPtr p) {};
+ virtual bool processNotification(const LLNotificationPtr& p);
+
+protected:
+ virtual void initChannel() {};
+};
+
/**
* Handler for offers notices.
* It manages life time of offer notices.
*/
-class LLOfferHandler : public LLSysHandler
+class LLOfferHandler : public LLCommunicationNotificationHandler
{
public:
LLOfferHandler();
virtual ~LLOfferHandler();
- // base interface functions
- /*virtual*/ void onChange(LLNotificationPtr p);
- /*virtual*/ void onDelete(LLNotificationPtr notification);
- /*virtual*/ bool processNotification(const LLNotificationPtr& p);
+ virtual void onChange(LLNotificationPtr p);
+ virtual void onDelete(LLNotificationPtr notification);
+ virtual bool processNotification(const LLNotificationPtr& p);
protected:
- /*virtual*/ void initChannel();
+ virtual void initChannel();
};
/**
* Handler for UI hints.
*/
-class LLHintHandler : public LLNotificationChannel
+class LLHintHandler : public LLSystemNotificationHandler
{
public:
- LLHintHandler() : LLNotificationChannel("Hints", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "hint"))
- {}
+ LLHintHandler();
virtual ~LLHintHandler() {}
- /*virtual*/ void onAdd(LLNotificationPtr p);
- /*virtual*/ void onLoad(LLNotificationPtr p);
- /*virtual*/ void onDelete(LLNotificationPtr p);
+ virtual void onAdd(LLNotificationPtr p);
+ virtual void onLoad(LLNotificationPtr p);
+ virtual void onDelete(LLNotificationPtr p);
+ virtual bool processNotification(const LLNotificationPtr& p);
+
+protected:
+ virtual void initChannel() {};
};
/**
* Handler for browser notifications
*/
-class LLBrowserNotification : public LLNotificationChannel
+class LLBrowserNotification : public LLSystemNotificationHandler
{
public:
- LLBrowserNotification()
- : LLNotificationChannel("Browser", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "browser"))
- {}
- /*virtual*/ void onAdd(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ void onChange(LLNotificationPtr p) { processNotification(p); }
- bool processNotification(const LLNotificationPtr& p);
+ LLBrowserNotification();
+ virtual ~LLBrowserNotification() {}
+
+ virtual bool processNotification(const LLNotificationPtr& p);
+
+protected:
+ virtual void initChannel() {};
};
/**
* Handler for outbox notifications
*/
-class LLOutboxNotification : public LLNotificationChannel
+class LLOutboxNotification : public LLSystemNotificationHandler
{
public:
- LLOutboxNotification()
- : LLNotificationChannel("Outbox", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "outbox"))
- {}
- /*virtual*/ void onAdd(LLNotificationPtr p) { processNotification(p); }
- /*virtual*/ void onChange(LLNotificationPtr p) { }
- /*virtual*/ void onDelete(LLNotificationPtr p);
- bool processNotification(const LLNotificationPtr& p);
+ LLOutboxNotification();
+ virtual ~LLOutboxNotification() {};
+ virtual void onChange(LLNotificationPtr p) { }
+ virtual void onDelete(LLNotificationPtr p);
+ virtual bool processNotification(const LLNotificationPtr& p);
+
+protected:
+ virtual void initChannel() {};
};
class LLHandlerUtil
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 7f1216ff40..f0175d677c 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -41,8 +41,16 @@
using namespace LLNotificationsUI;
-LLSysHandler::LLSysHandler(const std::string& name, const std::string& notification_type)
-: LLNotificationChannel(name, "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, notification_type))
+LLNotificationHandler::LLNotificationHandler(const std::string& name, const std::string& notification_type, const std::string& parentName)
+: LLNotificationChannel(name, parentName, LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, notification_type))
+{}
+
+LLSystemNotificationHandler::LLSystemNotificationHandler(const std::string& name, const std::string& notification_type)
+ : LLNotificationHandler(name, notification_type, "System")
+{}
+
+LLCommunicationNotificationHandler::LLCommunicationNotificationHandler(const std::string& name, const std::string& notification_type)
+ : LLNotificationHandler(name, notification_type, "Communication")
{}
// static
diff --git a/indra/newview/llnotificationhinthandler.cpp b/indra/newview/llnotificationhinthandler.cpp
index 271f418507..f40369a2e0 100644
--- a/indra/newview/llnotificationhinthandler.cpp
+++ b/indra/newview/llnotificationhinthandler.cpp
@@ -33,6 +33,27 @@
using namespace LLNotificationsUI;
-void LLHintHandler::onAdd(LLNotificationPtr p) { LLHints::show(p); }
-void LLHintHandler::onLoad(LLNotificationPtr p) { LLHints::show(p); }
-void LLHintHandler::onDelete(LLNotificationPtr p) { LLHints::hide(p); }
+LLHintHandler::LLHintHandler()
+ : LLSystemNotificationHandler("Hints", "hint")
+{
+}
+
+void LLHintHandler::onAdd(LLNotificationPtr p)
+{
+ LLHints::show(p);
+}
+
+void LLHintHandler::onLoad(LLNotificationPtr p)
+{
+ LLHints::show(p);
+}
+
+void LLHintHandler::onDelete(LLNotificationPtr p)
+{
+ LLHints::hide(p);
+}
+
+bool LLHintHandler::processNotification(const LLNotificationPtr& p)
+{
+ return false;
+}
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index ff5b5e21f7..da38c9063b 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -41,7 +41,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLOfferHandler::LLOfferHandler()
-: LLSysHandler("Offer", "offer")
+: LLCommunicationNotificationHandler("Offer", "offer")
{
// Getting a Channel for our notifications
LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 290a81f91c..e2d4e9f8ce 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -39,7 +39,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLScriptHandler::LLScriptHandler()
-: LLSysHandler("Notifications", "notify")
+: LLSystemNotificationHandler("Notifications", "notify")
{
// Getting a Channel for our notifications
LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
index a31b95811e..b797775369 100644
--- a/indra/newview/llnotificationstorage.cpp
+++ b/indra/newview/llnotificationstorage.cpp
@@ -25,207 +25,143 @@
*/
#include "llviewerprecompiledheaders.h" // must be first include
+
#include "llnotificationstorage.h"
-#include "llxmlnode.h" // for linux compilers
+#include <string>
+#include <map>
-#include "llchannelmanager.h"
-#include "llscreenchannel.h"
-#include "llscriptfloater.h"
+#include "llerror.h"
+#include "llfile.h"
+#include "llnotifications.h"
+#include "llpointer.h"
+#include "llsd.h"
#include "llsdserialize.h"
+#include "llsingleton.h"
#include "llviewermessage.h"
-//////////////////////////////////////////////////////////////////////////
-class LLResponderRegistry
+class LLResponderRegistry : public LLSingleton<LLResponderRegistry>
{
public:
-
- static void registerResponders();
-
- static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
-
+ LLResponderRegistry();
+ ~LLResponderRegistry();
+
+ LLNotificationResponderInterface* createResponder(const std::string& pNotificationName, const LLSD& pParams);
+
+protected:
+
private:
-
- template<typename RESPONDER_TYPE>
- static LLNotificationResponderInterface* create(const LLSD& params)
- {
- RESPONDER_TYPE* responder = new RESPONDER_TYPE();
- responder->fromLLSD(params);
- return responder;
- }
-
+ template<typename RESPONDER_TYPE> static LLNotificationResponderInterface* create(const LLSD& pParams);
+
typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
-
- static void add(const std::string& notification_name, const responder_constructor_t& ctr);
-
-private:
-
+
+ void add(const std::string& pNotificationName, const responder_constructor_t& pConstructor);
+
typedef std::map<std::string, responder_constructor_t> build_map_t;
-
- static build_map_t sBuildMap;
+ build_map_t mBuildMap;
};
-//////////////////////////////////////////////////////////////////////////
-
-LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+LLNotificationStorage::LLNotificationStorage(std::string pFileName)
+ : mFileName(pFileName)
{
- mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
}
-bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+LLNotificationStorage::~LLNotificationStorage()
{
- // we ignore "load" messages, but rewrite the persistence file on any other
- const std::string sigtype = payload["sigtype"].asString();
- if ("load" != sigtype)
- {
- saveNotifications();
- }
- return false;
}
-static LLFastTimer::DeclareTimer FTM_SAVE_NOTIFICATIONS("Save Notifications");
-
-void LLPersistentNotificationStorage::saveNotifications()
+bool LLNotificationStorage::writeNotifications(const LLSD& pNotificationData) const
{
- LLFastTimer _(FTM_SAVE_NOTIFICATIONS);
- llofstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
- {
- llwarns << "Failed to open " << mFileName << llendl;
- return;
- }
-
- LLSD output;
- LLSD& data = output["data"];
+ llofstream notifyFile(mFileName.c_str());
+ bool didFileOpen = notifyFile.is_open();
- boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
- if (!history_channel)
+ if (!didFileOpen)
{
- return;
+ LL_WARNS("LLNotificationStorage") << "Failed to open file '" << mFileName << "'" << LL_ENDL;
}
-
- for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory();
- it != end_it;
- ++it)
+ else
{
- LLNotificationPtr notification = *it;
-
- // After a notification was placed in Persist channel, it can become
- // responded, expired or canceled - in this case we are should not save it
- if(notification->isRespondedTo() || notification->isCancelled()
- || notification->isExpired())
- {
- continue;
- }
-
- data.append(notification->asLLSD());
+ LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+ formatter->format(pNotificationData, notifyFile, LLSDFormatter::OPTIONS_PRETTY);
}
- LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
- formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
+ return didFileOpen;
}
-static LLFastTimer::DeclareTimer FTM_LOAD_NOTIFICATIONS("Load Notifications");
-
-void LLPersistentNotificationStorage::loadNotifications()
+bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const
{
- LLFastTimer _(FTM_LOAD_NOTIFICATIONS);
- LLResponderRegistry::registerResponders();
+ bool didFileRead;
- LLNotifications::instance().getChannel("Persistent")->
- connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+ pNotificationData.clear();
- llifstream notify_file(mFileName.c_str());
- if (!notify_file.is_open())
+ llifstream notifyFile(mFileName.c_str());
+ didFileRead = notifyFile.is_open();
+ if (!didFileRead)
{
- llwarns << "Failed to open " << mFileName << llendl;
- return;
+ LL_WARNS("LLNotificationStorage") << "Failed to open file '" << mFileName << "'" << LL_ENDL;
}
-
- LLSD input;
- LLPointer<LLSDParser> parser = new LLSDXMLParser();
- if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
+ else
{
- llwarns << "Failed to parse open notifications" << llendl;
- return;
- }
-
- if (input.isUndefined())
- {
- return;
- }
-
- LLSD& data = input["data"];
- if (data.isUndefined())
- {
- return;
- }
-
- using namespace LLNotificationsUI;
- LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
- findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
-
- LLNotifications& instance = LLNotifications::instance();
-
- for (LLSD::array_const_iterator notification_it = data.beginArray();
- notification_it != data.endArray();
- ++notification_it)
- {
- LLSD notification_params = *notification_it;
- LLNotificationPtr notification(new LLNotification(notification_params));
-
- LLNotificationResponderPtr responder(LLResponderRegistry::
- createResponder(notification_params["name"], notification_params["responder"]));
- notification->setResponseFunctor(responder);
-
- instance.add(notification);
-
- // hide script floaters so they don't confuse the user and don't overlap startup toast
- LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
-
- if(notification_channel)
+ LLPointer<LLSDParser> parser = new LLSDXMLParser();
+ didFileRead = (parser->parse(notifyFile, pNotificationData, LLSDSerialize::SIZE_UNLIMITED) >= 0);
+ if (!didFileRead)
{
- // hide saved toasts so they don't confuse the user
- notification_channel->hideToast(notification->getID());
+ LL_WARNS("LLNotificationStorage") << "Failed to parse open notifications from file '" << mFileName
+ << "'" << LL_ENDL;
}
}
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
+ return didFileRead;
+}
-void LLResponderRegistry::registerResponders()
+LLNotificationResponderInterface* LLNotificationStorage::createResponder(const std::string& pNotificationName, const LLSD& pParams) const
{
- sBuildMap.clear();
+ return LLResponderRegistry::getInstance()->createResponder(pNotificationName, pParams);
+}
+LLResponderRegistry::LLResponderRegistry()
+ : LLSingleton<LLResponderRegistry>()
+ , mBuildMap()
+{
add("ObjectGiveItem", &create<LLOfferInfo>);
+ add("OwnObjectGiveItem", &create<LLOfferInfo>);
add("UserGiveItem", &create<LLOfferInfo>);
+
+ add("TeleportOffered", &create<LLOfferInfo>);
+ add("TeleportOffered_MaturityExceeded", &create<LLOfferInfo>);
+
+ add("OfferFriendship", &create<LLOfferInfo>);
}
-LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
+LLResponderRegistry::~LLResponderRegistry()
{
- build_map_t::const_iterator it = sBuildMap.find(notification_name);
- if(sBuildMap.end() == it)
+}
+
+LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& pNotificationName, const LLSD& pParams)
+{
+ build_map_t::const_iterator it = mBuildMap.find(pNotificationName);
+ if(mBuildMap.end() == it)
{
return NULL;
}
responder_constructor_t ctr = it->second;
- return ctr(params);
+ return ctr(pParams);
}
-void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
+template<typename RESPONDER_TYPE> LLNotificationResponderInterface* LLResponderRegistry::create(const LLSD& pParams)
{
- if(sBuildMap.find(notification_name) != sBuildMap.end())
+ RESPONDER_TYPE* responder = new RESPONDER_TYPE();
+ responder->fromLLSD(pParams);
+ return responder;
+}
+
+void LLResponderRegistry::add(const std::string& pNotificationName, const responder_constructor_t& pConstructor)
+{
+ if (mBuildMap.find(pNotificationName) != mBuildMap.end())
{
- llwarns << "Responder is already registered : " << notification_name << llendl;
- llassert(!"Responder already registered");
+ LL_ERRS("LLResponderRegistry") << "Responder is already registered : " << pNotificationName << LL_ENDL;
}
- sBuildMap[notification_name] = ctr;
+ mBuildMap.insert(std::make_pair<std::string, responder_constructor_t>(pNotificationName, pConstructor));
}
-
-// EOF
diff --git a/indra/newview/llnotificationstorage.h b/indra/newview/llnotificationstorage.h
index 8635c797c0..7aabf7d09e 100644
--- a/indra/newview/llnotificationstorage.h
+++ b/indra/newview/llnotificationstorage.h
@@ -27,32 +27,27 @@
#ifndef LL_NOTIFICATIONSTORAGE_H
#define LL_NOTIFICATIONSTORAGE_H
-#include "llnotifications.h"
-
-// Class that saves not responded(unread) notifications.
-// Unread notifications are saved in open_notifications.xml in SL account folder
-//
-// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
-// Notifications using functor responders are saved automatically (see llviewermessage.cpp
-// lure_callback_reg for example).
-// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
-// be a) serializable(implement LLNotificationResponderInterface),
-// b) registered with LLResponderRegistry (found in llnotificationstorage.cpp).
-class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>
-{
- LOG_CLASS(LLPersistentNotificationStorage);
-public:
+#include <string>
- LLPersistentNotificationStorage();
+#include "llerror.h"
- void saveNotifications();
+class LLNotificationResponderInterface;
+class LLSD;
- void loadNotifications();
+class LLNotificationStorage
+{
+ LOG_CLASS(LLNotificationStorage);
+public:
+ LLNotificationStorage(std::string pFileName);
+ ~LLNotificationStorage();
-private:
+protected:
+ bool writeNotifications(const LLSD& pNotificationData) const;
+ bool readNotifications(LLSD& pNotificationData) const;
- bool onPersistentChannelChanged(const LLSD& payload);
+ LLNotificationResponderInterface* createResponder(const std::string& pNotificationName, const LLSD& pParams) const;
+private:
std::string mFileName;
};
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index faa67b5ea4..a85335f1ba 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -42,7 +42,7 @@ using namespace LLNotificationsUI;
//--------------------------------------------------------------------------
LLTipHandler::LLTipHandler()
-: LLSysHandler("NotificationTips", "notifytip")
+: LLSystemNotificationHandler("NotificationTips", "notifytip")
{
// Getting a Channel for our notifications
LLScreenChannel* channel = LLChannelManager::getInstance()->createNotificationChannel();
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index ecab7d2167..df1ccdd9fc 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -137,6 +137,7 @@ void LLPanelBlockedList::updateButtons()
{
bool hasSelected = NULL != mBlockedList->getSelectedItem();
getChildView("unblock_btn")->setEnabled(hasSelected);
+ getChildView("blocked_gear_btn")->setEnabled(hasSelected);
}
void LLPanelBlockedList::unblockItem()
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
new file mode 100644
index 0000000000..224aaa2146
--- /dev/null
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -0,0 +1,145 @@
+/**
+* @file llpersistentnotificationstorage.cpp
+* @brief Implementation of llpersistentnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 "llpersistentnotificationstorage.h"
+
+#include "llchannelmanager.h"
+#include "llnotificationstorage.h"
+#include "llscreenchannel.h"
+#include "llscriptfloater.h"
+#include "llviewermessage.h"
+
+LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+ : LLSingleton<LLPersistentNotificationStorage>()
+ , LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml"))
+{
+}
+
+LLPersistentNotificationStorage::~LLPersistentNotificationStorage()
+{
+}
+
+static LLFastTimer::DeclareTimer FTM_SAVE_NOTIFICATIONS("Save Notifications");
+
+void LLPersistentNotificationStorage::saveNotifications()
+{
+ LLFastTimer _(FTM_SAVE_NOTIFICATIONS);
+
+ boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
+ if (!history_channel)
+ {
+ return;
+ }
+
+ LLSD output = LLSD::emptyMap();
+ LLSD& data = output["data"];
+
+ for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory();
+ it != end_it;
+ ++it)
+ {
+ LLNotificationPtr notification = *it;
+
+ // After a notification was placed in Persist channel, it can become
+ // responded, expired or canceled - in this case we are should not save it
+ if(notification->isRespondedTo() || notification->isCancelled()
+ || notification->isExpired())
+ {
+ continue;
+ }
+
+ data.append(notification->asLLSD());
+ }
+
+ writeNotifications(output);
+}
+
+static LLFastTimer::DeclareTimer FTM_LOAD_NOTIFICATIONS("Load Notifications");
+
+void LLPersistentNotificationStorage::loadNotifications()
+{
+ LLFastTimer _(FTM_LOAD_NOTIFICATIONS);
+
+ LLNotifications::instance().getChannel("Persistent")->
+ connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+
+ LLSD input;
+ if (!readNotifications(input) ||input.isUndefined())
+ {
+ return;
+ }
+
+ LLSD& data = input["data"];
+ if (data.isUndefined())
+ {
+ return;
+ }
+
+ using namespace LLNotificationsUI;
+ LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+ LLNotifications& instance = LLNotifications::instance();
+
+ for (LLSD::array_const_iterator notification_it = data.beginArray();
+ notification_it != data.endArray();
+ ++notification_it)
+ {
+ LLSD notification_params = *notification_it;
+ LLNotificationPtr notification(new LLNotification(notification_params));
+
+ LLNotificationResponderPtr responder(createResponder(notification_params["name"], notification_params["responder"]));
+ notification->setResponseFunctor(responder);
+
+ instance.add(notification);
+
+ // hide script floaters so they don't confuse the user and don't overlap startup toast
+ LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
+
+ if(notification_channel)
+ {
+ // hide saved toasts so they don't confuse the user
+ notification_channel->hideToast(notification->getID());
+ }
+ }
+}
+
+bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+{
+ // we ignore "load" messages, but rewrite the persistence file on any other
+ const std::string sigtype = payload["sigtype"].asString();
+ if ("load" != sigtype)
+ {
+ saveNotifications();
+ }
+ return false;
+}
+
+// EOF
diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h
new file mode 100644
index 0000000000..98a825d2c1
--- /dev/null
+++ b/indra/newview/llpersistentnotificationstorage.h
@@ -0,0 +1,63 @@
+/**
+* @file llpersistentnotificationstorage.h
+* @brief Header file for llpersistentnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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_LLPERSISTENTNOTIFICATIONSTORAGE_H
+#define LL_LLPERSISTENTNOTIFICATIONSTORAGE_H
+
+#include "llerror.h"
+#include "llnotificationstorage.h"
+#include "llsingleton.h"
+
+class LLSD;
+
+// Class that saves not responded(unread) notifications.
+// Unread notifications are saved in open_notifications.xml in SL account folder
+//
+// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
+// Notifications using functor responders are saved automatically (see llviewermessage.cpp
+// lure_callback_reg for example).
+// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
+// be a) serializable(implement LLNotificationResponderInterface),
+// b) registered with LLResponderRegistry (found in llpersistentnotificationstorage.cpp).
+
+class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>, public LLNotificationStorage
+{
+ LOG_CLASS(LLPersistentNotificationStorage);
+public:
+ LLPersistentNotificationStorage();
+ ~LLPersistentNotificationStorage();
+
+ void saveNotifications();
+ void loadNotifications();
+
+protected:
+
+private:
+ bool onPersistentChannelChanged(const LLSD& payload);
+};
+
+#endif // LL_LLPERSISTENTNOTIFICATIONSTORAGE_H
+
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index 8a43855a7d..e92bd766ca 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -40,6 +40,7 @@
LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLTransientDockableFloater(NULL, true, key),
mChannel(NULL),
mMessageList(NULL),
+ mSysWellChiclet(NULL),
NOTIFICATION_WELL_ANCHOR_NAME("notification_well_panel"),
IM_WELL_ANCHOR_NAME("im_well_panel"),
mIsReshapedByUser(false)
@@ -79,6 +80,15 @@ void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask)
setVisible(TRUE);
}
+void LLSysWellWindow::setSysWellChiclet(LLSysWellChiclet* chiclet)
+{
+ mSysWellChiclet = chiclet;
+ if(NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
+}
+
//---------------------------------------------------------------------------------
LLSysWellWindow::~LLSysWellWindow()
{
@@ -89,6 +99,10 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id)
{
if(mMessageList->removeItemByValue(id))
{
+ if (NULL != mSysWellChiclet)
+ {
+ mSysWellChiclet->updateWidget(isWindowEmpty());
+ }
reshapeWindow();
}
else
@@ -334,6 +348,7 @@ void LLNotificationWellWindow::addItem(LLSysWellItem::Params p)
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));
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 406ab1b59e..cc5c057d8b 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -66,6 +66,8 @@ public:
void onStartUpToastClick(S32 x, S32 y, MASK mask);
+ void setSysWellChiclet(LLSysWellChiclet* chiclet);
+
// size constants for the window and for its elements
static const S32 MAX_WINDOW_HEIGHT = 200;
static const S32 MIN_WINDOW_WIDTH = 318;
@@ -84,6 +86,11 @@ protected:
LLNotificationsUI::LLScreenChannel* mChannel;
LLFlatListView* mMessageList;
+ /**
+ * Reference to an appropriate Well chiclet to release "new message" state. EXT-3147
+ */
+ LLSysWellChiclet* mSysWellChiclet;
+
bool mIsReshapedByUser;
};
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index fe9c00cc27..be9f7d645a 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7586,6 +7586,20 @@ void handle_web_content_test(const LLSD& param)
LLWeb::loadURLInternal(url);
}
+void handle_show_url(const LLSD& param)
+{
+ std::string url = param.asString();
+ if(gSavedSettings.getBOOL("UseExternalBrowser"))
+ {
+ LLWeb::loadURLExternal(url);
+ }
+ else
+ {
+ LLWeb::loadURLInternal(url);
+ }
+
+}
+
void handle_buy_currency_test(void*)
{
std::string url =
@@ -8415,6 +8429,7 @@ void initialize_menus()
// Advanced > UI
commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
+ commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2));
view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index f5da94dc87..61716d1d5b 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3169,17 +3169,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["online"] = (offline == IM_ONLINE);
payload["sender"] = msg->getSender().getIPandPort();
- if (is_do_not_disturb)
- {
- send_do_not_disturb_message(msg, from_id);
- LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
- }
- else if (is_muted)
+ if (is_muted)
{
LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
}
else
{
+ if (is_do_not_disturb)
+ {
+ send_do_not_disturb_message(msg, from_id);
+ }
args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
if(message.empty())
{
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1d7abb7c1c..1c463015e2 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -37,8 +37,10 @@
#include "llagent.h"
#include "llagentcamera.h"
+#include "llcommunicationchannel.h"
#include "llfloaterreg.h"
#include "llmeshrepository.h"
+#include "llnotificationhandler.h"
#include "llpanellogin.h"
#include "llviewerkeyboard.h"
#include "llviewermenu.h"
@@ -127,6 +129,7 @@
#include "llmorphview.h"
#include "llmoveview.h"
#include "llnavigationbar.h"
+#include "llnotificationhandler.h"
#include "llpanelpathfindingrebakenavmesh.h"
#include "llpaneltopinfobar.h"
#include "llpopupview.h"
@@ -1554,11 +1557,11 @@ LLViewerWindow::LLViewerWindow(const Params& p)
mWindowListener.reset(new LLWindowListener(this, boost::lambda::var(gKeyboard)));
mViewerWindowListener.reset(new LLViewerWindowListener(this));
- mAlertsChannel.reset(new LLNotificationChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")));
- mModalAlertsChannel.reset(new LLNotificationChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")));
+ mSystemChannel.reset(new LLNotificationChannel("System", "Visible", LLNotificationFilters::includeEverything));
+ mCommunicationChannel.reset(new LLCommunicationChannel("Communication", "Visible"));
+ mAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alerts", "alert"));
+ mModalAlertsChannel.reset(new LLNotificationsUI::LLViewerAlertHandler("VW_alertmodal", "alertmodal"));
- mAlertsChannel->connectChanged(&LLViewerWindow::onAlert);
- mModalAlertsChannel->connectChanged(&LLViewerWindow::onAlert);
bool ignore = gSavedSettings.getBOOL("IgnoreAllNotifications");
LLNotifications::instance().setIgnoreAllNotifications(ignore);
if (ignore)
@@ -5044,25 +5047,6 @@ LLRect LLViewerWindow::getChatConsoleRect()
//----------------------------------------------------------------------------
-//static
-bool LLViewerWindow::onAlert(const LLSD& notify)
-{
- LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
-
- if (gHeadlessClient)
- {
- llinfos << "Alert: " << notification->getName() << llendl;
- }
-
- // If we're in mouselook, the mouse is hidden and so the user can't click
- // the dialog buttons. In that case, change to First Person instead.
- if( gAgentCamera.cameraMouselook() )
- {
- gAgentCamera.changeCameraToDefault();
- }
- return false;
-}
-
void LLViewerWindow::setUIVisibility(bool visible)
{
mUIVisible = visible;
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index ee6a7793f8..5a0d9652b8 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -43,6 +43,7 @@
#include "lltimer.h"
#include "llstat.h"
#include "llmousehandler.h"
+#include "llnotifications.h"
#include "llhandle.h"
#include "llinitparam.h"
@@ -401,7 +402,6 @@ public:
private:
bool shouldShowToolTipFor(LLMouseHandler *mh);
- static bool onAlert(const LLSD& notify);
void switchToolByMask(MASK mask);
void destroyWindow();
@@ -418,8 +418,10 @@ private:
bool mActive;
bool mUIVisible;
- boost::shared_ptr<class LLNotificationChannel> mAlertsChannel,
- mModalAlertsChannel;
+ LLNotificationChannelPtr mSystemChannel;
+ LLNotificationChannelPtr mCommunicationChannel;
+ LLNotificationChannelPtr mAlertsChannel;
+ LLNotificationChannelPtr mModalAlertsChannel;
LLRect mWindowRectRaw; // whole window, including UI
LLRect mWindowRectScaled; // whole window, scaled by UI size
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 951c145f25..ea7bf29209 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -34,8 +34,6 @@
#include "llvoavatar.h"
-#define XXX_STINSON_CHUI_REWORK // temporarily re-enabling the in-world voice-dot
-
#include <stdio.h>
#include <ctype.h>
@@ -711,13 +709,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLMemType mt(LLMemType::MTYPE_AVATAR);
//VTResume(); // VTune
-#ifdef XXX_STINSON_CHUI_REWORK
// mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline
const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
-#else // XXX_STINSON_CHUI_REWORK
- mVoiceVisualizer = new LLVoiceVisualizer();
-#endif // XXX_STINSON_CHUI_REWORK
lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl;
@@ -893,11 +887,7 @@ void LLVOAvatar::markDead()
mNameText = NULL;
sNumVisibleChatBubbles--;
}
-#ifdef XXX_STINSON_CHUI_REWORK
mVoiceVisualizer->markDead();
-#else // XXX_STINSON_CHUI_REWORK
- mVoiceVisualizer->setStopSpeaking();
-#endif // XXX_STINSON_CHUI_REWORK
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
LLViewerObject::markDead();
}
@@ -1429,9 +1419,7 @@ void LLVOAvatar::initInstance(void)
//VTPause(); // VTune
-#ifdef XXX_STINSON_CHUI_REWORK
mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
-#endif // XXX_STINSON_CHUI_REWORK
}
@@ -2529,7 +2517,6 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
{
-#ifdef XXX_STINSON_CHUI_REWORK
bool render_visualizer = voice_enabled;
// Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
@@ -2542,7 +2529,6 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
}
mVoiceVisualizer->setVoiceEnabled(render_visualizer);
-#endif // XXX_STINSON_CHUI_REWORK
if ( voice_enabled )
{
@@ -2618,7 +2604,6 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
}
}
-#ifdef XXX_STINSON_CHUI_REWORK
//--------------------------------------------------------------------------------------------
// here we get the approximate head position and set as sound source for the voice symbol
// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
@@ -2636,7 +2621,6 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
tagPos[VZ] += ( mBodySize[VZ] + 0.125f );
mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );
}
-#endif // XXX_STINSON_CHUI_REWORK
}//if ( voiceEnabled )
}
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index dd529d74e9..b46c55321c 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -541,6 +541,7 @@ void LLVoiceClient::setMuteMic(bool muted)
{
mMuteMic = muted;
updateMicMuteLogic();
+ mMicroChangedSignal();
}
diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp
index d380a8672f..b497f80560 100644
--- a/indra/newview/llvoicevisualizer.cpp
+++ b/indra/newview/llvoicevisualizer.cpp
@@ -45,7 +45,6 @@
//29de489d-0491-fb00-7dab-f9e686d31e83
-#ifdef XXX_STINSON_CHUI_REWORK
//--------------------------------------------------------------------------------------
// sound symbol constants
//--------------------------------------------------------------------------------------
@@ -61,7 +60,6 @@ const F32 BASE_BRIGHTNESS = 0.7f; // gray level of the voice indicator when qu
const F32 DOT_SIZE = 0.05f; // size of the dot billboard texture
const F32 DOT_OPACITY = 0.7f; // how opaque the dot is
const F32 WAVE_MOTION_RATE = 1.5f; // scalar applied to consecutive waves as a function of speaking amplitude
-#endif // XXX_STINSON_CHUI_REWORK
//--------------------------------------------------------------------------------------
// gesticulation constants
@@ -69,13 +67,11 @@ const F32 WAVE_MOTION_RATE = 1.5f; // scalar applied to consecutive waves as a
const F32 DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE = 0.2f;
const F32 DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE = 1.0f;
-#ifdef XXX_STINSON_CHUI_REWORK
//--------------------------------------------------------------------------------------
// other constants
//--------------------------------------------------------------------------------------
const F32 ONE_HALF = 1.0f; // to clarify intent and reduce magic numbers in the code.
const LLVector3 WORLD_UPWARD_DIRECTION = LLVector3( 0.0f, 0.0f, 1.0f ); // Z is up in SL
-#endif // XXX_STINSON_CHUI_REWORK
//------------------------------------------------------------------
// Initialize the statics
@@ -98,28 +94,12 @@ F32 LLVoiceVisualizer::sAahPowerTransfersf = 0.0f;
//-----------------------------------------------
// constructor
//-----------------------------------------------
-#ifdef XXX_STINSON_CHUI_REWORK
LLVoiceVisualizer::LLVoiceVisualizer( const U8 type )
: LLHUDEffect(type)
-#else // XXX_STINSON_CHUI_REWORK
-LLVoiceVisualizer::LLVoiceVisualizer()
- : LLRefCount(),
- mTimer(),
- mStartTime(0.0),
- mCurrentlySpeaking(false),
- mSpeakingAmplitude(0.0f),
- mMaxGesticulationAmplitude(DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE),
- mMinGesticulationAmplitude(DEFAULT_MINIMUM_GESTICULATION_AMPLITUDE)
-#endif // XXX_STINSON_CHUI_REWORK
{
-#ifdef XXX_STINSON_CHUI_REWORK
mCurrentTime = mTimer.getTotalSeconds();
mPreviousTime = mCurrentTime;
mStartTime = mCurrentTime;
-#else // XXX_STINSON_CHUI_REWORK
- mStartTime = mTimer.getTotalSeconds();
-#endif // XXX_STINSON_CHUI_REWORK
-#ifdef XXX_STINSON_CHUI_REWORK
mVoiceSourceWorldPosition = LLVector3( 0.0f, 0.0f, 0.0f );
mSpeakingAmplitude = 0.0f;
mCurrentlySpeaking = false;
@@ -128,11 +108,9 @@ LLVoiceVisualizer::LLVoiceVisualizer()
mMaxGesticulationAmplitude = DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE;
mSoundSymbol.mActive = true;
mSoundSymbol.mPosition = LLVector3( 0.0f, 0.0f, 0.0f );
-#endif // XXX_STINSON_CHUI_REWORK
mTimer.reset();
-#ifdef XXX_STINSON_CHUI_REWORK
const char* sound_level_img[] =
{
"voice_meter_dot.j2c",
@@ -154,7 +132,6 @@ LLVoiceVisualizer::LLVoiceVisualizer()
}
mSoundSymbol.mTexture[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-#endif // XXX_STINSON_CHUI_REWORK
// The first instance loads the initial state from prefs.
if (!sPrefsInitialized)
@@ -174,7 +151,6 @@ LLVoiceVisualizer::LLVoiceVisualizer()
}//---------------------------------------------------
-#ifdef XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
void LLVoiceVisualizer::setMinGesticulationAmplitude( F32 m )
{
@@ -195,16 +171,13 @@ void LLVoiceVisualizer::setVoiceEnabled( bool v )
mVoiceEnabled = v;
}//---------------------------------------------------
-#endif // XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
void LLVoiceVisualizer::setStartSpeaking()
{
mStartTime = mTimer.getTotalSeconds();
mCurrentlySpeaking = true;
-#ifdef XXX_STINSON_CHUI_REWORK
mSoundSymbol.mActive = true;
-#endif // XXX_STINSON_CHUI_REWORK
}//---------------------------------------------------
@@ -359,7 +332,6 @@ void LLVoiceVisualizer::lipSyncOohAah( F32& ooh, F32& aah )
}//---------------------------------------------------
-#ifdef XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
// this method is inherited from HUD Effect
//---------------------------------------------------
@@ -558,7 +530,6 @@ void LLVoiceVisualizer::setVoiceSourceWorldPosition( const LLVector3 &p )
mVoiceSourceWorldPosition = p;
}//---------------------------------------------------
-#endif // XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
VoiceGesticulationLevel LLVoiceVisualizer::getCurrentGesticulationLevel()
@@ -589,7 +560,6 @@ LLVoiceVisualizer::~LLVoiceVisualizer()
}//----------------------------------------------
-#ifdef XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
// "packData" is inherited from HUDEffect
//---------------------------------------------------
@@ -639,5 +609,3 @@ void LLVoiceVisualizer::markDead()
LLHUDEffect::markDead();
}//------------------------------------------------------------------
-
-#endif // XXX_STINSON_CHUI_REWORK
diff --git a/indra/newview/llvoicevisualizer.h b/indra/newview/llvoicevisualizer.h
index 5da592c48e..36c78252d1 100644
--- a/indra/newview/llvoicevisualizer.h
+++ b/indra/newview/llvoicevisualizer.h
@@ -42,12 +42,7 @@
#ifndef LL_VOICE_VISUALIZER_H
#define LL_VOICE_VISUALIZER_H
-#define XXX_STINSON_CHUI_REWORK // temporarily re-enabling the in-world voice-dot
-#ifdef XXX_STINSON_CHUI_REWORK
#include "llhudeffect.h"
-#else // XXX_STINSON_CHUI_REWORK
-#include "llpointer.h"
-#endif // XXX_STINSON_CHUI_REWORK
//-----------------------------------------------------------------------------------------------
// The values of voice gesticulation represent energy levels for avatar animation, based on
@@ -65,45 +60,30 @@ enum VoiceGesticulationLevel
NUM_VOICE_GESTICULATION_LEVELS
};
-#ifdef XXX_STINSON_CHUI_REWORK
const static int NUM_VOICE_SYMBOL_WAVES = 7;
-#endif // XXX_STINSON_CHUI_REWORK
//----------------------------------------------------
// LLVoiceVisualizer class
//----------------------------------------------------
-#ifdef XXX_STINSON_CHUI_REWORK
class LLVoiceVisualizer : public LLHUDEffect
-#else // XXX_STINSON_CHUI_REWORK
-class LLVoiceVisualizer : public LLRefCount
-#endif // XXX_STINSON_CHUI_REWORK
{
//---------------------------------------------------
// public methods
//---------------------------------------------------
public:
-#ifdef XXX_STINSON_CHUI_REWORK
LLVoiceVisualizer( const U8 type ); //constructor
-#else // XXX_STINSON_CHUI_REWORK
- LLVoiceVisualizer(); //constructor
-#endif // XXX_STINSON_CHUI_REWORK
~LLVoiceVisualizer(); //destructor
-#ifdef XXX_STINSON_CHUI_REWORK
void setVoiceSourceWorldPosition( const LLVector3 &p ); // this should be the position of the speaking avatar's head
void setMinGesticulationAmplitude( F32 ); // the lower range of meaningful amplitude for setting gesticulation level
void setMaxGesticulationAmplitude( F32 ); // the upper range of meaningful amplitude for setting gesticulation level
-#endif // XXX_STINSON_CHUI_REWORK
void setStartSpeaking(); // tell me when the av starts speaking
-#ifdef XXX_STINSON_CHUI_REWORK
void setVoiceEnabled( bool ); // tell me whether or not the user is voice enabled
-#endif // XXX_STINSON_CHUI_REWORK
void setSpeakingAmplitude( F32 ); // tell me how loud the av is speaking (ranges from 0 to 1)
void setStopSpeaking(); // tell me when the av stops speaking
bool getCurrentlySpeaking(); // the get for the above set
VoiceGesticulationLevel getCurrentGesticulationLevel(); // based on voice amplitude, I'll give you the current "energy level" of avatar speech
void lipSyncOohAah( F32& ooh, F32& aah );
-#ifdef XXX_STINSON_CHUI_REWORK
void render(); // inherited from HUD Effect
void packData(LLMessageSystem *mesgsys); // inherited from HUD Effect
void unpackData(LLMessageSystem *mesgsys, S32 blocknum); // inherited from HUD Effect
@@ -119,7 +99,6 @@ class LLVoiceVisualizer : public LLRefCount
//----------------------------------------------------------------------------------------------
void setMaxGesticulationAmplitude();
void setMinGesticulationAmplitude();
-#endif // XXX_STINSON_CHUI_REWORK
//---------------------------------------------------
// private members
@@ -129,7 +108,6 @@ class LLVoiceVisualizer : public LLRefCount
static void setPreferences( );
static void lipStringToF32s ( std::string& in_string, F32*& out_F32s, U32& count_F32s ); // convert a string of digits to an array of floats
-#ifdef XXX_STINSON_CHUI_REWORK
struct SoundSymbol
{
F32 mWaveExpansion [ NUM_VOICE_SYMBOL_WAVES ];
@@ -140,20 +118,15 @@ class LLVoiceVisualizer : public LLRefCount
bool mActive;
LLVector3 mPosition;
};
-#endif // XXX_STINSON_CHUI_REWORK
LLFrameTimer mTimer; // so I can ask the current time in seconds
F64 mStartTime; // time in seconds when speaking started
-#ifdef XXX_STINSON_CHUI_REWORK
F64 mCurrentTime; // current time in seconds, captured every step
F64 mPreviousTime; // copy of "current time" from last frame
SoundSymbol mSoundSymbol; // the sound symbol that appears over the avatar's head
bool mVoiceEnabled; // if off, no rendering should happen
-#endif // XXX_STINSON_CHUI_REWORK
bool mCurrentlySpeaking; // is the user currently speaking?
-#ifdef XXX_STINSON_CHUI_REWORK
LLVector3 mVoiceSourceWorldPosition; // give this to me every step - I need it to update the sound symbol
-#endif // XXX_STINSON_CHUI_REWORK
F32 mSpeakingAmplitude; // this should be set as often as possible when the user is speaking
F32 mMaxGesticulationAmplitude; // this is the upper-limit of the envelope of detectable gesticulation leves
F32 mMinGesticulationAmplitude; // this is the lower-limit of the envelope of detectable gesticulation leves
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 05230b8bd5..0de217fc0d 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -12,6 +12,9 @@
name="EmphasisColor_35"
value="0.38 0.694 0.573 0.35" />
<color
+ name="BeaconColor"
+ value="0.749 0.298 0 1" />
+ <color
name="White"
value="1 1 1 1" />
<color
@@ -523,6 +526,9 @@
name="MenuItemHighlightBgColor"
reference="EmphasisColor_35" />
<color
+ name="MenuItemFlashBgColor"
+ reference="BeaconColor" />
+ <color
name="MenuItemHighlightFgColor"
reference="White" />
<color
diff --git a/indra/newview/skins/default/textures/bottomtray/Notices_Unread.png b/indra/newview/skins/default/textures/bottomtray/Notices_Unread.png
new file mode 100644
index 0000000000..0ac5b72b8f
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Notices_Unread.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index bf6e933dfd..a07d7e4855 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -365,6 +365,8 @@ with the same filename but different name
<texture name="Nearby_chat_icon" file_name="icons/nearby_chat_icon.png" preload="false" />
+ <texture name="Notices_Unread" file_name="bottomtray/Notices_Unread.png" preload="true" />
+
<texture name="NoEntryLines" file_name="world/NoEntryLines.png" use_mips="true" preload="false" />
<texture name="NoEntryPassLines" file_name="world/NoEntryPassLines.png" use_mips="true" preload="false" />
diff --git a/indra/newview/skins/default/xui/da/menu_notification_well_button.xml b/indra/newview/skins/default/xui/da/menu_notification_well_button.xml
new file mode 100644
index 0000000000..40b35b5fdd
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Luk alle" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/de/menu_notification_well_button.xml b/indra/newview/skins/default/xui/de/menu_notification_well_button.xml
new file mode 100644
index 0000000000..0f2784f160
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Alle schließen" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/floater_conversation_log.xml b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
index c9c52e5ce5..256e03c4d7 100644
--- a/indra/newview/skins/default/xui/en/floater_conversation_log.xml
+++ b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
@@ -1,91 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<floater
- can_resize="true"
- positioning="cascading"
- height="400"
- min_height="100"
- min_width="390"
- layout="topleft"
- name="floater_conversation_log"
- save_rect="true"
- single_instance="true"
- reuse_instance="true"
- title="CONVERSATION LOG"
- width="450">
-
+ can_resize="true"
+ positioning="cascading"
+ height="200"
+ min_height="100"
+ min_width="230"
+ layout="topleft"
+ name="floater_conversation_log"
+ save_rect="true"
+ single_instance="true"
+ reuse_instance="true"
+ title="CONVERSATION LOG"
+ width="300">
<string name="logging_calls_disabled">
Conversations are not being logged. To log conversations in the future, select "Save IM logs on my computer" under Preferences > Privacy.
</string>
-
- <panel
- follows="left|top|right"
- height="27"
- layout="topleft"
- left="0"
- name="buttons_panel"
- top="0">
- <filter_editor
- follows="left|top|right"
- height="23"
- layout="topleft"
- left="8"
- label="Filter People"
- max_length_chars="300"
- name="people_filter_input"
- text_color="Black"
- text_pad_left="10"
- top="4"
- width="364" />
- <menu_button
- follows="right"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Conv_toolbar_sort"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="5"
- menu_filename="menu_conversation_log_view.xml"
- menu_position="bottomleft"
- name="conversation_view_btn"
- tool_tip="View/sort options"
- top="3"
- width="31" />
- <menu_button
- follows="right"
- height="25"
- image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Middle_Selected"
- image_unselected="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="2"
- name="conversations_gear_btn"
- tool_tip="Actions on selected person or group"
- top="3"
- width="31" />
- </panel>
- <panel
- follows="all"
- height="370"
- layout="topleft"
- left="5"
- name="buttons_panel"
- right="-5"
- top_pad="5">
+ <panel
+ follows="left|top|right"
+ height="32"
+ left="0"
+ name="buttons_panel"
+ top="0">
+ <filter_editor
+ follows="left|top|right"
+ height="23"
+ layout="topleft"
+ left="8"
+ label="Filter People"
+ max_length_chars="300"
+ name="people_filter_input"
+ text_color="Black"
+ text_pad_left="10"
+ top="4"
+ width="204" />
+ <menu_button
+ follows="top|right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="8"
+ menu_filename="menu_conversation_log_view.xml"
+ menu_position="bottomleft"
+ name="conversation_view_btn"
+ tool_tip="View/sort options"
+ top="3"
+ width="31" />
+ <menu_button
+ follows="top|right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="8"
+ name="conversations_gear_btn"
+ tool_tip="Actions on selected person or group"
+ top="3"
+ width="31" />
+ </panel>
+ <panel
+ bottom="-1"
+ follows="all"
+ left="0"
+ name="log_panel"
+ right="-1"
+ top="32">
<conversation_log_list
- opaque="true"
- allow_select="true"
- follows="all"
- height="360"
- layout="topleft"
- left="3"
- keep_selection_visible_on_reshape="true"
- item_pad="2"
- multi_select="false"
- name="conversation_log_list"
- right="-3"
- top="5" />
- </panel>
+ allow_select="true"
+ bottom="-8"
+ opaque="true"
+ follows="all"
+ left="8"
+ keep_selection_visible_on_reshape="true"
+ item_pad="2"
+ multi_select="false"
+ name="conversation_log_list"
+ right="-8"
+ top="0" />
+ </panel>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml
index 1128b8fef6..e7638fe669 100644
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -3,9 +3,8 @@
can_close="true"
can_minimize="true"
can_resize="true"
- height="230"
+ height="210"
layout="topleft"
- min_height="50"
name="floater_im_box"
help_topic="floater_im_box"
save_rect="true"
@@ -24,22 +23,20 @@
value="Conv_toolbar_expand"/>
<layout_stack
animate="true"
+ bottom="-1"
follows="all"
- height="230"
layout="topleft"
left="0"
name="conversations_stack"
orientation="horizontal"
- top="0"
- width="450">
+ right="-1"
+ top="0">
<layout_panel
auto_resize="false"
user_resize="true"
- height="430"
name="conversations_layout_panel"
min_dim="38"
- width="268"
- expanded_min_dim="120">
+ expanded_min_dim="156">
<layout_stack
animate="false"
follows="left|top|right"
@@ -48,8 +45,8 @@
left="0"
name="conversations_pane_buttons_stack"
orientation="horizontal"
- top="0"
- width="268">
+ right="-1"
+ top="0">
<layout_panel
auto_resize="true"
height="35"
@@ -109,46 +106,44 @@
image_unselected="Toolbar_Middle_Off"
layout="topleft"
top="5"
- left="5"
+ left="1"
name="expand_collapse_btn"
tool_tip="Collapse/Expand this list"
width="31" />
</layout_panel>
</layout_stack>
<panel
+ bottom="-5"
follows="all"
layout="topleft"
name="conversations_list_panel"
opaque="true"
- top_pad="0"
+ top="35"
left="5"
- height="390"
- width="263"/>
+ right="-1"/>
</layout_panel>
<layout_panel
auto_resize="true"
user_resize="true"
- height="430"
name="messages_layout_panel"
- width="412"
- expanded_min_dim="225">
+ expanded_min_dim="222">
<panel_container
+ bottom="-5"
follows="all"
- height="430"
layout="topleft"
left="0"
name="im_box_tab_container"
- top="0"
- width="412">
+ right="-1"
+ top="0">
<panel
+ bottom="-1"
follows="all"
layout="topleft"
name="stub_panel"
opaque="true"
top_pad="0"
left="0"
- height="430"
- width="412">
+ right="-1">
<button
follows="right|top"
height="25"
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index e4b127b7b9..8f0574177f 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -49,6 +49,15 @@
<floater.string
name="end_call_button_tooltip"
value="Close voice connection"/>
+ <floater.string
+ name="expcol_button_not_tearoff_tooltip"
+ value="Collapse this pane"/>
+ <floater.string
+ name="expcol_button_tearoff_and_expanded_tooltip"
+ value="Collapse participant list"/>
+ <floater.string
+ name="expcol_button_tearoff_and_collapsed_tooltip"
+ value="Expand participant list"/>
<view
follows="all"
layout="topleft"
@@ -79,6 +88,21 @@
tool_tip="View/sort options"
top="5"
width="31" />
+ <menu_button
+ menu_filename="menu_im_conversation.xml"
+ follows="top|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ top="5"
+ left_pad="4"
+ name="gear_btn"
+ visible="false"
+ tool_tip="Actions on selected person"
+ width="31"/>
<button
enabled="false"
follows="top|left"
@@ -191,7 +215,7 @@
auto_resize="true"
visible="true"
name="left_part_holder"
- min_width="225">
+ min_width="221">
<panel
name="trnsAndChat_panel"
follows="all"
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
index e0edf384d6..46c6e19fa5 100644
--- a/indra/newview/skins/default/xui/en/menu_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -76,6 +76,13 @@
<on_enable function="Avatar.EnableItem" parameter="can_delete" />
</menu_item_call>
<menu_item_call
+ label="Remove friends"
+ layout="topleft"
+ name="remove_friends">
+ <on_click function="Avatar.DoToSelected" parameter="remove_friend" />
+ <on_enable function="Avatar.EnableItem" parameter="can_delete" />
+ </menu_item_call>
+ <menu_item_call
label="Invite to group..."
layout="topleft"
name="invite_to_group">
diff --git a/indra/newview/skins/default/xui/en/menu_im_conversation.xml b/indra/newview/skins/default/xui/en/menu_im_conversation.xml
new file mode 100644
index 0000000000..8882d0a7d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_im_conversation.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Conversation Gear Menu">
+ <menu_item_call
+ label="View Profile"
+ layout="topleft"
+ name="View Profile">
+ <on_click function="Avatar.GearDoToSelected" parameter="view_profile" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_view_profile" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add Friend"
+ layout="topleft"
+ name="Add Friend">
+ <on_click function="Avatar.GearDoToSelected" parameter="add_friend" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove friend"
+ layout="topleft"
+ name="remove_friend">
+ <on_click function="Avatar.GearDoToSelected" parameter="remove_friend" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Offer teleport"
+ layout="topleft"
+ name="offer_teleport">
+ <on_click function="Avatar.GearDoToSelected" parameter="offer_teleport"/>
+ <on_enable function="Avatar.EnableGearItem" parameter="can_offer_teleport"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Invite to group..."
+ layout="topleft"
+ name="invite_to_group">
+ <on_click function="Avatar.GearDoToSelected" parameter="invite_to_group" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_invite" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="View Icons Separator" />
+ <menu_item_call
+ label="Chat history..."
+ layout="topleft"
+ name="chat_history">
+ <on_click function="Avatar.GearDoToSelected" parameter="chat_history"/>
+ <on_enable function="Avatar.EnableGearItem" parameter="can_chat_history"/>
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"/>
+ <menu_item_call
+ label="Map"
+ layout="topleft"
+ name="map">
+ <on_click function="Avatar.GearDoToSelected" parameter="map" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_show_on_map" />
+ </menu_item_call>
+ <menu_item_call
+ label="Share"
+ layout="topleft"
+ name="Share">
+ <on_click function="Avatar.GearDoToSelected" parameter="share" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_share" />
+ </menu_item_call>
+ <menu_item_call
+ label="Pay"
+ layout="topleft"
+ name="Pay">
+ <on_click function="Avatar.GearDoToSelected" parameter="pay" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_pay" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"/>
+ <menu_item_check
+ label="Block Voice"
+ layout="topleft"
+ name="Block/Unblock">
+ <on_check function="Avatar.CheckGearItem" parameter="is_blocked" />
+ <on_click function="Avatar.GearDoToSelected" parameter="block_unblock" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_block" />
+ </menu_item_check>
+ <menu_item_check
+ label="Block Text"
+ layout="topleft"
+ name="MuteText">
+ <on_check function="Avatar.CheckGearItem" parameter="is_muted" />
+ <on_click function="Avatar.GearDoToSelected" parameter="mute_unmute" />
+ <on_enable function="Avatar.EnableGearItem" parameter="can_block" />
+ </menu_item_check>
+ <menu_item_separator
+ layout="topleft"/>
+</toggleable_menu>
+
diff --git a/indra/newview/skins/default/xui/en/menu_notification_well_button.xml b/indra/newview/skins/default/xui/en/menu_notification_well_button.xml
new file mode 100644
index 0000000000..263ac40f4e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_notification_well_button.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Notification Well Button Context Menu">
+ <menu_item_call
+ label="Close All"
+ layout="topleft"
+ name="Close All">
+ <menu_item_call.on_click
+ function="NotificationWellChicletMenu.Action"
+ parameter="close all" />
+ <menu_item_call.on_enable
+ function="NotificationWellChicletMenu.EnableItem"
+ parameter="can close all" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 3e7329c0b5..76de81559b 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1267,7 +1267,58 @@
function="Floater.Show"
parameter="hud" />
</menu_item_call>-->
-
+ <menu_item_separator/>
+
+ <menu_item_call
+ label="User’s guide"
+ name="User’s guide">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-User-s-Guide/ta-p/1244857"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Knowledge Base"
+ name="Knowledge Base">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://community.secondlife.com/t5/tkb/communitypage"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Wiki"
+ name="Wiki">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://wiki.secondlife.com"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Community Forums"
+ name="Community Forums">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://community.secondlife.com/t5/Forums/ct-p/Forums"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Support portal"
+ name="Support portal">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="https://support.secondlife.com/"/>
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
+ label="[SECOND_LIFE] News"
+ name="Second Life News">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://community.secondlife.com/t5/Featured-News/bg-p/blog_feature_news"/>
+ </menu_item_call>
+ <menu_item_call
+ label="[SECOND_LIFE] Blogs"
+ name="Second Life Blogs">
+ <menu_item_call.on_click
+ function="Advanced.ShowURL"
+ parameter="http://community.secondlife.com/t5/Blogs/ct-p/Blogs"/>
+ </menu_item_call>
<menu_item_separator/>
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 94307d2f93..05798da8e2 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3696,7 +3696,6 @@ Do Not Disturb is on. You will not be notified of incoming communications.
- Other residents will receive your Do Not Disturb response (set in Preferences &gt; General).
- Teleportation offers will be declined.
- Voice calls will be rejected.
-- Inventory offers will go to your Trash.
<usetemplate
ignoretext="I change my status to Do Not Disturb mode"
name="okignore"
@@ -6584,7 +6583,7 @@ However, this region contains content accessible to adults only.
log_to_im="true"
log_to_chat="false"
show_toast="false"
- type="offer">
+ type="notify">
Teleport offer sent to [TO_NAME]
</notification>
@@ -6637,7 +6636,7 @@ However, this region contains content accessible to adults only.
name="FriendshipOffered"
log_to_im="true"
show_toast="false"
- type="offer">
+ type="notify">
<tag>friendship</tag>
You have offered friendship to [TO_NAME]
</notification>
@@ -6667,7 +6666,7 @@ However, this region contains content accessible to adults only.
icon="notify.tga"
name="FriendshipAccepted"
log_to_im="true"
- type="offer">
+ type="notify">
<tag>friendship</tag>
&lt;nolink&gt;[NAME]&lt;/nolink&gt; accepted your friendship offer.
</notification>
@@ -6687,7 +6686,7 @@ However, this region contains content accessible to adults only.
name="FriendshipAcceptedByMe"
log_to_im="true"
show_toast="false"
- type="offer">
+ type="notify">
<tag>friendship</tag>
Friendship offer accepted.
</notification>
@@ -6697,7 +6696,7 @@ Friendship offer accepted.
name="FriendshipDeclinedByMe"
log_to_im="true"
show_toast="false"
- type="offer">
+ type="notify">
<tag>friendship</tag>
Friendship offer declined.
</notification>
diff --git a/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
index 390047d493..fc321fdd23 100644
--- a/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
@@ -77,5 +77,49 @@
width="12" />
</chiclet_panel>
</layout_panel>
+ <layout_panel auto_resize="false"
+ width="4"
+ min_width="4"/>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="37"
+ name="notification_well_panel"
+ top="0"
+ width="37">
+ <chiclet_notification
+ follows="right"
+ height="23"
+ layout="topleft"
+ left="0"
+ max_displayed_count="99"
+ name="notification_well"
+ top="5"
+ width="35">
+ <button
+ auto_resize="false"
+ bottom_pad="3"
+ follows="right"
+ halign="center"
+ height="23"
+ image_overlay="Notices_Unread"
+ image_overlay_alignment="center"
+ image_pressed="WellButton_Lit"
+ image_pressed_selected="WellButton_Lit_Selected"
+ image_selected="PushButton_Press"
+ label_color="Black"
+ left="0"
+ name="Unread"
+ tool_tip="Notifications"
+ width="34">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="notification_well_window" />
+ </button>
+ </chiclet_notification>
+ </layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/widgets/toolbar.xml b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
index 053b213ef4..0ace37a5dc 100644
--- a/indra/newview/skins/default/xui/en/widgets/toolbar.xml
+++ b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
@@ -30,9 +30,9 @@
image_overlay_alignment="left"
use_ellipses="true"
auto_resize="true"
- button_flash_count="3"
- button_flash_rate="0.25"
- flash_color="EmphasisColor"/>
+ button_flash_count="4"
+ button_flash_rate="0.5"
+ flash_color="BeaconColor"/>
<button_icon pad_left="10"
pad_right="10"
image_bottom_pad="10"
@@ -51,7 +51,7 @@
chrome="true"
use_ellipses="true"
auto_resize="true"
- button_flash_count="3"
- button_flash_rate="0.25"
- flash_color="EmphasisColor"/>
+ button_flash_count="4"
+ button_flash_rate="0.5"
+ flash_color="BeaconColor"/>
</toolbar>
diff --git a/indra/newview/skins/default/xui/es/menu_notification_well_button.xml b/indra/newview/skins/default/xui/es/menu_notification_well_button.xml
new file mode 100644
index 0000000000..0562d35be7
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Cerrar todo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_notification_well_button.xml b/indra/newview/skins/default/xui/fr/menu_notification_well_button.xml
new file mode 100644
index 0000000000..323bfdbf16
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Tout fermer" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/it/menu_notification_well_button.xml b/indra/newview/skins/default/xui/it/menu_notification_well_button.xml
new file mode 100644
index 0000000000..8c82e30f0e
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Chiudi tutto" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/ja/menu_notification_well_button.xml b/indra/newview/skins/default/xui/ja/menu_notification_well_button.xml
new file mode 100644
index 0000000000..913bae8958
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="すべて閉じる" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/pl/menu_notification_well_button.xml b/indra/newview/skins/default/xui/pl/menu_notification_well_button.xml
new file mode 100644
index 0000000000..bd3d42f9b1
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Zamknij" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_notification_well_button.xml b/indra/newview/skins/default/xui/pt/menu_notification_well_button.xml
new file mode 100644
index 0000000000..43ad4134ec
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Fechar tudo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/ru/menu_notification_well_button.xml b/indra/newview/skins/default/xui/ru/menu_notification_well_button.xml
new file mode 100644
index 0000000000..4d067e232a
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Закрыть все" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/tr/menu_notification_well_button.xml b/indra/newview/skins/default/xui/tr/menu_notification_well_button.xml
new file mode 100644
index 0000000000..39c66268f5
--- /dev/null
+++ b/indra/newview/skins/default/xui/tr/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Tümünü Kapat" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/zh/menu_notification_well_button.xml b/indra/newview/skins/default/xui/zh/menu_notification_well_button.xml
new file mode 100644
index 0000000000..b629f73584
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="全部關閉" name="Close All"/>
+</context_menu>