summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/settings.xml6
-rw-r--r--indra/newview/llagentwearables.cpp10
-rw-r--r--indra/newview/llappearancemgr.cpp2
-rw-r--r--indra/newview/llappviewer.cpp32
-rw-r--r--indra/newview/llassetuploadresponders.cpp5
-rw-r--r--indra/newview/llchathistory.cpp22
-rw-r--r--indra/newview/llchathistory.h9
-rw-r--r--indra/newview/llchiclet.cpp2
-rw-r--r--indra/newview/llfloaterbuy.cpp3
-rw-r--r--indra/newview/llfloaterbuycurrency.cpp3
-rw-r--r--indra/newview/llfloaterpreference.cpp31
-rw-r--r--indra/newview/llfloaterreporter.cpp5
-rw-r--r--indra/newview/llimfloater.cpp51
-rw-r--r--indra/newview/llimview.cpp38
-rw-r--r--indra/newview/llimview.h11
-rw-r--r--indra/newview/llinventorybridge.cpp7
-rw-r--r--indra/newview/llinventoryobserver.cpp1
-rw-r--r--indra/newview/llmutelist.cpp52
-rw-r--r--indra/newview/llmutelist.h10
-rw-r--r--indra/newview/llnearbychathandler.cpp33
-rw-r--r--indra/newview/llnotificationhandler.h32
-rw-r--r--indra/newview/llnotificationhandlerutil.cpp149
-rw-r--r--indra/newview/llnotificationofferhandler.cpp59
-rw-r--r--indra/newview/llnotificationtiphandler.cpp6
-rw-r--r--indra/newview/llpanelavatar.cpp11
-rw-r--r--indra/newview/llpanelavatar.h1
-rw-r--r--indra/newview/llpanelblockedlist.cpp13
-rw-r--r--indra/newview/llpanelclassified.cpp6
-rw-r--r--indra/newview/llpanelobjectinventory.cpp20
-rw-r--r--indra/newview/llpanelplaceprofile.cpp8
-rw-r--r--indra/newview/llpanelplaces.cpp5
-rw-r--r--indra/newview/llprogressview.cpp26
-rw-r--r--indra/newview/llprogressview.h2
-rw-r--r--indra/newview/llscreenchannel.cpp4
-rw-r--r--indra/newview/llscrollingpanelparam.cpp12
-rw-r--r--indra/newview/llspeakers.cpp1
-rw-r--r--indra/newview/lltexturefetch.cpp2
-rw-r--r--indra/newview/lltoastnotifypanel.cpp201
-rw-r--r--indra/newview/lltoastnotifypanel.h34
-rw-r--r--indra/newview/lltooldraganddrop.cpp38
-rw-r--r--indra/newview/lltooldraganddrop.h4
-rw-r--r--indra/newview/llviewermedia.cpp115
-rw-r--r--indra/newview/llviewermedia.h12
-rw-r--r--indra/newview/llviewermenu.cpp16
-rw-r--r--indra/newview/llviewermenufile.cpp12
-rw-r--r--indra/newview/llviewermessage.cpp82
-rw-r--r--indra/newview/llviewermessage.h2
-rw-r--r--indra/newview/llviewerobject.cpp3
-rw-r--r--indra/newview/llviewertexteditor.cpp5
-rw-r--r--indra/newview/llviewertexture.cpp3
-rw-r--r--indra/newview/llviewerwindow.cpp6
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Object_Multi.pngbin0 -> 774 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml1
-rw-r--r--indra/newview/skins/default/xui/de/panel_bottomtray.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_currency.xml2
-rw-r--r--indra/newview/skins/default/xui/en/main_view.xml18
-rw-r--r--indra/newview/skins/default/xui/en/menu_profile_overflow.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_bottomtray.xml7
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_prim_media_controls.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml35
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml47
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chat_history.xml1
64 files changed, 1079 insertions, 278 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 8edf766132..97c8cbfa7b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10347,7 +10347,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
<key>VivoxDebugLevel</key>
<map>
@@ -10655,7 +10655,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
- <integer>700</integer>
+ <integer>738</integer>
</map>
<key>WindowMaximized</key>
<map>
@@ -10677,7 +10677,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
- <integer>1000</integer>
+ <integer>1024</integer>
</map>
<key>WindowX</key>
<map>
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 65503d4998..ebadd8a165 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -443,6 +443,11 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B
new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()?
setWearable(type,index,new_wearable);
+ // old_wearable may still be referred to by other inventory items. Revert
+ // unsaved changes so other inventory items aren't affected by the changes
+ // that were just saved.
+ old_wearable->revertValues();
+
LLInventoryItem* item = gInventory.getItem(old_item_id);
if (item)
{
@@ -545,6 +550,11 @@ void LLAgentWearables::saveWearableAs(const EWearableType type,
category_id,
new_name,
cb);
+
+ // old_wearable may still be referred to by other inventory items. Revert
+ // unsaved changes so other inventory items aren't affected by the changes
+ // that were just saved.
+ old_wearable->revertValues();
}
void LLAgentWearables::revertWearable(const EWearableType type, const U32 index)
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index f2d15757c9..b3dfb8f141 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -399,7 +399,7 @@ bool LLWearableHoldingPattern::isFetchCompleted()
bool LLWearableHoldingPattern::isTimedOut()
{
- static F32 max_wait_time = 20.0; // give up if wearable fetches haven't completed in max_wait_time seconds.
+ static F32 max_wait_time = 60.0; // give up if wearable fetches haven't completed in max_wait_time seconds.
return mWaitTime.getElapsedTimeF32() > max_wait_time;
}
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 2384e6c5ba..11c252406a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -304,10 +304,7 @@ static std::string gLaunchFileOnQuit;
// Used on Win32 for other apps to identify our window (eg, win_setup)
const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
-static const S32 FIRST_RUN_WINDOW_WIDTH = 1024;
-//should account for Windows task bar
-static const S32 FIRST_RUN_WINDOW_HIGHT = 738;
//----------------------------------------------------------------------------
// List of entries from strings.xml to always replace
@@ -2374,35 +2371,12 @@ bool LLAppViewer::initWindow()
// store setting in a global for easy access and modification
gNoRender = gSavedSettings.getBOOL("DisableRendering");
- S32 window_x = gSavedSettings.getS32("WindowX");
- S32 window_y = gSavedSettings.getS32("WindowY");
- S32 window_width = gSavedSettings.getS32("WindowWidth");
- S32 window_height = gSavedSettings.getS32("WindowHeight");
-
- bool show_maximized = gSavedSettings.getBOOL("WindowMaximized");
-
- bool first_run = gSavedSettings.getBOOL("FirstLoginThisInstall");
-
- if (first_run)//for first login
- {
- window_width = FIRST_RUN_WINDOW_WIDTH;//yep hardcoded
- window_height = FIRST_RUN_WINDOW_HIGHT;
-
- //if screen resolution is lower then first run width/height then show maximized
- LLDisplayInfo display_info;
- if(display_info.getDisplayWidth() <= FIRST_RUN_WINDOW_WIDTH
- || display_info.getDisplayHeight()<=FIRST_RUN_WINDOW_HIGHT)
- {
- show_maximized = true;
- }
- }
-
// always start windowed
BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
gViewerWindow = new LLViewerWindow(gWindowTitle,
VIEWER_WINDOW_CLASSNAME,
- window_x, window_y,
- window_width, window_height,
+ gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
+ gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
FALSE, ignorePixelDepth);
LLNotificationsUI::LLNotificationManager::getInstance();
@@ -2413,7 +2387,7 @@ bool LLAppViewer::initWindow()
gViewerWindow->toggleFullscreen(FALSE);
}
- if (show_maximized)
+ if (gSavedSettings.getBOOL("WindowMaximized"))
{
gViewerWindow->mWindow->maximize();
gViewerWindow->getWindow()->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 80cf8f1d61..8441796219 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -182,7 +182,10 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)
// deal with L$ errors
if (reason == "insufficient funds")
{
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs"), LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
+ S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs", args), price);
}
else
{
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 78b258a82d..a0ce773f96 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -447,6 +447,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
: LLUICtrl(p),
mMessageHeaderFilename(p.message_header),
mMessageSeparatorFilename(p.message_separator),
+ mMessagePlaintextSeparatorFilename(p.message_plaintext_separator),
mLeftTextPad(p.left_text_pad),
mRightTextPad(p.right_text_pad),
mLeftWidgetPad(p.left_widget_pad),
@@ -534,6 +535,12 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
+LLView* LLChatHistory::getPlaintextSeparator()
+{
+ LLPanel* separator = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessagePlaintextSeparatorFilename, NULL, LLPanel::child_registry_t::instance());
+ return separator;
+}
+
LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params)
{
LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
@@ -632,6 +639,15 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
if (use_plain_text_chat_history)
{
+ // append plaintext separator
+ LLView* separator = getPlaintextSeparator();
+ LLInlineViewSegment::Params p;
+ p.force_newline = true;
+ p.left_pad = mLeftWidgetPad;
+ p.right_pad = mRightWidgetPad;
+ p.view = separator;
+ mEditor->appendWidget(p, "\n", false);
+
mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getText().size() != 0, style_params);
if (utf8str_trim(chat.mFromName).size() != 0)
@@ -734,7 +750,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
LLNotificationPtr notification = LLNotificationsUtil::find(chat.mNotifId);
if (notification != NULL)
{
- LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(
+ LLIMToastNotifyPanel* notify_box = new LLIMToastNotifyPanel(
notification);
//we can't set follows in xml since it broke toasts behavior
notify_box->setFollowsLeft();
@@ -743,7 +759,9 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
ctrl_list_t ctrls = notify_box->getControlPanel()->getCtrlList();
S32 offset = 0;
- for (ctrl_list_t::iterator it = ctrls.begin(); it != ctrls.end(); it++)
+ // Children were added by addChild() which uses push_front to insert them into list,
+ // so to get buttons in correct order reverse iterator is used (EXT-5906)
+ for (ctrl_list_t::reverse_iterator it = ctrls.rbegin(); it != ctrls.rend(); it++)
{
LLButton * button = dynamic_cast<LLButton*> (*it);
if (button != NULL)
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index 950b32861b..dfe5ea98e6 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -47,6 +47,8 @@ class LLChatHistory : public LLUICtrl
Optional<std::string> message_header;
//Message separator filename
Optional<std::string> message_separator;
+ //Message plaintext separator filename
+ Optional<std::string> message_plaintext_separator;
//Text left padding from the scroll rect
Optional<S32> left_text_pad;
//Text right padding from the scroll rect
@@ -69,6 +71,7 @@ class LLChatHistory : public LLUICtrl
Params()
: message_header("message_header"),
message_separator("message_separator"),
+ message_plaintext_separator("message_plaintext_separator"),
left_text_pad("left_text_pad"),
right_text_pad("right_text_pad"),
left_widget_pad("left_widget_pad"),
@@ -97,6 +100,11 @@ class LLChatHistory : public LLUICtrl
*/
LLView* getSeparator();
/**
+ * Builds a message plaintext separator.
+ * @return pointer to LLView separator object.
+ */
+ LLView* getPlaintextSeparator();
+ /**
* Builds a message header.
* @return pointer to LLView header object.
*/
@@ -133,6 +141,7 @@ class LLChatHistory : public LLUICtrl
std::string mMessageHeaderFilename;
std::string mMessageSeparatorFilename;
+ std::string mMessagePlaintextSeparatorFilename;
S32 mLeftTextPad;
S32 mRightTextPad;
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 8efa814a2e..1f92686a43 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -1137,7 +1137,7 @@ void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
S32 unread = data["participant_unread"].asInteger();
LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
- if (im_floater && im_floater->getVisible())
+ if (im_floater && im_floater->getVisible() && im_floater->hasFocus())
{
unread = 0;
}
diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp
index fba557c656..589f570d96 100644
--- a/indra/newview/llfloaterbuy.cpp
+++ b/indra/newview/llfloaterbuy.cpp
@@ -246,7 +246,8 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj,
// Compute icon for this item
BOOL item_is_multi = FALSE;
- if ( inv_item->getFlags() & LLInventoryItem::II_FLAGS_LANDMARK_VISITED )
+ if ( inv_item->getFlags() & LLInventoryItem::II_FLAGS_LANDMARK_VISITED
+ || inv_item->getFlags() & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
{
item_is_multi = TRUE;
}
diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp
index 1642e6725e..7fddd1fc5f 100644
--- a/indra/newview/llfloaterbuycurrency.cpp
+++ b/indra/newview/llfloaterbuycurrency.cpp
@@ -234,8 +234,7 @@ void LLFloaterBuyCurrencyUI::updateUI()
if (mHasTarget)
{
childSetVisible("buy_action", true);
- childSetTextArg("buy_action", "[NAME]", mTargetName);
- childSetTextArg("buy_action", "[PRICE]", llformat("%d",mTargetPrice));
+ childSetTextArg("buy_action", "[ACTION]", mTargetName);
}
}
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index e998d10fcc..3487f52f35 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -183,7 +183,6 @@ void LLVoiceSetKeyDialog::onCancel(void* user_data)
// a static member and update all our static callbacks
void handleNameTagOptionChanged(const LLSD& newvalue);
-viewer_media_t get_web_media();
bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response);
//bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater);
@@ -191,23 +190,14 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response
void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator);
-viewer_media_t get_web_media()
-{
- viewer_media_t media_source = LLViewerMedia::newMediaImpl(LLUUID::null);
- media_source->initializeMedia("text/html");
- return media_source;
-}
-
-
bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if ( option == 0 ) // YES
{
// clean web
- viewer_media_t media_source = get_web_media();
- if (media_source && media_source->hasMedia())
- media_source->getMediaPlugin()->clear_cache();
+ LLViewerMedia::clearAllCaches();
+ LLViewerMedia::clearAllCookies();
// clean nav bar history
LLNavigationBar::getInstance()->clearHistoryCache();
@@ -429,17 +419,14 @@ void LLFloaterPreference::apply()
std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "");
childSetText("cache_location", cache_location);
- viewer_media_t media_source = get_web_media();
- if (media_source && media_source->hasMedia())
+ LLViewerMedia::setCookiesEnabled(childGetValue("cookies_enabled"));
+
+ if(hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port"))
{
- media_source->getMediaPlugin()->enable_cookies(childGetValue("cookies_enabled"));
- if(hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port"))
- {
- bool proxy_enable = childGetValue("web_proxy_enabled");
- std::string proxy_address = childGetValue("web_proxy_editor");
- int proxy_port = childGetValue("web_proxy_port");
- media_source->getMediaPlugin()->proxy_setup(proxy_enable, proxy_address, proxy_port);
- }
+ bool proxy_enable = childGetValue("web_proxy_enabled");
+ std::string proxy_address = childGetValue("web_proxy_editor");
+ int proxy_port = childGetValue("web_proxy_port");
+ LLViewerMedia::setProxyConfig(proxy_enable, proxy_address, proxy_port);
}
// LLWString busy_response = utf8str_to_wstring(getChild<LLUICtrl>("busy_response")->getValue().asString());
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 0f3c176cea..42a7eeff26 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -84,6 +84,8 @@
#include "llassetuploadresponders.h"
#include "llagentui.h"
+#include "lltrans.h"
+
const U32 INCLUDE_SCREENSHOT = 0x01 << 0;
//-----------------------------------------------------------------------------
@@ -372,8 +374,7 @@ void LLFloaterReporter::onClickSend(void *userdata)
return;
}
-
- LLUploadDialog::modalUploadDialog("Uploading...\n\nReport");
+ LLUploadDialog::modalUploadDialog(LLTrans::getString("uploading_abuse_report"));
// *TODO don't upload image if checkbox isn't checked
std::string url = gAgent.getRegion()->getCapability("SendUserReport");
std::string sshot_url = gAgent.getRegion()->getCapability("SendUserReportWithScreenshot");
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 77eaebb0bc..91f4f57e54 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -128,6 +128,11 @@ void LLIMFloater::onFocusReceived()
LLIMModel::getInstance()->setActiveSessionID(mSessionID);
LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true);
+
+ if (getVisible())
+ {
+ LLIMModel::instance().sendNoUnreadMessages(mSessionID);
+ }
}
// virtual
@@ -454,7 +459,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect)
void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
{
// update notification channel state
- LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>
+ LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
@@ -473,7 +478,7 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
void LLIMFloater::setVisible(BOOL visible)
{
- LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>
+ LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
LLTransientDockableFloater::setVisible(visible);
@@ -609,7 +614,16 @@ void LLIMFloater::updateMessages()
bool use_plain_text_chat_history = gSavedSettings.getBOOL("PlainTextChatHistory");
std::list<LLSD> messages;
- LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);
+
+ // we shouldn't reset unread message counters if IM floater doesn't have focus
+ if (hasFocus())
+ {
+ LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);
+ }
+ else
+ {
+ LLIMModel::instance().getMessagesSilently(mSessionID, messages, mLastMessageIndex+1);
+ }
if (messages.size())
{
@@ -642,6 +656,24 @@ void LLIMFloater::updateMessages()
if (msg.has("notification_id"))
{
chat.mNotifId = msg["notification_id"].asUUID();
+ // if notification exists - embed it
+ if (LLNotificationsUtil::find(chat.mNotifId) != NULL)
+ {
+ // remove embedded notification from channel
+ LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
+ (LLNotificationsUI::LLChannelManager::getInstance()->
+ findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+ if (getVisible())
+ {
+ // toast will be automatically closed since it is not storable toast
+ channel->hideToast(chat.mNotifId);
+ }
+ }
+ // if notification doesn't exist - try to use next message which should be log entry
+ else
+ {
+ continue;
+ }
}
//process text message
else
@@ -651,6 +683,19 @@ void LLIMFloater::updateMessages()
mChatHistory->appendMessage(chat, chat_args);
mLastMessageIndex = msg["index"].asInteger();
+
+ // if it is a notification - next message is a notification history log, so skip it
+ if (chat.mNotifId.notNull() && LLNotificationsUtil::find(chat.mNotifId) != NULL)
+ {
+ if (++iter == iter_end)
+ {
+ break;
+ }
+ else
+ {
+ mLastMessageIndex++;
+ }
+ }
}
}
}
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index b3f085ef6d..7a4febec20 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -608,10 +608,10 @@ bool LLIMModel::clearSession(const LLUUID& session_id)
return true;
}
-void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
+void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
{
LLIMSession* session = findIMSession(session_id);
- if (!session)
+ if (!session)
{
llwarns << "session " << session_id << "does not exist " << llendl;
return;
@@ -619,7 +619,7 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
int i = session->mMsgs.size() - start_index;
- for (std::list<LLSD>::iterator iter = session->mMsgs.begin();
+ for (std::list<LLSD>::iterator iter = session->mMsgs.begin();
iter != session->mMsgs.end() && i > 0;
iter++)
{
@@ -628,6 +628,16 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
messages.push_back(*iter);
i--;
}
+}
+
+void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)
+{
+ LLIMSession* session = findIMSession(session_id);
+ if (!session)
+ {
+ llwarns << "session " << session_id << "does not exist " << llendl;
+ return;
+ }
session->mNumUnread = 0;
session->mParticipantUnreadMessageCount = 0;
@@ -639,6 +649,13 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
mNoUnreadMsgsSignal(arg);
}
+void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
+{
+ getMessagesSilently(session_id, messages, start_index);
+
+ sendNoUnreadMessages(session_id);
+}
+
bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {
LLIMSession* session = findIMSession(session_id);
@@ -717,13 +734,22 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
return NULL;
}
- addToHistory(session_id, from, from_id, utf8_text);
- if (log2file) logToFile(session_id, from, from_id, utf8_text);
+ // replace interactive system message marker with correct from string value
+ std::string from_name = from;
+ if (INTERACTIVE_SYSTEM_FROM == from)
+ {
+ from_name = SYSTEM_FROM;
+ }
+
+ addToHistory(session_id, from_name, from_id, utf8_text);
+ if (log2file) logToFile(session_id, from_name, from_id, utf8_text);
session->mNumUnread++;
//update count of unread messages from real participant
- if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from))
+ if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from)
+ // we should increment counter for interactive system messages()
+ || INTERACTIVE_SYSTEM_FROM == from)
{
++(session->mParticipantUnreadMessageCount);
}
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index e7404074e0..f1693d0e17 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -178,6 +178,17 @@ public:
bool clearSession(const LLUUID& session_id);
/**
+ * Populate supplied std::list with messages starting from index specified by start_index without
+ * emitting no unread messages signal.
+ */
+ void getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0);
+
+ /**
+ * Sends no unread messages signal.
+ */
+ void sendNoUnreadMessages(const LLUUID& session_id);
+
+ /**
* Populate supplied std::list with messages starting from index specified by start_index
*/
void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 1f918c72ea..6fedd9ac4d 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -103,7 +103,7 @@ std::string ICON_NAME[ICON_NAME_COUNT] =
"Inv_Script",
"Inv_Clothing",
"Inv_Object",
- "Inv_Object",
+ "Inv_Object_Multi",
"Inv_Notecard",
"Inv_Skin",
"Inv_Snapshot",
@@ -5358,7 +5358,10 @@ LLUIImagePtr LLLinkItemBridge::getIcon() const
{
if (LLViewerInventoryItem *item = getItem())
{
- return get_item_icon(item->getActualType(), item->getInventoryType(), 0, FALSE);
+ U32 attachment_point = (item->getFlags() & 0xff); // low byte of inventory flags
+ bool is_multi = LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags();
+
+ return get_item_icon(item->getActualType(), item->getInventoryType(), attachment_point, is_multi);
}
return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE);
}
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 2fb8aea4e9..62c2d80609 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -54,7 +54,6 @@
#include "llappviewer.h"
#include "lldbstrings.h"
#include "llviewerstats.h"
-#include "llmutelist.h"
#include "llnotificationsutil.h"
#include "llcallbacklist.h"
#include "llpreview.h"
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 2d3c4b187e..95094f6b52 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -128,68 +128,26 @@ LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)
}
-std::string LLMute::getDisplayName() const
+std::string LLMute::getDisplayType() const
{
- std::string name_with_suffix = mName;
switch (mType)
{
case BY_NAME:
default:
- name_with_suffix += " " + LLTrans::getString("MuteByName");
+ return LLTrans::getString("MuteByName");
break;
case AGENT:
- name_with_suffix += " " + LLTrans::getString("MuteAgent");
+ return LLTrans::getString("MuteAgent");
break;
case OBJECT:
- name_with_suffix += " " + LLTrans::getString("MuteObject");
+ return LLTrans::getString("MuteObject");
break;
case GROUP:
- name_with_suffix += " " + LLTrans::getString("MuteGroup");
+ return LLTrans::getString("MuteGroup");
break;
}
- return name_with_suffix;
}
-void LLMute::setFromDisplayName(const std::string& display_name)
-{
- size_t pos = 0;
- mName = display_name;
-
- pos = mName.rfind(" " + LLTrans::getString("MuteGroup"));
- if (pos != std::string::npos)
- {
- mName.erase(pos);
- mType = GROUP;
- return;
- }
-
- pos = mName.rfind(" " + LLTrans::getString("MuteObject"));
- if (pos != std::string::npos)
- {
- mName.erase(pos);
- mType = OBJECT;
- return;
- }
-
- pos = mName.rfind(" " + LLTrans::getString("MuteAgent"));
- if (pos != std::string::npos)
- {
- mName.erase(pos);
- mType = AGENT;
- return;
- }
-
- pos = mName.rfind(" " + LLTrans::getString("MuteByName"));
- if (pos != std::string::npos)
- {
- mName.erase(pos);
- mType = BY_NAME;
- return;
- }
-
- llwarns << "Unable to set mute from display name " << display_name << llendl;
- return;
-}
/* static */
LLMuteList* LLMuteList::getInstance()
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index e1e81a24b4..7cb11e6031 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -63,14 +63,8 @@ public:
LLMute(const LLUUID& id, const std::string& name = std::string(), EType type = BY_NAME, U32 flags = 0);
- // Returns name + suffix based on type
- // For example: "James Tester (resident)"
- std::string getDisplayName() const;
-
- // Converts a UI name into just the agent or object name
- // For example: "James Tester (resident)" sets the name to "James Tester"
- // and the type to AGENT.
- void setFromDisplayName(const std::string& display_name);
+ // Returns localized type name of muted item
+ std::string getDisplayType() const;
public:
LLUUID mID; // agent or object id
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index 08ae93c3a6..e199f9f180 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -268,24 +268,23 @@ void LLNearbyChatScreenChannel::showToastsBottom()
}
break;
}
- else
- {
- toast_rect = toast->getRect();
- toast_rect.setLeftTopAndSize(getRect().mLeft , toast_top, toast_rect.getWidth() ,toast_rect.getHeight());
-
- toast->setRect(toast_rect);
- toast->setIsHidden(false);
- toast->setVisible(TRUE);
+ bottom = toast_top - toast->getTopPad();
+ }
- if(!toast->hasFocus())
- {
- // Fixing Z-order of toasts (EXT-4862)
- // Next toast will be positioned under this one.
- gFloaterView->sendChildToBack(toast);
- }
-
- bottom = toast->getRect().mTop - toast->getTopPad();
- }
+ // use reverse order to provide correct z-order and avoid toast blinking
+ for(std::vector<LLToast*>::reverse_iterator it = m_active_toasts.rbegin(); it != m_active_toasts.rend(); ++it)
+ {
+ LLToast* toast = (*it);
+ S32 toast_top = bottom + toast->getTopPad();
+
+ toast_rect = toast->getRect();
+ toast_rect.setLeftTopAndSize(getRect().mLeft , toast_top, toast_rect.getWidth() ,toast_rect.getHeight());
+
+ toast->setRect(toast_rect);
+ toast->setIsHidden(false);
+ toast->setVisible(TRUE);
+
+ bottom = toast->getRect().mBottom - margin;
}
}
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index a163b6fd62..1dc0e414a2 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -291,6 +291,11 @@ public:
static bool canAddNotifPanelToIM(const LLNotificationPtr& notification);
/**
+ * Checks whether notification can be used multiple times or not.
+ */
+ static bool isNotificationReusable(const LLNotificationPtr& notification);
+
+ /**
* Checks if passed notification can create IM session and be written into it.
*
* This method uses canLogToIM() & canSpawnIMSession().
@@ -298,6 +303,18 @@ public:
static bool canSpawnSessionAndLogToIM(const LLNotificationPtr& notification);
/**
+ * Checks if passed notification can create toast.
+ *
+ * It returns false only for inventory accepted/declined notifications if respective IM window is open (EXT-5909)
+ */
+ static bool canSpawnToast(const LLNotificationPtr& notification);
+
+ /**
+ * Determines whether IM floater is opened.
+ */
+ static bool isIMFloaterOpened(const LLNotificationPtr& notification);
+
+ /**
* Writes notification message to IM session.
*/
static void logToIM(const EInstantMessage& session_type,
@@ -343,6 +360,21 @@ public:
* Adds notification panel to the IM floater.
*/
static void addNotifPanelToIM(const LLNotificationPtr& notification);
+
+ /**
+ * Updates messages of IM floater.
+ */
+ static void updateIMFLoaterMesages(const LLUUID& session_id);
+
+ /**
+ * Updates messages of visible IM floater.
+ */
+ static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification);
+
+ /**
+ * Decrements counter of IM messages.
+ */
+ static void decIMMesageCounter(const LLNotificationPtr& notification);
};
}
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 88bb769109..d3ad61128d 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -127,7 +127,9 @@ const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"),
FRIENDSHIP_DECLINED_BYME("FriendshipDeclinedByMe"),
FRIEND_ONLINE("FriendOnline"), FRIEND_OFFLINE("FriendOffline"),
SERVER_OBJECT_MESSAGE("ServerObjectMessage"),
- TELEPORT_OFFERED("TeleportOffered");
+ TELEPORT_OFFERED("TeleportOffered"),
+ TELEPORT_OFFER_SENT("TeleportOfferSent");
+
// static
bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification)
@@ -137,11 +139,15 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification)
|| PAYMENT_RECIVED == notification->getName()
|| OFFER_FRIENDSHIP == notification->getName()
|| FRIENDSHIP_OFFERED == notification->getName()
+ || FRIENDSHIP_ACCEPTED == notification->getName()
|| FRIENDSHIP_ACCEPTED_BYME == notification->getName()
|| FRIENDSHIP_DECLINED_BYME == notification->getName()
|| SERVER_OBJECT_MESSAGE == notification->getName()
|| INVENTORY_ACCEPTED == notification->getName()
- || INVENTORY_DECLINED == notification->getName();
+ || INVENTORY_DECLINED == notification->getName()
+ || USER_GIVE_ITEM == notification->getName()
+ || TELEPORT_OFFERED == notification->getName()
+ || TELEPORT_OFFER_SENT == notification->getName();
}
// static
@@ -158,19 +164,25 @@ bool LLHandlerUtil::canLogToNearbyChat(const LLNotificationPtr& notification)
bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification)
{
return OFFER_FRIENDSHIP == notification->getName()
- || FRIENDSHIP_ACCEPTED == notification->getName()
|| USER_GIVE_ITEM == notification->getName()
- || INVENTORY_ACCEPTED == notification->getName()
- || INVENTORY_DECLINED == notification->getName();
+ || TELEPORT_OFFERED == notification->getName();
}
// static
bool LLHandlerUtil::canAddNotifPanelToIM(const LLNotificationPtr& notification)
{
return OFFER_FRIENDSHIP == notification->getName()
- || USER_GIVE_ITEM == notification->getName();
+ || USER_GIVE_ITEM == notification->getName()
+ || TELEPORT_OFFERED == notification->getName();
}
+// static
+bool LLHandlerUtil::isNotificationReusable(const LLNotificationPtr& notification)
+{
+ return OFFER_FRIENDSHIP == notification->getName()
+ || USER_GIVE_ITEM == notification->getName()
+ || TELEPORT_OFFERED == notification->getName();
+}
// static
bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notification)
@@ -179,18 +191,57 @@ bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notificat
}
// static
+bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification)
+{
+ bool cannot_spawn = isIMFloaterOpened(notification) && (INVENTORY_DECLINED == notification->getName()
+ || INVENTORY_ACCEPTED == notification->getName());
+
+ return !cannot_spawn;
+}
+
+// static
+bool LLHandlerUtil::isIMFloaterOpened(const LLNotificationPtr& notification)
+{
+ bool res = false;
+
+ LLUUID from_id = notification->getPayload()["from_id"];
+ LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL,
+ from_id);
+
+ LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>(
+ "impanel", session_id);
+ if (im_floater != NULL)
+ {
+ res = im_floater->getVisible() == TRUE;
+ }
+
+ return res;
+}
+
+// static
void LLHandlerUtil::logToIM(const EInstantMessage& session_type,
const std::string& session_name, const std::string& from_name,
const std::string& message, const LLUUID& session_owner_id,
const LLUUID& from_id)
{
+ std::string from = from_name;
+ if (from_name.empty())
+ {
+ from = SYSTEM_FROM;
+ }
+
LLUUID session_id = LLIMMgr::computeSessionID(session_type,
session_owner_id);
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
session_id);
if (session == NULL)
{
- LLIMModel::instance().logToFile(session_name, from_name, from_id, message);
+ // replace interactive system message marker with correct from string value
+ if (INTERACTIVE_SYSTEM_FROM == from_name)
+ {
+ from = SYSTEM_FROM;
+ }
+ LLIMModel::instance().logToFile(session_name, from, from_id, message);
}
else
{
@@ -201,8 +252,16 @@ void LLHandlerUtil::logToIM(const EInstantMessage& session_type,
// set searched session as active to avoid IM toast popup
LLIMModel::instance().setActiveSessionID(session_id);
- LLIMModel::instance().addMessage(session_id, from_name, from_id,
+ S32 unread = session->mNumUnread;
+ S32 participant_unread = session->mParticipantUnreadMessageCount;
+ LLIMModel::instance().addMessageSilently(session_id, from, from_id,
message);
+ // we shouldn't increment counters when logging, so restore them
+ session->mNumUnread = unread;
+ session->mParticipantUnreadMessageCount = participant_unread;
+
+ // update IM floater messages
+ updateIMFLoaterMesages(session_id);
// restore active session id
if (active_session_id.isNull())
@@ -250,13 +309,13 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_fi
if(to_file_only)
{
- logToIM(IM_NOTHING_SPECIAL, session_name, name, notification->getMessage(),
+ logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(),
LLUUID(), LLUUID());
}
else
{
- logToIM(IM_NOTHING_SPECIAL, session_name, name, notification->getMessage(),
- from_id, from_id);
+ logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(),
+ from_id, LLUUID());
}
}
}
@@ -324,7 +383,16 @@ std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notifica
if (res.empty())
{
LLUUID from_id = notification->getPayload()["FROM_ID"];
- gCacheName->getFullName(from_id, res);
+
+ //*TODO all keys everywhere should be made of the same case, there is a mix of keys in lower and upper cases
+ if (from_id.isNull())
+ {
+ from_id = notification->getPayload()["from_id"];
+ }
+ if(!gCacheName->getFullName(from_id, res))
+ {
+ res = "";
+ }
}
return res;
}
@@ -343,11 +411,60 @@ void LLHandlerUtil::addNotifPanelToIM(const LLNotificationPtr& notification)
LLSD offer;
offer["notification_id"] = notification->getID();
- offer["from_id"] = notification->getPayload()["from_id"];
- offer["from"] = name;
- offer["time"] = LLLogChat::timestamp(true);
+ offer["from"] = SYSTEM_FROM;
+ offer["time"] = LLLogChat::timestamp(false);
offer["index"] = (LLSD::Integer)session->mMsgs.size();
session->mMsgs.push_front(offer);
- LLIMFloater::show(session_id);
+
+ // update IM floater and counters
+ LLSD arg;
+ arg["session_id"] = session_id;
+ arg["num_unread"] = ++(session->mNumUnread);
+ arg["participant_unread"] = ++(session->mParticipantUnreadMessageCount);
+ LLIMModel::getInstance()->mNewMsgSignal(arg);
+}
+
+// static
+void LLHandlerUtil::updateIMFLoaterMesages(const LLUUID& session_id)
+{
+ LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
+ if (im_floater != NULL && im_floater->getVisible())
+ {
+ im_floater->updateMessages();
+ }
+}
+
+// static
+void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification)
+{
+ const std::string name = LLHandlerUtil::getSubstitutionName(notification);
+ LLUUID from_id = notification->getPayload()["from_id"];
+ LLUUID session_id = spawnIMSession(name, from_id);
+
+ updateIMFLoaterMesages(session_id);
+}
+
+// static
+void LLHandlerUtil::decIMMesageCounter(const LLNotificationPtr& notification)
+{
+ const std::string name = LLHandlerUtil::getSubstitutionName(notification);
+ LLUUID from_id = notification->getPayload()["from_id"];
+ LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, from_id);
+
+ LLIMModel::LLIMSession * session = LLIMModel::getInstance()->findIMSession(
+ session_id);
+
+ if (session == NULL)
+ {
+ return;
+ }
+
+ LLSD arg;
+ arg["session_id"] = session_id;
+ session->mNumUnread--;
+ arg["num_unread"] = session->mNumUnread;
+ session->mParticipantUnreadMessageCount--;
+ arg["participant_unread"] = session->mParticipantUnreadMessageCount;
+ LLIMModel::getInstance()->mNewMsgSignal(arg);
}
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 8ebd5de258..e93aec9d01 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -103,6 +103,8 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
}
else
{
+ notification->setReusable(LLHandlerUtil::isNotificationReusable(notification));
+
LLUUID session_id;
if (LLHandlerUtil::canSpawnIMSession(notification))
{
@@ -113,35 +115,58 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
session_id = LLHandlerUtil::spawnIMSession(name, from_id);
}
- if (LLHandlerUtil::canAddNotifPanelToIM(notification))
+ bool show_toast = true;
+ bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification);
+ if (add_notid_to_im)
{
LLHandlerUtil::addNotifPanelToIM(notification);
- LLHandlerUtil::logToIMP2P(notification, true);
+ if (LLHandlerUtil::isIMFloaterOpened(notification))
+ {
+ show_toast = false;
+ }
}
- else if (notification->getPayload().has("SUPPRESS_TOAST")
+
+ if (notification->getPayload().has("SUPPRESS_TOAST")
&& notification->getPayload()["SUPPRESS_TOAST"])
{
- LLHandlerUtil::logToIMP2P(notification);
LLNotificationsUtil::cancel(notification);
}
- else
+ else if(show_toast)
{
LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);
-
+ // don't close notification on panel destroy since it will be used by IM floater
+ notify_box->setCloseNotificationOnDestroy(!add_notid_to_im);
LLToast::Params p;
p.notif_id = notification->getID();
p.notification = notification;
p.panel = notify_box;
p.on_delete_toast = boost::bind(&LLOfferHandler::onDeleteToast, this, _1);
+ // we not save offer notifications to the syswell floater that should be added to the IM floater
+ p.can_be_stored = !add_notid_to_im;
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
if(channel)
channel->addToast(p);
- LLHandlerUtil::logToIMP2P(notification);
+ // if we not add notification to IM - add it to notification well
+ if (!add_notid_to_im)
+ {
+ // send a signal to the counter manager
+ mNewNotificationSignal();
+ }
+ }
- // send a signal to the counter manager
- mNewNotificationSignal();
+ if (LLHandlerUtil::canLogToIM(notification))
+ {
+ // log only to file if notif panel can be embedded to IM and IM is opened
+ if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification))
+ {
+ LLHandlerUtil::logToIMP2P(notification, true);
+ }
+ else
+ {
+ LLHandlerUtil::logToIMP2P(notification);
+ }
}
}
}
@@ -155,6 +180,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
}
else
{
+ if (LLHandlerUtil::canAddNotifPanelToIM(notification)
+ && !LLHandlerUtil::isIMFloaterOpened(notification))
+ {
+ LLHandlerUtil::decIMMesageCounter(notification);
+ }
mChannel->killToastByNotificationID(notification->getID());
}
}
@@ -166,8 +196,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
void LLOfferHandler::onDeleteToast(LLToast* toast)
{
- // send a signal to the counter manager
- mDelNotificationSignal();
+ if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification()))
+ {
+ // send a signal to the counter manager
+ mDelNotificationSignal();
+ }
// send a signal to a listener to let him perform some action
// in this case listener is a SysWellWindow and it will remove a corresponding item from its list
@@ -181,7 +214,9 @@ void LLOfferHandler::onRejectToast(LLUUID& id)
if (notification
&& LLNotificationManager::getInstance()->getHandlerForNotification(
- notification->getType()) == this)
+ notification->getType()) == this
+ // don't delete notification since it may be used by IM floater
+ && !LLHandlerUtil::canAddNotifPanelToIM(notification))
{
LLNotifications::instance().cancel(notification);
}
diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp
index 4e2c5085ed..1f1afe293a 100644
--- a/indra/newview/llnotificationtiphandler.cpp
+++ b/indra/newview/llnotificationtiphandler.cpp
@@ -150,6 +150,12 @@ bool LLTipHandler::processNotification(const LLSD& notify)
LLHandlerUtil::spawnIMSession(name, from_id);
}
+ // don't spawn toast for inventory accepted/declined offers if respective IM window is open (EXT-5909)
+ if (!LLHandlerUtil::canSpawnToast(notification))
+ {
+ return true;
+ }
+
LLToastPanel* notify_box = NULL;
if("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName())
{
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 57b478ffef..a0ba2f739b 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -495,6 +495,7 @@ BOOL LLPanelAvatarProfile::postBuild()
&LLPanelAvatarProfile::onMapButtonClick, this)), NULL);
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("Profile.ShowOnMap", boost::bind(&LLPanelAvatarProfile::onMapButtonClick, this));
registrar.add("Profile.Pay", boost::bind(&LLPanelAvatarProfile::pay, this));
registrar.add("Profile.Share", boost::bind(&LLPanelAvatarProfile::share, this));
registrar.add("Profile.BlockUnblock", boost::bind(&LLPanelAvatarProfile::toggleBlock, this));
@@ -504,6 +505,7 @@ BOOL LLPanelAvatarProfile::postBuild()
registrar.add("Profile.CSR", boost::bind(&LLPanelAvatarProfile::csr, this));
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable;
+ enable.add("Profile.EnableShowOnMap", boost::bind(&LLPanelAvatarProfile::enableShowOnMap, this));
enable.add("Profile.EnableGod", boost::bind(&enable_god));
enable.add("Profile.EnableBlock", boost::bind(&LLPanelAvatarProfile::enableBlock, this));
enable.add("Profile.EnableUnblock", boost::bind(&LLPanelAvatarProfile::enableUnblock, this));
@@ -698,6 +700,15 @@ void LLPanelAvatarProfile::toggleBlock()
LLAvatarActions::toggleBlock(getAvatarId());
}
+bool LLPanelAvatarProfile::enableShowOnMap()
+{
+ bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId());
+
+ bool enable_map_btn = (is_buddy_online && is_agent_mappable(getAvatarId()))
+ || gAgent.isGodlike();
+ return enable_map_btn;
+}
+
bool LLPanelAvatarProfile::enableBlock()
{
return LLAvatarActions::canBlock(getAvatarId()) && !LLAvatarActions::isBlocked(getAvatarId());
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 2bd23b6e9c..bb8df2ff9c 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -202,6 +202,7 @@ protected:
void unfreeze();
void csr();
+ bool enableShowOnMap();
bool enableBlock();
bool enableUnblock();
bool enableGod();
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index 362657a458..a186bc926c 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -119,8 +119,13 @@ void LLPanelBlockedList::refreshBlockedList()
std::vector<LLMute>::iterator it;
for (it = mutes.begin(); it != mutes.end(); ++it)
{
- std::string display_name = it->getDisplayName();
- mBlockedList->addStringUUIDItem(display_name, it->mID, ADD_BOTTOM, TRUE);
+ LLScrollListItem::Params item_p;
+ item_p.enabled(TRUE);
+ item_p.value(it->mID); // link UUID of blocked item with ScrollListItem
+ item_p.columns.add().column("item_name").value(it->mName);//.type("text");
+ item_p.columns.add().column("item_type").value(it->getDisplayType());//.type("text").width(111);
+
+ mBlockedList->addRow(item_p, ADD_BOTTOM);
}
}
@@ -145,9 +150,7 @@ void LLPanelBlockedList::onRemoveBtnClick()
{
std::string name = mBlockedList->getSelectedItemLabel();
LLUUID id = mBlockedList->getStringUUIDSelectedItem();
- LLMute mute(id);
- mute.setFromDisplayName(name);
- // now mute.mName has the suffix trimmed off
+ LLMute mute(id, name);
S32 last_selected = mBlockedList->getFirstSelectedIndex();
if (LLMuteList::getInstance()->remove(mute))
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 021e1f5159..70a7bf644b 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -1893,7 +1893,7 @@ void LLPanelClassifiedEdit::resetControls()
LLPanelClassifiedInfo::resetControls();
getChild<LLComboBox>("category")->setCurrentByIndex(0);
- getChild<LLIconsComboBox>("content_type")->setCurrentByIndex(0);
+ getChild<LLComboBox>("content_type")->setCurrentByIndex(0);
childSetValue("auto_renew", false);
childSetValue("price_for_listing", MINIMUM_PRICE_FOR_LISTING);
childSetEnabled("price_for_listing", TRUE);
@@ -1928,7 +1928,7 @@ U32 LLPanelClassifiedEdit::getContentType()
void LLPanelClassifiedEdit::setContentType(U32 content_type)
{
- LLIconsComboBox* ct_cb = getChild<LLIconsComboBox>("content_type");
+ LLComboBox* ct_cb = getChild<LLComboBox>("content_type");
ct_cb->setCurrentByIndex(content_type);
ct_cb->resetDirty();
}
@@ -1988,7 +1988,7 @@ U8 LLPanelClassifiedEdit::getFlags()
{
bool auto_renew = childGetValue("auto_renew").asBoolean();
- LLComboBox* content_cb = getChild<LLIconsComboBox>("content_type");
+ LLComboBox* content_cb = getChild<LLComboBox>("content_type");
bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE;
return pack_classified_flags_request(auto_renew, false, mature, false);
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 7505581904..c43cbf5819 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -609,7 +609,9 @@ void LLTaskInvFVBridge::performAction(LLFolderView* folder, LLInventoryModel* mo
{
if (price > 0 && price > gStatusBar->getBalance())
{
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_costs"), price);
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_costs", args), price);
}
else
{
@@ -1188,7 +1190,8 @@ public:
LLTaskObjectBridge(
LLPanelObjectInventory* panel,
const LLUUID& uuid,
- const std::string& name);
+ const std::string& name,
+ U32 flags = 0);
virtual LLUIImagePtr getIcon() const;
};
@@ -1196,8 +1199,9 @@ public:
LLTaskObjectBridge::LLTaskObjectBridge(
LLPanelObjectInventory* panel,
const LLUUID& uuid,
- const std::string& name) :
- LLTaskInvFVBridge(panel, uuid, name)
+ const std::string& name,
+ U32 flags) :
+ LLTaskInvFVBridge(panel, uuid, name, flags)
{
}
@@ -1442,9 +1446,15 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
// object->getName());
break;
case LLAssetType::AT_OBJECT:
+ {
+ item = dynamic_cast<LLInventoryItem*>(object);
+ U32 flags = ( NULL == item ? 0 : item->getFlags() );
+
new_bridge = new LLTaskObjectBridge(panel,
object->getUUID(),
- object->getName());
+ object->getName(),
+ flags);
+ }
break;
case LLAssetType::AT_NOTECARD:
new_bridge = new LLTaskNotecardBridge(panel,
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index cdd79b1559..1a1650c38b 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -567,9 +567,13 @@ void LLPanelPlaceProfile::onForSaleBannerClick()
if(parcel->getLocalID() == mSelectedParcelID &&
mLastSelectedRegionID ==selected_region->getRegionID())
{
- if(parcel->getSalePrice() - gStatusBar->getBalance() > 0)
+ S32 price = parcel->getSalePrice();
+
+ if(price - gStatusBar->getBalance() > 0)
{
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("buying_selected_land"), parcel->getSalePrice());
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("buying_selected_land", args), price);
}
else
{
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 26b57c003b..f9ba6f625d 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -278,6 +278,11 @@ BOOL LLPanelPlaces::postBuild()
mFilterEditor = getChild<LLFilterEditor>("Filter");
if (mFilterEditor)
{
+ //when list item is being clicked the filter editor looses focus
+ //committing on focus lost leads to detaching list items
+ //BUT a detached list item cannot be made selected and must not be clicked onto
+ mFilterEditor->setCommitOnFocusLost(false);
+
mFilterEditor->setCommitCallback(boost::bind(&LLPanelPlaces::onFilterEdit, this, _2, false));
}
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index 120b584cd9..9b5e38d0aa 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -68,15 +68,16 @@ const F32 TOTAL_LOGIN_TIME = 10.f; // seconds, wild guess at time from GL contex
S32 gLastStartAnimationFrame = 0; // human-style indexing, first image = 1
const S32 ANIMATION_FRAMES = 1; //13;
+static LLRegisterPanelClassWrapper<LLProgressView> r("progress_view");
+
+
// XUI: Translate
-LLProgressView::LLProgressView(const LLRect &rect)
+LLProgressView::LLProgressView()
: LLPanel(),
mPercentDone( 0.f ),
mMouseDownInActiveArea( false ),
mUpdateEvents("LLProgressView")
{
- LLUICtrlFactory::getInstance()->buildPanel(this, "panel_progress.xml");
- reshape(rect.getWidth(), rect.getHeight());
mUpdateEvents.listen("self", boost::bind(&LLProgressView::handleUpdate, this, _1));
}
@@ -92,6 +93,9 @@ BOOL LLProgressView::postBuild()
getChild<LLTextBox>("message_text")->setClickedCallback(onClickMessage, this);
+ // hidden initially, until we need it
+ LLPanel::setVisible(FALSE);
+
sInstance = this;
return TRUE;
}
@@ -126,19 +130,23 @@ BOOL LLProgressView::handleKeyHere(KEY key, MASK mask)
void LLProgressView::setVisible(BOOL visible)
{
+ // hiding progress view
if (getVisible() && !visible)
{
-
mFadeTimer.start();
+ // hiding progress view, so show menu bars
+ LLUI::getRootView()->getChildView("menu_bar_holder")->setVisible(TRUE);
}
+ // showing progress view
else if (!getVisible() && visible)
{
- gViewerWindow->addPopup(this);
-
+ // showing progress view, so hide menu bars
+ LLUI::getRootView()->getChildView("menu_bar_holder")->setVisible(FALSE);
+
setFocus(TRUE);
mFadeTimer.stop();
mProgressTimer.start();
- LLPanel::setVisible(visible);
+ LLPanel::setVisible(TRUE);
}
}
@@ -148,7 +156,7 @@ void LLProgressView::draw()
static LLTimer timer;
// Paint bitmap if we've got one
- glPushMatrix();
+ glPushMatrix();
if (gStartTexture)
{
LLGLSUIDefault gls_ui;
@@ -189,7 +197,7 @@ void LLProgressView::draw()
// Fade is complete, release focus
gFocusMgr.releaseFocusIfNeeded( this );
LLPanel::setVisible(FALSE);
- gViewerWindow->removePopup(this);
+ mFadeTimer.stop();
gStartTexture = NULL;
}
diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h
index 6853674d88..374b14be83 100644
--- a/indra/newview/llprogressview.h
+++ b/indra/newview/llprogressview.h
@@ -44,7 +44,7 @@ class LLProgressBar;
class LLProgressView : public LLPanel
{
public:
- LLProgressView(const LLRect& rect);
+ LLProgressView();
virtual ~LLProgressView();
BOOL postBuild();
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index a4426b370e..dffb5e5e12 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -710,9 +710,7 @@ void LLScreenChannel::hideToast(const LLUUID& notification_id)
if(mToastList.end() != it)
{
ToastElem te = *it;
- te.toast->setVisible(FALSE);
- te.toast->stopTimer();
- mToastList.erase(it);
+ te.toast->hide();
}
}
diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index 32a915608e..dc64296521 100644
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -168,25 +168,25 @@ void LLScrollingPanelParam::draw()
LLPanel::draw();
// Draw the hints over the "less" and "more" buttons.
- glPushMatrix();
+ gGL.pushUIMatrix();
{
const LLRect& r = mHintMin->getRect();
F32 left = (F32)(r.mLeft + BTN_BORDER);
F32 bot = (F32)(r.mBottom + BTN_BORDER);
- glTranslatef(left, bot, 0.f);
+ gGL.translateUI(left, bot, 0.f);
mHintMin->draw();
}
- glPopMatrix();
+ gGL.popUIMatrix();
- glPushMatrix();
+ gGL.pushUIMatrix();
{
const LLRect& r = mHintMax->getRect();
F32 left = (F32)(r.mLeft + BTN_BORDER);
F32 bot = (F32)(r.mBottom + BTN_BORDER);
- glTranslatef(left, bot, 0.f);
+ gGL.translateUI(left, bot, 0.f);
mHintMax->draw();
}
- glPopMatrix();
+ gGL.popUIMatrix();
// Draw labels on top of the buttons
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 717a8bda1e..6cf9c6b95d 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -37,7 +37,6 @@
#include "llagent.h"
#include "llappviewer.h"
#include "llimview.h"
-#include "llmutelist.h"
#include "llsdutil.h"
#include "lluicolortable.h"
#include "llviewerobjectlist.h"
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index b1b3ae473c..1c7b3a0fe0 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -571,7 +571,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
if ((mFetcher->isQuitting() || mImagePriority < 1.0f || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
{
- if (mState < WRITE_TO_CACHE)
+ if (mState < DECODE_IMAGE)
{
return true; // abort
}
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index e6d13a7613..907740a88e 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -44,6 +44,7 @@
#include "llrect.h"
#include "lltrans.h"
#include "llnotificationsutil.h"
+#include "llviewermessage.h"
const S32 BOTTOM_PAD = VPAD * 3;
const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding
@@ -53,6 +54,8 @@ S32 BUTTON_WIDTH = 90;
const LLFontGL* LLToastNotifyPanel::sFont = NULL;
const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL;
+LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal;
+
LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification, const LLRect& rect) :
LLToastPanel(notification),
mTextBox(NULL),
@@ -60,7 +63,8 @@ mInfoPanel(NULL),
mControlPanel(NULL),
mNumOptions(0),
mNumButtons(0),
-mAddedDefaultBtn(false)
+mAddedDefaultBtn(false),
+mCloseNotificationOnDestroy(true)
{
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_notification.xml");
if(rect != LLRect::null)
@@ -193,11 +197,25 @@ mAddedDefaultBtn(false)
// we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed
adjustPanelForScriptNotice(button_panel_width, button_panel_height);
updateButtonsLayout(buttons, h_pad);
+ // save buttons for later use in disableButtons()
+ mButtons.assign(buttons.begin(), buttons.end());
}
}
// adjust panel's height to the text size
mInfoPanel->setFollowsAll();
snapToMessageHeight(mTextBox, MAX_LENGTH);
+
+ if(notification->isReusable())
+ {
+ mButtonClickConnection = sButtonClickSignal.connect(
+ boost::bind(&LLToastNotifyPanel::onToastPanelButtonClicked, this, _1, _2));
+
+ if(notification->isRespondedTo())
+ {
+ // User selected an option in toast, now disable required buttons in IM window
+ disableRespondedOptions(notification);
+ }
+ }
}
void LLToastNotifyPanel::addDefaultButton()
{
@@ -265,9 +283,13 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt
LLToastNotifyPanel::~LLToastNotifyPanel()
{
+ mButtonClickConnection.disconnect();
+
std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer());
- if (LLNotificationsUtil::find(mNotification->getID()) != NULL)
+ if (mCloseNotificationOnDestroy && LLNotificationsUtil::find(mNotification->getID()) != NULL)
{
+ // let reusable notification be deleted
+ mNotification->setReusable(false);
LLNotifications::getInstance()->cancel(mNotification);
}
}
@@ -342,6 +364,104 @@ void LLToastNotifyPanel::adjustPanelForTipNotice()
}
}
+typedef std::set<std::string> button_name_set_t;
+typedef std::map<std::string, button_name_set_t> disable_button_map_t;
+
+disable_button_map_t initUserGiveItemDisableButtonMap()
+{
+ // see EXT-5905 for disable rules
+
+ disable_button_map_t disable_map;
+ button_name_set_t buttons;
+
+ buttons.insert("Show");
+ disable_map.insert(std::make_pair("Show", buttons));
+
+ buttons.insert("Discard");
+ disable_map.insert(std::make_pair("Discard", buttons));
+
+ buttons.insert("Mute");
+ disable_map.insert(std::make_pair("Mute", buttons));
+
+ return disable_map;
+}
+
+disable_button_map_t initTeleportOfferedDisableButtonMap()
+{
+ disable_button_map_t disable_map;
+ button_name_set_t buttons;
+
+ buttons.insert("Teleport");
+ buttons.insert("Cancel");
+
+ disable_map.insert(std::make_pair("Teleport", buttons));
+ disable_map.insert(std::make_pair("Cancel", buttons));
+
+ return disable_map;
+}
+
+disable_button_map_t initFriendshipOfferedDisableButtonMap()
+{
+ disable_button_map_t disable_map;
+ button_name_set_t buttons;
+
+ buttons.insert("Accept");
+ buttons.insert("Decline");
+
+ disable_map.insert(std::make_pair("Accept", buttons));
+ disable_map.insert(std::make_pair("Decline", buttons));
+
+ return disable_map;
+}
+
+button_name_set_t getButtonDisableList(const std::string& notification_name, const std::string& button_name)
+{
+ static disable_button_map_t user_give_item_disable_map = initUserGiveItemDisableButtonMap();
+ static disable_button_map_t teleport_offered_disable_map = initTeleportOfferedDisableButtonMap();
+ static disable_button_map_t friendship_offered_disable_map = initFriendshipOfferedDisableButtonMap();
+
+ disable_button_map_t::const_iterator it;
+ disable_button_map_t::const_iterator it_end;
+ disable_button_map_t search_map;
+
+ if("UserGiveItem" == notification_name)
+ {
+ search_map = user_give_item_disable_map;
+ }
+ else if("TeleportOffered" == notification_name)
+ {
+ search_map = teleport_offered_disable_map;
+ }
+ else if("OfferFriendship" == notification_name)
+ {
+ search_map = friendship_offered_disable_map;
+ }
+
+ it = search_map.find(button_name);
+ it_end = search_map.end();
+
+ if(it_end != it)
+ {
+ return it->second;
+ }
+ return button_name_set_t();
+}
+
+void LLToastNotifyPanel::disableButtons(const std::string& notification_name, const std::string& selected_button)
+{
+ button_name_set_t buttons = getButtonDisableList(notification_name, selected_button);
+
+ std::vector<index_button_pair_t>::const_iterator it = mButtons.begin();
+ for ( ; it != mButtons.end(); it++)
+ {
+ LLButton* btn = it->second;
+ if(buttons.find(btn->getName()) != buttons.end())
+ {
+ btn->setEnabled(FALSE);
+ }
+ }
+}
+
// static
void LLToastNotifyPanel::onClickButton(void* data)
{
@@ -354,8 +474,81 @@ void LLToastNotifyPanel::onClickButton(void* data)
{
response[button_name] = true;
}
+
+ bool is_reusable = self->mNotification->isReusable();
+ // When we call respond(), LLOfferInfo will delete itself in inventory_offer_callback(),
+ // lets copy it while it's still valid.
+ LLOfferInfo* old_info = static_cast<LLOfferInfo*>(self->mNotification->getResponder());
+ LLOfferInfo* new_info = NULL;
+ if(is_reusable && old_info)
+ {
+ new_info = new LLOfferInfo(*old_info);
+ self->mNotification->setResponder(new_info);
+ }
+
self->mNotification->respond(response);
- // disable all buttons
- self->mControlPanel->setEnabled(FALSE);
+ if(is_reusable)
+ {
+ sButtonClickSignal(self->mNotification->getID(), button_name);
+
+ if(new_info)
+ {
+ self->mNotification->setResponseFunctor(
+ boost::bind(&LLOfferInfo::inventory_offer_callback, new_info, _1, _2));
+ }
+ }
+ else
+ {
+ // disable all buttons
+ self->mControlPanel->setEnabled(FALSE);
+ }
}
+
+void LLToastNotifyPanel::onToastPanelButtonClicked(const LLUUID& notification_id, const std::string btn_name)
+{
+ if(mNotification->getID() == notification_id)
+ {
+ disableButtons(mNotification->getName(), btn_name);
+ }
+}
+
+void LLToastNotifyPanel::disableRespondedOptions(LLNotificationPtr& notification)
+{
+ LLSD response = notification->getResponse();
+ for (LLSD::map_const_iterator response_it = response.beginMap();
+ response_it != response.endMap(); ++response_it)
+ {
+ if (response_it->second.isBoolean() && response_it->second.asBoolean())
+ {
+ // that after multiple responses there can be many pressed buttons
+ // need to process them all
+ disableButtons(notification->getName(), response_it->first);
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+
+LLIMToastNotifyPanel::LLIMToastNotifyPanel(LLNotificationPtr& pNotification, const LLRect& rect /* = LLRect::null */)
+ : LLToastNotifyPanel(pNotification, rect)
+{
+ mTextBox->setFollowsAll();
+}
+
+void LLIMToastNotifyPanel::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
+{
+ S32 text_height = mTextBox->getTextBoundingRect().getHeight();
+ S32 widget_height = mTextBox->getRect().getHeight();
+ S32 delta = text_height - widget_height;
+ LLRect rc = getRect();
+
+ rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height + delta);
+ height = rc.getHeight();
+ width = rc.getWidth();
+
+ LLToastPanel::reshape(width, height, called_from_parent);
+}
+
+// EOF
diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h
index 152975e7de..a8d2d03236 100644
--- a/indra/newview/lltoastnotifypanel.h
+++ b/indra/newview/lltoastnotifypanel.h
@@ -65,6 +65,7 @@ public:
virtual ~LLToastNotifyPanel();
LLPanel * getControlPanel() { return mControlPanel; }
+ void setCloseNotificationOnDestroy(bool close) { mCloseNotificationOnDestroy = close; }
protected:
LLButton* createButton(const LLSD& form_element, BOOL is_option);
@@ -76,7 +77,7 @@ protected:
};
std::vector<InstanceAndS32*> mBtnCallbackData;
-private:
+ bool mCloseNotificationOnDestroy;
typedef std::pair<int,LLButton*> index_button_pair_t;
void adjustPanelForScriptNotice(S32 max_width, S32 max_height);
@@ -90,6 +91,13 @@ private:
*/
void updateButtonsLayout(const std::vector<index_button_pair_t>& buttons, S32 h_pad);
+ /**
+ * Disable specific button(s) based on notification name and clicked button
+ */
+ void disableButtons(const std::string& notification_name, const std::string& selected_button);
+
+ std::vector<index_button_pair_t> mButtons;
+
// panel elements
LLTextBase* mTextBox;
LLPanel* mInfoPanel; // a panel, that contains an information
@@ -98,6 +106,21 @@ private:
// internal handler for button being clicked
static void onClickButton(void* data);
+ typedef boost::signals2::signal <void (const LLUUID& notification_id, const std::string btn_name)>
+ button_click_signal_t;
+ static button_click_signal_t sButtonClickSignal;
+ boost::signals2::connection mButtonClickConnection;
+
+ /**
+ * handle sButtonClickSignal (to disable buttons) across all panels with given notification_id
+ */
+ void onToastPanelButtonClicked(const LLUUID& notification_id, const std::string btn_name);
+
+ /**
+ * Process response data. Will disable selected options
+ */
+ void disableRespondedOptions(LLNotificationPtr& notification);
+
bool mIsTip;
bool mAddedDefaultBtn;
bool mIsScriptDialog;
@@ -111,4 +134,13 @@ private:
static const LLFontGL* sFontSmall;
};
+class LLIMToastNotifyPanel : public LLToastNotifyPanel
+{
+public:
+
+ LLIMToastNotifyPanel(LLNotificationPtr& pNotification, const LLRect& rect = LLRect::null);
+
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+};
+
#endif /* LLTOASTNOTIFYPANEL_H_ */
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 125c62474e..47e60a966e 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1503,15 +1503,38 @@ void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent,
LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
+ logInventoryOffer(to_agent, im_session_id);
+
+ // add buddy to recent people list
+ LLRecentPeople::instance().add(to_agent);
+}
+
+//static
+void LLToolDragAndDrop::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id)
+{
+ // compute id of possible IM session with agent that has "to_agent" id
+ LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, to_agent);
// If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat.
- if (im_session_id != LLUUID::null)
+ if (im_session_id.notNull())
{
LLSD args;
gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
}
-
- // add buddy to recent people list
- LLRecentPeople::instance().add(to_agent);
+ // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat.
+ else if (LLIMModel::getInstance()->findIMSession(session_id))
+ {
+ LLSD args;
+ gIMMgr->addSystemMessage(session_id, "inventory_item_offered", args);
+ }
+ // If this item was given by drag-and-drop on avatar while IM panel wasn't open, log this action to IM history.
+ else
+ {
+ std::string full_name;
+ if (gCacheName->getFullName(to_agent, full_name))
+ {
+ LLIMModel::instance().logToFile(full_name, LLTrans::getString("SECOND_LIFE"), im_session_id, LLTrans::getString("inventory_item_offered-im"));
+ }
+ }
}
void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent,
@@ -1723,12 +1746,7 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent,
LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
- // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat.
- if (im_session_id != LLUUID::null)
- {
- LLSD args;
- gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
- }
+ logInventoryOffer(to_agent, im_session_id);
}
}
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 79b2bc32a3..0da13dac8b 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -227,6 +227,10 @@ protected:
LLInventoryCategory* cat,
const LLUUID &im_session_id = LLUUID::null);
+ // log "Inventory item offered" to IM
+ static void logInventoryOffer(const LLUUID& to_agent,
+ const LLUUID &im_session_id = LLUUID::null);
+
public:
// helper functions
static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index b9509a98f5..af42ed0dc9 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -982,6 +982,119 @@ bool LLViewerMedia::isParcelAudioPlaying()
return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::clearAllCookies()
+{
+ // Clear all cookies for all plugins
+ impl_list::iterator iter = sViewerMediaImplList.begin();
+ impl_list::iterator end = sViewerMediaImplList.end();
+ for (; iter != end; iter++)
+ {
+ LLViewerMediaImpl* pimpl = *iter;
+ if(pimpl->mMediaSource)
+ {
+ pimpl->mMediaSource->clear_cookies();
+ }
+ }
+
+ // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly.
+ // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded.
+ // Until such time as we can centralize cookie storage, the following hack should cover these cases:
+
+ // HACK: Look for cookie files in all possible places and delete them.
+ // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
+
+ // Places that cookie files can be:
+ // <getOSUserAppDir>/browser_profile/cookies
+ // <getOSUserAppDir>/first_last/browser_profile/cookies (note that there may be any number of these!)
+
+ std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter();
+ std::string target;
+ std::string filename;
+
+ lldebugs << "base dir = " << base_dir << llendl;
+
+ // The non-logged-in version is easy
+ target = base_dir;
+ target += "browser_profile";
+ target += gDirUtilp->getDirDelimiter();
+ target += "cookies";
+ lldebugs << "target = " << target << llendl;
+ if(LLFile::isfile(target))
+ {
+ LLFile::remove(target);
+ }
+
+ // the hard part: iterate over all user directories and delete the cookie file from each one
+ while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename, false))
+ {
+ target = base_dir;
+ target += filename;
+ target += gDirUtilp->getDirDelimiter();
+ target += "browser_profile";
+ target += gDirUtilp->getDirDelimiter();
+ target += "cookies";
+ lldebugs << "target = " << target << llendl;
+ if(LLFile::isfile(target))
+ {
+ LLFile::remove(target);
+ }
+ }
+
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::clearAllCaches()
+{
+ // Clear all plugins' caches
+ impl_list::iterator iter = sViewerMediaImplList.begin();
+ impl_list::iterator end = sViewerMediaImplList.end();
+ for (; iter != end; iter++)
+ {
+ LLViewerMediaImpl* pimpl = *iter;
+ pimpl->clearCache();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::setCookiesEnabled(bool enabled)
+{
+ // Set the "cookies enabled" flag for all loaded plugins
+ impl_list::iterator iter = sViewerMediaImplList.begin();
+ impl_list::iterator end = sViewerMediaImplList.end();
+ for (; iter != end; iter++)
+ {
+ LLViewerMediaImpl* pimpl = *iter;
+ if(pimpl->mMediaSource)
+ {
+ pimpl->mMediaSource->enable_cookies(enabled);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port)
+{
+ // Set the proxy config for all loaded plugins
+ impl_list::iterator iter = sViewerMediaImplList.begin();
+ impl_list::iterator end = sViewerMediaImplList.end();
+ for (; iter != end; iter++)
+ {
+ LLViewerMediaImpl* pimpl = *iter;
+ if(pimpl->mMediaSource)
+ {
+ pimpl->mMediaSource->proxy_setup(enable, host, port);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
bool LLViewerMedia::hasInWorldMedia()
{
if (sInWorldMediaDisabled) return false;
@@ -1321,6 +1434,8 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
media_source->focus(mHasFocus);
media_source->setBackgroundColor(mBackgroundColor);
+ media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
+
if(mClearCache)
{
mClearCache = false;
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index bc51e713a1..f9870fb3b9 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -133,6 +133,18 @@ public:
static bool isParcelMediaPlaying();
static bool isParcelAudioPlaying();
+ // Clear all cookies for all plugins
+ static void clearAllCookies();
+
+ // Clear all plugins' caches
+ static void clearAllCaches();
+
+ // Set the "cookies enabled" flag for all loaded plugins
+ static void setCookiesEnabled(bool enabled);
+
+ // Set the proxy config for all loaded plugins
+ static void setProxyConfig(bool enable, const std::string &host, int port);
+
private:
static void onTeleportFinished();
};
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 5c40d02f8d..5598a589cc 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -436,7 +436,8 @@ void init_menus()
gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT));
gMenuBarView->setBackgroundColor( color );
- gMenuHolder->addChild(gMenuBarView);
+ LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
+ menu_bar_holder->addChild(gMenuBarView);
gViewerWindow->setMenuBackgroundColor(false,
LLViewerLogin::getInstance()->isInProductionGrid());
@@ -471,9 +472,10 @@ void init_menus()
gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
gLoginMenuBarView->arrangeAndClear();
LLRect menuBarRect = gLoginMenuBarView->getRect();
- gLoginMenuBarView->setRect(LLRect(menuBarRect.mLeft, menuBarRect.mTop, gViewerWindow->getRootView()->getRect().getWidth() - menuBarRect.mLeft, menuBarRect.mBottom));
+ menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight());
+ gLoginMenuBarView->setRect(menuBarRect);
gLoginMenuBarView->setBackgroundColor( color );
- gMenuHolder->addChild(gLoginMenuBarView);
+ menu_bar_holder->addChild(gLoginMenuBarView);
// tooltips are on top of EVERYTHING, including menus
gViewerWindow->getRootView()->sendChildToFront(gToolTipView);
@@ -3274,7 +3276,9 @@ void handle_buy_object(LLSaleInfo sale_info)
if (price > 0 && price > gStatusBar->getBalance())
{
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_object_costs"), price);
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("this_object_costs", args), price);
return;
}
@@ -4404,8 +4408,10 @@ void handle_buy_or_take()
}
else
{
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", total_price);
LLFloaterBuyCurrency::buyCurrency(
- "Buying this costs", total_price);
+ LLTrans::getString("BuyingCosts", args), total_price);
}
}
else
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 00762894cd..dfde9a9d1d 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -811,10 +811,10 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt
if(!(can_afford_transaction(expected_upload_cost)))
{
- LLFloaterBuyCurrency::buyCurrency(
- llformat(LLTrans::getString("UploadingCosts").c_str(),
- data->mAssetInfo.getName().c_str()),
- expected_upload_cost);
+ LLStringUtil::format_map_t args;
+ args["NAME"] = data->mAssetInfo.getName();
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("UploadingCosts", args), expected_upload_cost);
is_balance_sufficient = FALSE;
}
else if(region)
@@ -1001,7 +1001,9 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
if (balance < expected_upload_cost)
{
// insufficient funds, bail on this upload
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs"), expected_upload_cost);
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs", args), expected_upload_cost);
return;
}
}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index bd0012057c..3d0dfbed40 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -105,6 +105,7 @@
#include "llpanelplaceprofile.h"
#include <boost/algorithm/string/split.hpp> //
+#include <boost/regex.hpp>
#if LL_WINDOWS // For Windows specific error handler
#include "llwindebug.h" // For the invalid message handler
@@ -272,7 +273,9 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_
}
else
{
- LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("giving"), amount);
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", amount);
+ LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("giving", args), amount);
}
}
@@ -1081,6 +1084,21 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd)
mHost = LLHost(sd["sender"].asString());
}
+LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
+{
+ mIM = info.mIM;
+ mFromID = info.mFromID;
+ mFromGroup = info.mFromGroup;
+ mFromObject = info.mFromObject;
+ mTransactionID = info.mTransactionID;
+ mFolderID = info.mFolderID;
+ mObjectID = info.mObjectID;
+ mType = info.mType;
+ mFromName = info.mFromName;
+ mDesc = info.mDesc;
+ mHost = info.mHost;
+}
+
LLSD LLOfferInfo::asLLSD()
{
LLSD sd;
@@ -1572,7 +1590,11 @@ void inventory_offer_handler(LLOfferInfo* info)
}
else // Agent -> Agent Inventory Offer
{
+ p.responder = info;
// Note: sets inventory_offer_callback as the callback
+ // *TODO fix memory leak
+ // inventory_offer_callback() is not invoked if user received notification and
+ // closes viewer(without responding the notification)
p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
p.name = "UserGiveItem";
@@ -4498,8 +4520,64 @@ void process_money_balance_reply( LLMessageSystem* msg, void** )
payload["from_id"] = from_id;
LLNotificationsUtil::add("PaymentRecived", args, payload);
}
+ //AD *HACK: Parsing incoming string to localize messages that come from server! EXT-5986
+ // It's only a temporarily and ineffective measure. It doesn't affect performance much
+ // because we get here only for specific type of messages, but anyway it is not right to do it!
+ // *TODO: Server-side changes should be made and this code removed.
else
{
+ if(desc.find("You paid")==0)
+ {
+ // Regular expression for message parsing- change it in case of server-side changes.
+ // Each set of parenthesis will later be used to find arguments of message we generate
+ // in the end of this if- (.*) gives us name of money receiver, (\\d+)-amount of money we pay
+ // and ([^$]*)- reason of payment
+ boost::regex expr("You paid (?:.{0}|(.*) )L\\$(\\d+)\\s?([^$]*)\\.");
+ boost::match_results <std::string::const_iterator> matches;
+ if(boost::regex_match(desc, matches, expr))
+ {
+ // Name of full localizable notification string
+ // there are three types of this string- with name of receiver and reason of payment,
+ // without name and without reason (but not simultaneously)
+ // example of string without name - You paid L$100 to create a group.
+ // example of string without reason - You paid Smdby Linden L$100.
+ // example of string with reason and name - You paid Smbdy Linden L$100 for a land access pass.
+ std::string line = "you_paid_ldollars_no_name";
+
+ // arguments of string which will be in notification
+ LLStringUtil::format_map_t str_args;
+
+ // extracting amount of money paid (without L$ symbols). It is always present.
+ str_args["[AMOUNT]"] = std::string(matches[2]);
+
+ // extracting name of person/group you are paying (it may be absent)
+ std::string name = std::string(matches[1]);
+ if(!name.empty())
+ {
+ str_args["[NAME]"] = name;
+ line = "you_paid_ldollars";
+ }
+
+ // extracting reason of payment (it may be absent)
+ std::string reason = std::string(matches[3]);
+ if (reason.empty())
+ {
+ line = "you_paid_ldollars_no_reason";
+ }
+ else
+ {
+ std::string localized_reason;
+ // if we haven't found localized string for reason of payment leave it as it was
+ str_args["[REASON]"] = LLTrans::findString(localized_reason, reason) ? localized_reason : reason;
+ }
+
+ // forming final message string by retrieving localized version from xml
+ // and applying previously found arguments
+ line = LLTrans::getString(line, str_args);
+ args["MESSAGE"] = line;
+ }
+ }
+
LLNotificationsUtil::add("SystemMessage", args);
}
@@ -5486,6 +5564,8 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
args["TO_NAME"] = target_name;
LLSD payload;
+
+ //*TODO please rewrite all keys to the same case, lower or upper
payload["from_id"] = target_id;
payload["SESSION_NAME"] = target_name;
payload["SUPPRESS_TOAST"] = true;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index 7dd629dcfd..88f9697037 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -215,6 +215,8 @@ struct LLOfferInfo
mIM(IM_NOTHING_SPECIAL), mType(LLAssetType::AT_NONE) {};
LLOfferInfo(const LLSD& sd);
+ LLOfferInfo(const LLOfferInfo& info);
+
void forceResponse(InventoryOfferResponse response);
EInstantMessage mIM;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index b5642d07a5..6c8346df86 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4029,7 +4029,8 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const
avatar_parent = (LLViewerObject*)root_edit->getParent();
}
- if (avatar_parent && avatar_parent->isAvatar() && root_edit && root_edit->mDrawable.notNull())
+ if (avatar_parent && avatar_parent->isAvatar() &&
+ root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent())
{
LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent();
position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index ea8af223c3..c9b3886fef 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -524,7 +524,10 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
break;
case LLAssetType::AT_SOUND: img_name = "Inv_Sound"; break;
case LLAssetType::AT_CLOTHING: img_name = "Inv_Clothing"; break;
- case LLAssetType::AT_OBJECT: img_name = "Inv_Object"; break;
+ case LLAssetType::AT_OBJECT:
+ img_name = LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags() ?
+ "Inv_Object_Multi" : "Inv_Object";
+ break;
case LLAssetType::AT_CALLINGCARD: img_name = "Inv_CallingCard"; break;
case LLAssetType::AT_LANDMARK: img_name = "Inv_Landmark"; break;
case LLAssetType::AT_NOTECARD: img_name = "Inv_Notecard"; break;
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index dbbf0219c9..9fbffdac35 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1546,8 +1546,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
}
else
{
- // Leave the priority as-is
- return mDecodePriority;
+ priority = -1.f; //stop fetching
}
}
else if (cur_discard < 0)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index adac4b9b40..e7d64c48a0 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1351,7 +1351,8 @@ LLViewerWindow::LLViewerWindow(
mStatesDirty(false),
mIsFullscreenChecked(false),
mCurrResolutionIndex(0),
- mViewerWindowListener(new LLViewerWindowListener(this))
+ mViewerWindowListener(new LLViewerWindowListener(this)),
+ mProgressView(NULL)
{
LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
@@ -1588,8 +1589,7 @@ void LLViewerWindow::initBase()
gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
// Add the progress bar view (startup view), which overrides everything
- mProgressView = new LLProgressView(full_window);
- getRootView()->addChild(mProgressView);
+ mProgressView = getRootView()->getChild<LLProgressView>("progress_view");
setShowProgress(FALSE);
setProgressCancelButtonVisible(FALSE);
diff --git a/indra/newview/skins/default/textures/icons/Inv_Object_Multi.png b/indra/newview/skins/default/textures/icons/Inv_Object_Multi.png
new file mode 100644
index 0000000000..11f4871ad8
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Object_Multi.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index b1594816b2..a3e5361e76 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -247,6 +247,7 @@ with the same filename but different name
<texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />
<texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />
<texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />
+ <texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" />
<texture name="Inv_Pants" file_name="icons/Inv_Pants.png" preload="false" />
<texture name="Inv_Script" file_name="icons/Inv_Script.png" preload="false" />
<texture name="Inv_Shirt" file_name="icons/Inv_Shirt.png" preload="false" />
diff --git a/indra/newview/skins/default/xui/de/panel_bottomtray.xml b/indra/newview/skins/default/xui/de/panel_bottomtray.xml
index d3f89b0ad3..d52b8dcf4d 100644
--- a/indra/newview/skins/default/xui/de/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/de/panel_bottomtray.xml
@@ -9,7 +9,7 @@
<layout_stack name="toolbar_stack">
<layout_panel name="speak_panel">
<talk_button name="talk">
- <speak_button label="Sprechen" label_selected="Sprechen" name="speak_btn"/>
+ <speak_button label="Sprechen" label_selected="Sprechen" name="speak_btn" halign="right" />
</talk_button>
</layout_panel>
<layout_panel name="gesture_panel">
diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency.xml b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
index 961bd6b5e4..e02d32596a 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_currency.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
@@ -182,7 +182,7 @@
width="180"
layout="topleft"
name="buy_action">
- [NAME] L$ [PRICE]
+ [ACTION]
</text>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 85853f39bb..1ace760816 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -143,12 +143,19 @@
<panel mouse_opaque="false"
follows="left|right|top"
name="status_bar_container"
- tab_stop="false"
+ tab_stop="false"
height="19"
left="0"
top="0"
width="1024"
visible="false"/>
+ <view mouse_opaque="false"
+ follows="all"
+ name="menu_bar_holder"
+ left="0"
+ top="0"
+ width="1024"
+ height="768"/>
<notify_box_view top="0"
follows="all"
height="768"
@@ -159,6 +166,15 @@
<panel top="0"
follows="all"
height="768"
+ mouse_opaque="true"
+ name="progress_view"
+ filename="panel_progress.xml"
+ class="progress_view"
+ width="1024"
+ visible="false"/>
+ <panel top="0"
+ follows="all"
+ height="768"
mouse_opaque="false"
name="popup_holder"
class="popup_holder"
diff --git a/indra/newview/skins/default/xui/en/menu_profile_overflow.xml b/indra/newview/skins/default/xui/en/menu_profile_overflow.xml
index 5162a4902f..b0b7b554b0 100644
--- a/indra/newview/skins/default/xui/en/menu_profile_overflow.xml
+++ b/indra/newview/skins/default/xui/en/menu_profile_overflow.xml
@@ -6,6 +6,15 @@
name="profile_overflow_menu"
width="120">
<menu_item_call
+ label="Map"
+ layout="topleft"
+ name="show_on_map">
+ <menu_item_call.on_click
+ function="Profile.ShowOnMap" />
+ <menu_item_call.on_enable
+ function="Profile.EnableShowOnMap" />
+ </menu_item_call>
+ <menu_item_call
label="Pay"
layout="topleft"
name="pay">
diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
index 072ea882e6..d3f6695375 100644
--- a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
@@ -39,7 +39,13 @@
name="blocked"
tool_tip="List of currently blocked Residents"
top="30"
- width="270" />
+ width="270">
+ <scroll_list.columns
+ name="item_name" />
+ <scroll_list.columns
+ name="item_type"
+ width="96" />
+ </scroll_list>
<button
follows="left|bottom"
height="23"
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index e70a0512d6..58c5c11e51 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -74,12 +74,15 @@
name="talk"
top="5"
width="105">
+ <!-- do not remove halign attribute with default value. otherwise it can't be overridden in other locales.
+ & pad_right is default value for long label which can be right aligned. See EXT-6318 -->
<speak_button
- halign="left"
+ halign="center"
name="speak_btn"
label="Speak"
label_selected="Speak"
- pad_left="12"
+ pad_right="22"
+ use_ellipses="true"
/>
<show_button>
<show_button.init_callback
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 627e616af5..d1e0746d9d 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -216,7 +216,7 @@ height="16"
name="login_help"
top_pad="2"
right="-10"
- width="180">
+ width="190">
Need help logging in? </text>
<!-- <text
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
index 6b5f0c3896..6bf00373ea 100644
--- a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="left|right|top|bottom"
- name="MediaControlsPanel"
+ name="MediaControls"
background_visible="false"
height="200"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index 412485e03f..30191aecb6 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -314,9 +314,12 @@
left="2"
mouse_opaque="false"
name="add_friend"
+ pad_left="1"
+ pad_right="1"
tool_tip="Offer friendship to the Resident"
top="5"
- width="80" />
+ use_ellipses="true"
+ width="117" />
<button
follows="bottom|left"
height="23"
@@ -325,8 +328,8 @@
name="im"
tool_tip="Open instant message session"
top="5"
- left_pad="3"
- width="39" />
+ left_pad="1"
+ width="21" />
<button
follows="bottom|left"
height="23"
@@ -334,20 +337,12 @@
layout="topleft"
name="call"
tool_tip="Call this Resident"
- left_pad="3"
+ left_pad="1"
+ pad_left="1"
+ pad_right="1"
top="5"
- width="43" />
- <button
- enabled="false"
- follows="bottom|left"
- height="23"
- label="Map"
- layout="topleft"
- name="show_on_map_btn"
- tool_tip="Show the Resident on the map"
- top="5"
- left_pad="3"
- width="41" />
+ use_ellipses="true"
+ width="51" />
<button
follows="bottom|left"
height="23"
@@ -355,9 +350,12 @@
layout="topleft"
name="teleport"
tool_tip="Offer teleport"
- left_pad="3"
+ left_pad="1"
+ pad_left="1"
+ pad_right="1"
top="5"
- width="69" />
+ use_ellipses="true"
+ width="92" />
<button
follows="bottom|right"
height="23"
@@ -367,7 +365,6 @@
tool_tip="Pay money to or share inventory with the Resident"
right="-1"
top="5"
- left_pad="3"
width="23" />
</layout_panel>
<layout_panel
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 3a766bb798..47386bd332 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2202,7 +2202,8 @@ Clears (deletes) the media and all params from the given face.
<!-- Viewer menu -->
<string name="AcquiredItems">Acquired Items</string>
<string name="Cancel">Cancel</string>
- <string name="UploadingCosts">Uploading %s costs</string>
+ <string name="UploadingCosts">Uploading [NAME] costs L$ [AMOUNT]</string>
+ <string name="BuyingCosts">Buying this costs L$ [AMOUNT]</string>
<string name="UnknownFileExtension">
Unknown file extension .%s
Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh
@@ -3050,14 +3051,48 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
<!-- Financial operations strings -->
<string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT]</string>
- <string name="giving">Giving</string>
- <string name="uploading_costs">Uploading costs</string>
- <string name="this_costs">This costs</string>
- <string name="buying_selected_land">Buying selected land</string>
- <string name="this_object_costs">This object costs"</string>
+ <string name="you_paid_ldollars">You paid [NAME] L$[AMOUNT] [REASON].</string>
+ <string name="you_paid_ldollars_no_reason">You paid [NAME] L$[AMOUNT].</string>
+ <string name="you_paid_ldollars_no_name">You paid L$[AMOUNT] [REASON].</string>
+ <string name="for a parcel of land">for a parcel of land</string>
+ <string name="for a land access pass">for a land access pass</string>
+ <string name="for deeding land">for deeding land</string>
+ <string name="to create a group">to create a group</string>
+ <string name="to join a group">to join a group</string>
+ <string name="to upload">to upload</string>
+
+ <string name="giving">Giving L$ [AMOUNT]</string>
+ <string name="uploading_costs">Uploading costs L$ [AMOUNT]</string>
+ <string name="this_costs">This costs L$ [AMOUNT]</string>
+ <string name="buying_selected_land">Buying selected land L$ [AMOUNT]</string>
+ <string name="this_object_costs">This object costs L$ [AMOUNT]</string>
<string name="group_role_everyone">Everyone</string>
<string name="group_role_officers">Officers</string>
<string name="group_role_owners">Owners</string>
+ <string name="uploading_abuse_report">Uploading...
+
+Abuse Report</string>
+
+ <!-- names for new inventory items-->
+ <string name="New Shape">New Shape</string>
+ <string name="New Skin">New Skin</string>
+ <string name="New Hair">New Hair</string>
+ <string name="New Eyes">New Eyes</string>
+ <string name="New Shirt">New Shirt</string>
+ <string name="New Pants">New Pants</string>
+ <string name="New Shoes">New Shoes</string>
+ <string name="New Socks">New Socks</string>
+ <string name="New Jacket">New Jacket</string>
+ <string name="New Gloves">New Gloves</string>
+ <string name="New Undershirt">New Undershirt</string>
+ <string name="New Underpants">New Underpants</string>
+ <string name="New Skirt">New Skirt</string>
+ <string name="New Alpha">New Alpha</string>
+ <string name="New Tattoo">New Tattoo</string>
+ <string name="Invalid Wearable">Invalid Wearable</string>
+ <string name="New Script">New Script</string>
+ <string name="New Folder">New Folder</string>
+ <string name="Contents">Contents</string>
</strings>
diff --git a/indra/newview/skins/default/xui/en/widgets/chat_history.xml b/indra/newview/skins/default/xui/en/widgets/chat_history.xml
index ef885e8045..aa3ea736b8 100644
--- a/indra/newview/skins/default/xui/en/widgets/chat_history.xml
+++ b/indra/newview/skins/default/xui/en/widgets/chat_history.xml
@@ -2,6 +2,7 @@
<chat_history
message_header="panel_chat_header.xml"
message_separator="panel_chat_separator.xml"
+ message_plaintext_separator="panel_chat_plaintext_separator.xml"
left_text_pad="10"
right_text_pad="15"
left_widget_pad="0"