diff options
Diffstat (limited to 'indra')
159 files changed, 6812 insertions, 3253 deletions
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 6b4bd0d7ef..ff1b6c5334 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -36,9 +36,12 @@ #include "apr_time.h" +#include <time.h> #include <iomanip> #include <sstream> +#include "lltimer.h" + static const F64 DATE_EPOCH = 0.0; static const F64 LL_APR_USEC_PER_SEC = 1000000.0; @@ -122,7 +125,7 @@ void LLDate::toHTTPDateStream(std::ostream& s) const << " GMT"; // RFC 1123 date does not use microseconds - llinfos << "Date in RFC 1123 format is " << s << llendl; + //llinfos << "Date in RFC 1123 format is " << s << llendl; } void LLDate::toStream(std::ostream& s) const @@ -239,6 +242,17 @@ bool operator!=(const LLDate& first, const LLDate& second) return (first.secondsSinceEpoch() != second.secondsSinceEpoch()); } +/* static */ LLDate LLDate::now() +{ + // time() returns seconds, we want fractions of a second, which LLTimer provides --RN + return LLDate(LLTimer::getTotalSeconds()); +} + +bool LLDate::operator<(const LLDate& rhs) const +{ + return mSecondsSinceEpoch < rhs.mSecondsSinceEpoch; +} + std::ostream& operator<<(std::ostream& s, const LLDate& date) { date.toStream(s); @@ -250,3 +264,4 @@ std::istream& operator>>(std::istream& s, LLDate& date) date.fromStream(s); return s; } + diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 2b53c8cc9a..b660f9fcdd 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -35,6 +35,7 @@ #define LL_LLDATE_H #include <iosfwd> +#include <string> #include "stdtypes.h" @@ -53,7 +54,7 @@ public: LLDate(); /** - * @brief Construct a date equal to epoch. + * @brief Construct a date equal the source date. */ LLDate(const LLDate& date); @@ -111,6 +112,32 @@ public: * @param seconds The number of seconds since epoch UTC. */ void secondsSinceEpoch(F64 seconds); + + /** + * @brief Create an LLDate object set to the current time. + * + * @return The number of seconds since epoch UTC. + */ + static LLDate now(); + + /** + * @brief Compare dates using operator< so we can order them using STL. + * + * @param rhs -- the right hand side of the comparison operator + */ + bool operator<(const LLDate& rhs) const; + + /** + * @brief Remaining comparison operators in terms of operator< + * This conforms to the expectation of STL. + * + * @param rhs -- the right hand side of the comparison operator + */ + bool operator>(const LLDate& rhs) const { return rhs < *this; } + bool operator<=(const LLDate& rhs) const { return !(rhs < *this); } + bool operator>=(const LLDate& rhs) const { return !(*this < rhs); } + bool operator!=(const LLDate& rhs) const { return (*this < rhs) || (rhs < *this); } + bool operator==(const LLDate& rhs) const { return !(*this != rhs); } private: F64 mSecondsSinceEpoch; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index cc57e658fb..3f3dd33ee3 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -409,53 +409,58 @@ protected: // // class Foo: public LLSingleton<Foo>{}; // -// Foo* instance = Foo::getInstance(); +// Foo& instance = Foo::instance(); // -// The second way is to define a seperate class that exposes the singleton -// interface: +// The second way is to use the singleton class directly, without inheritance: // -// class FooSingleton: public LLSingleton<Foo>{}; +// typedef LLSingleton<Foo> FooSingleton; // -// Foo* instance = FooSingleton::getInstance(); +// Foo& instance = FooSingleton::instance(); +// +// In this case, the class being managed as a singleton needs to provide an +// initSingleton() method since the LLSingleton virtual method won't be +// available // // As currently written, it is not thread-safe. -#if LL_WINDOWS && _MSC_VER < 1400 // this is Visual C++ 2003 or earlier -// workaround for VC7 compiler bug -// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx -// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass> -// a friend and hide your constructor - template <typename T> class LLSingleton { public: - static T* getInstance() + virtual ~LLSingleton() {} +#ifdef LL_MSVC7 +// workaround for VC7 compiler bug +// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx +// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass> +// a friend and hide your constructor + static T* getInstance() { LLSingleton<T> singleton; - return singleton.get(); - } -private: - T* get() - { - static T instance; - return &instance; + return singleton.vsHack(); } -}; + T* vsHack() #else - -template <typename T> -class LLSingleton -{ -public: static T* getInstance() +#endif { static T instance; + static bool needs_init = true; + if (needs_init) + { + needs_init = false; + instance.initSingleton(); + } return &instance; } -}; -#endif + static T& instance() + { + return *getInstance(); + } + +private: + virtual void initSingleton() {} +}; //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 099f233f56..4bf4e442fd 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -349,7 +349,7 @@ namespace virtual bool has(const LLSD::String&) const; virtual LLSD get(const LLSD::String&) const; - void insert(const LLSD::String& k, const LLSD& v); + LLSD& insert(const LLSD::String& k, const LLSD& v); virtual void erase(const LLSD::String&); LLSD& ref(const LLSD::String&); virtual const LLSD& ref(const LLSD::String&) const; @@ -388,9 +388,14 @@ namespace return (i != mData.end()) ? i->second : LLSD(); } - void ImplMap::insert(const LLSD::String& k, const LLSD& v) + LLSD& ImplMap::insert(const LLSD::String& k, const LLSD& v) { mData.insert(DataMap::value_type(k, v)); + #ifdef LL_MSVC7 + return *((LLSD*)this); + #else + return *dynamic_cast<LLSD*>(this); + #endif } void ImplMap::erase(const LLSD::String& k) @@ -436,7 +441,7 @@ namespace virtual int size() const; virtual LLSD get(LLSD::Integer) const; void set(LLSD::Integer, const LLSD&); - void insert(LLSD::Integer, const LLSD&); + LLSD& insert(LLSD::Integer, const LLSD&); void append(const LLSD&); virtual void erase(LLSD::Integer); LLSD& ref(LLSD::Integer); @@ -485,9 +490,15 @@ namespace mData[index] = v; } - void ImplArray::insert(LLSD::Integer i, const LLSD& v) + LLSD& ImplArray::insert(LLSD::Integer i, const LLSD& v) { - if (i < 0) { return; } + if (i < 0) { + #ifdef LL_MSVC7 + return *((LLSD*)this); + #else + return *dynamic_cast<LLSD*>(this); + #endif + } DataVector::size_type index = i; if (index >= mData.size()) @@ -496,6 +507,11 @@ namespace } mData.insert(mData.begin() + index, v); + #ifdef LL_MSVC7 + return *((LLSD*)this); + #else + return *dynamic_cast<LLSD*>(this); + #endif } void ImplArray::append(const LLSD& v) @@ -739,8 +755,11 @@ LLSD LLSD::emptyMap() bool LLSD::has(const String& k) const { return safe(impl).has(k); } LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } -void LLSD::insert(const String& k, const LLSD& v) - { makeMap(impl).insert(k, v); } +LLSD& LLSD::insert(const String& k, const LLSD& v) + { + makeMap(impl).insert(k, v); + return *dynamic_cast<LLSD*>(this); + } void LLSD::erase(const String& k) { makeMap(impl).erase(k); } LLSD& LLSD::operator[](const String& k) @@ -761,8 +780,11 @@ int LLSD::size() const { return safe(impl).size(); } LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); } -void LLSD::insert(Integer i, const LLSD& v) - { makeArray(impl).insert(i, v); } +LLSD& LLSD::insert(Integer i, const LLSD& v) + { + makeArray(impl).insert(i, v); + return *this; + } void LLSD::append(const LLSD& v) { makeArray(impl).append(v); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 0382fb1360..87874009dd 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -222,7 +222,7 @@ public: bool has(const String&) const; LLSD get(const String&) const; - void insert(const String&, const LLSD&); + LLSD& insert(const String&, const LLSD&); void erase(const String&); LLSD& operator[](const String&); @@ -237,7 +237,7 @@ public: LLSD get(Integer) const; void set(Integer, const LLSD&); - void insert(Integer, const LLSD&); + LLSD& insert(Integer, const LLSD&); void append(const LLSD&); void erase(Integer); diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 2c34608064..2525e24989 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -569,6 +569,14 @@ LLEventTimer::LLEventTimer(F32 period) sActiveList.push_back(this); } +LLEventTimer::LLEventTimer(const LLDate& time) +: mEventTimer() +{ + mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); + sActiveList.push_back(this); +} + + LLEventTimer::~LLEventTimer() { sActiveList.remove(this); diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 1916d67fda..6d6f1f44cd 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -38,6 +38,7 @@ #include <limits.h> #include "stdtypes.h" +#include "lldate.h" #include <string> #include <list> @@ -173,6 +174,7 @@ class LLEventTimer { public: LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds + LLEventTimer(const LLDate& time); virtual ~LLEventTimer(); //function to be called at the supplied frequency diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 1098d1bd3c..019c5045d4 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -908,6 +908,21 @@ BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value) return FALSE; } +//static +LLUUID LLUUID::generateNewID(std::string hash_string) +{ + LLUUID new_id; + if (hash_string.empty()) + { + new_id.generate(); + } + else + { + new_id.generate(hash_string); + } + return new_id; +} + LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const { LLAssetID result; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index b2fcce5161..e5c204b589 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -65,6 +65,9 @@ public: // void generate(); // Generate a new UUID void generate(const std::string& stream); //Generate a new UUID based on hash of input stream + + static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc. + BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings void setNull(); // Faster than setting to LLUUID::null. @@ -124,7 +127,7 @@ public: static S32 getNodeID(unsigned char * node_id); static BOOL parseUUID(const std::string& buf, LLUUID* value); - + U8 mData[UUID_BYTES]; }; diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h index 4ac7cb4605..707f4451d1 100644 --- a/indra/llinventory/lleconomy.h +++ b/indra/llinventory/lleconomy.h @@ -47,6 +47,8 @@ public: // become a singleton and this pattern will more easily disambiguate them. typedef LLSingleton<LLGlobalEconomy> Singleton; + void initSingleton() { } + virtual void print(); static void processEconomyData(LLMessageSystem *msg, LLGlobalEconomy* econ_data); diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 0372bae106..916f4aa6c7 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -103,6 +103,30 @@ const F32 FP_MAG_THRESHOLD = 0.0000001f; // TODO: Replace with logic like is_approx_equal inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } +// These functions work by interpreting sign+exp+mantissa as an unsigned +// integer. +// For example: +// x = <sign>1 <exponent>00000010 <mantissa>00000000000000000000000 +// y = <sign>1 <exponent>00000001 <mantissa>11111111111111111111111 +// +// interpreted as ints = +// x = 10000001000000000000000000000000 +// y = 10000000111111111111111111111111 +// which is clearly a different of 1 in the least significant bit +// Values with the same exponent can be trivially shown to work. +// +// WARNING: Denormals of opposite sign do not work +// x = <sign>1 <exponent>00000000 <mantissa>00000000000000000000001 +// y = <sign>0 <exponent>00000000 <mantissa>00000000000000000000001 +// Although these values differ by 2 in the LSB, the sign bit makes +// the int comparison fail. +// +// WARNING: NaNs can compare equal +// There is no special treatment of exceptional values like NaNs +// +// WARNING: Infinity is comparable with F32_MAX and negative +// infinity is comparable with F32_MIN + inline BOOL is_approx_equal(F32 x, F32 y) { const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index 21ca4189ff..93b69714de 100644 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -223,6 +223,11 @@ public: return *this; } + bool isValid() const + { + return mLeft <= mRight && mBottom <= mTop; + } + bool isNull() const { return mLeft == mRight || mBottom == mTop; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index aced88f1a2..89c5115cfd 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -980,13 +980,10 @@ void LLGLState::initClass() { sStateMap[GL_DITHER] = GL_TRUE; // sStateMap[GL_TEXTURE_2D] = GL_TRUE; - + //make sure multisample defaults to disabled sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; glDisable(GL_MULTISAMPLE_ARB); - - //default vertex arrays to enabled. - glEnableClientState(GL_VERTEX_ARRAY); } //static diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 897cc4275d..1b4d4e7d54 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -36,6 +36,7 @@ set(llui_SOURCE_FILES lleditmenuhandler.cpp llfloater.cpp llfocusmgr.cpp + llfunctorregistry.cpp lliconctrl.cpp llkeywords.cpp lllineeditor.cpp @@ -43,6 +44,7 @@ set(llui_SOURCE_FILES llmodaldialog.cpp llmultislider.cpp llmultisliderctrl.cpp + llnotifications.cpp llpanel.cpp llprogressbar.cpp llradiogroup.cpp @@ -86,6 +88,7 @@ set(llui_HEADER_FILES lleditmenuhandler.h llfloater.h llfocusmgr.h + llfunctorregistry.h llhtmlhelp.h lliconctrl.h llkeywords.h @@ -95,6 +98,7 @@ set(llui_HEADER_FILES llmodaldialog.h llmultisliderctrl.h llmultislider.h + llnotifications.h llpanel.h llprogressbar.h llradiogroup.h diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index df5bcbe752..6edd5a7fe5 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -72,11 +72,12 @@ LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std:: mTextEntryTentative(TRUE), mListPosition(BELOW), mPrearrangeCallback( NULL ), - mTextEntryCallback( NULL ) + mTextEntryCallback( NULL ), + mLabel(label) { // Always use text box // Text label button - mButton = new LLButton(label, + mButton = new LLButton(mLabel, LLRect(), LLStringUtil::null, NULL, this); @@ -197,7 +198,12 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory * } } - combo_box->selectFirstItem(); + // if providing user text entry or descriptive label + // don't select an item under the hood + if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty()) + { + combo_box->selectFirstItem(); + } return combo_box; } @@ -259,7 +265,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOO { LLScrollListItem* item = mList->addSimpleElement(name, pos); item->setEnabled(enabled); - mList->selectFirstItem(); + if (!mAllowTextEntry && mLabel.empty()) + { + selectFirstItem(); + } return item; } @@ -268,7 +277,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAd { LLScrollListItem* item = mList->addSimpleElement(name, pos, id); item->setEnabled(enabled); - mList->selectFirstItem(); + if (!mAllowTextEntry && mLabel.empty()) + { + selectFirstItem(); + } return item; } @@ -278,7 +290,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddP LLScrollListItem* item = mList->addSimpleElement(name, pos); item->setEnabled(enabled); item->setUserdata( userdata ); - mList->selectFirstItem(); + if (!mAllowTextEntry && mLabel.empty()) + { + selectFirstItem(); + } return item; } @@ -287,7 +302,10 @@ LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosit { LLScrollListItem* item = mList->addSimpleElement(name, pos, value); item->setEnabled(enabled); - mList->selectFirstItem(); + if (!mAllowTextEntry && mLabel.empty()) + { + selectFirstItem(); + } return item; } diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 7427a33129..0317ebdae9 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -188,6 +188,7 @@ protected: LLScrollListCtrl* mList; EPreferredPosition mListPosition; LLPointer<LLUIImage> mArrowImage; + std::string mLabel; private: S32 mButtonPadding; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 22260b52cf..dd93684a69 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -147,6 +147,7 @@ LLFloater::LLFloater() : } mDragHandle = NULL; mHandle.bind(this); + mNotificationContext = new LLFloaterNotificationContext(getHandle()); } LLFloater::LLFloater(const std::string& name) @@ -220,6 +221,7 @@ void LLFloater::initFloater(const std::string& title, BOOL drag_on_left, BOOL minimizable, BOOL close_btn) { mHandle.bind(this); + mNotificationContext = new LLFloaterNotificationContext(getHandle()); // Init function can be called more than once, so clear out old data. for (S32 i = 0; i < BUTTON_COUNT; i++) @@ -429,6 +431,9 @@ void LLFloater::initFloater(const std::string& title, // virtual LLFloater::~LLFloater() { + delete mNotificationContext; + mNotificationContext = NULL; + control_map_t::iterator itor; for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor) { diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index b66eba8810..ebf2676960 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -39,6 +39,7 @@ #include "llpanel.h" #include "lluuid.h" #include "lltabcontainer.h" +#include "llnotifications.h" #include <set> class LLDragHandle; @@ -46,6 +47,7 @@ class LLResizeHandle; class LLResizeBar; class LLButton; class LLMultiFloater; +class LLFloater; const S32 LLFLOATER_VPAD = 6; const S32 LLFLOATER_HPAD = 6; @@ -70,6 +72,20 @@ const BOOL CLOSE_NO = FALSE; const BOOL ADJUST_VERTICAL_YES = TRUE; const BOOL ADJUST_VERTICAL_NO = FALSE; +// associates a given notification instance with a particular floater +class LLFloaterNotificationContext : + public LLNotificationContext +{ +public: + LLFloaterNotificationContext(LLHandle<LLFloater> floater_handle) : + mFloaterHandle(floater_handle) + {} + + LLFloater* getFloater() { return mFloaterHandle.get(); } +private: + LLHandle<LLFloater> mFloaterHandle; +}; + class LLFloater : public LLPanel { @@ -213,6 +229,11 @@ public: // handle refocusing. static void closeFocusedFloater(); + LLNotification::Params contextualNotification(const std::string& name) + { + return LLNotification::Params(name).context(mNotificationContext); + } + static void onClickClose(void *userdata); static void onClickMinimize(void *userdata); static void onClickTearOff(void *userdata); @@ -299,7 +320,7 @@ private: S32 mPreviousMinimizedBottom; S32 mPreviousMinimizedLeft; -private: + LLFloaterNotificationContext* mNotificationContext; LLRootHandle<LLFloater> mHandle; }; @@ -467,7 +488,6 @@ template <class T> class LLFloaterSingleton : public LLUISingleton<T, Visibility { }; - extern LLFloaterView* gFloaterView; #endif // LL_FLOATER_H diff --git a/indra/llui/llfunctorregistry.cpp b/indra/llui/llfunctorregistry.cpp new file mode 100644 index 0000000000..a6ecc6aa18 --- /dev/null +++ b/indra/llui/llfunctorregistry.cpp @@ -0,0 +1,37 @@ +/** + * @file llfunctorregistry.cpp + * @author Kent Quirk + * @brief Maintains a registry of named callback functors taking a single LLSD parameter + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + **/ + +#include "llfunctorregistry.h" + +// This is a default functor always resident in the system. +// It's used whenever a functor isn't found in the registry, so that +// we at least log the data relating to the user response. diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h new file mode 100644 index 0000000000..02bf74a28a --- /dev/null +++ b/indra/llui/llfunctorregistry.h @@ -0,0 +1,145 @@ +/** + * @file llfunctorregistry.h + * @author Kent Quirk + * @brief Maintains a registry of named callback functors taking a single LLSD parameter + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFUNCTORREGISTRY_H +#define LL_LLFUNCTORREGISTRY_H + +#include <string> +#include <map> + +#include <boost/function.hpp> + +#include "llsd.h" +#include "llmemory.h" + +/** + * @class LLFunctorRegistry + * @brief Maintains a collection of named functors for remote binding + * (mainly for use in callbacks from notifications and other signals) + * @see LLNotifications + * + * This class maintains a collection of named functors in a singleton. + * We wanted to be able to persist notifications with their callbacks + * across restarts of the viewer; we couldn't store functors that way. + * Using this registry, systems that require a functor to be maintained + * long term can register it at system startup, and then pass in the + * functor by name. + */ + +template <typename FUNCTOR_TYPE> +class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> > +{ + friend class LLSingleton<LLFunctorRegistry>; + LOG_CLASS(LLFunctorRegistry); +private: + LLFunctorRegistry() : LOGFUNCTOR("LogFunctor"), DONOTHING("DoNothing") + { + mMap[LOGFUNCTOR] = log_functor; + mMap[DONOTHING] = do_nothing; + } + +public: + typedef FUNCTOR_TYPE ResponseFunctor; + typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap; + + bool registerFunctor(const std::string& name, ResponseFunctor f) + { + bool retval = true; + typename FunctorMap::iterator it = mMap.find(name); + if (mMap.count(name) == 0) + { + mMap[name] = f; + } + else + { + llerrs << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << llendl; + retval = false; + } + + return retval; + } + + bool unregisterFunctor(const std::string& name) + { + if (mMap.count(name) == 0) + { + llwarns << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << llendl; + return false; + } + mMap.erase(name); + return true; + } + + FUNCTOR_TYPE getFunctor(const std::string& name) + { + typename FunctorMap::iterator it = mMap.find(name); + if (mMap.count(name) != 0) + { + return mMap[name]; + } + else + { + llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl; + return mMap[LOGFUNCTOR]; + } + } + + const std::string LOGFUNCTOR; + const std::string DONOTHING; + +private: + + static void log_functor(const LLSD& notification, const LLSD& payload) + { + llwarns << "log_functor called with payload: " << payload << llendl; + } + + static void do_nothing(const LLSD& notification, const LLSD& payload) + { + // what the sign sez + } + + FunctorMap mMap; +}; + +template <typename FUNCTOR_TYPE> +class LLFunctorRegistration +{ +public: + LLFunctorRegistration(const std::string& name, FUNCTOR_TYPE functor) + { + LLFunctorRegistry<FUNCTOR_TYPE>::instance().registerFunctor(name, functor); + } +}; + +#endif//LL_LLFUNCTORREGISTRY_H + diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp new file mode 100644 index 0000000000..c2da50b98b --- /dev/null +++ b/indra/llui/llnotifications.cpp @@ -0,0 +1,1471 @@ +/** +* @file llnotifications.cpp +* @brief Non-UI queue manager for keeping a prioritized list of notifications +* +* $LicenseInfo:firstyear=2008&license=viewergpl$ +* +* Copyright (c) 2008, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "linden_common.h" +#include "lluictrlfactory.h" +#include "lldir.h" +#include "llsdserialize.h" + +#include "llnotifications.h" + +#include <algorithm> +#include <boost/regex.hpp> + + +const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; + +// local channel for notification history +class LLNotificationHistoryChannel : public LLNotificationChannel +{ + LOG_CLASS(LLNotificationHistoryChannel); +public: + LLNotificationHistoryChannel(const std::string& filename) : + LLNotificationChannel("History", "Visible", &historyFilter), + mFileName(filename) + { + connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1)); + loadPersistentNotifications(); + } + +private: + bool historyHandler(const LLSD& payload) + { + // we ignore "load" messages, but rewrite the persistence file on any other + std::string sigtype = payload["sigtype"]; + if (sigtype != "load") + { + savePersistentNotifications(); + } + return false; + } + + // The history channel gets all notifications except those that have been cancelled + static bool historyFilter(LLNotificationPtr pNotification) + { + return !pNotification->isCancelled(); + } + + void savePersistentNotifications() + { + llinfos << "Saving open notifications to " << mFileName << llendl; + + llofstream notify_file(mFileName.c_str()); + if (!notify_file.is_open()) + { + llwarns << "Failed to open " << mFileName << llendl; + return; + } + + LLSD output; + output["version"] = NOTIFICATION_PERSIST_VERSION; + LLSD& data = output["data"]; + + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + if (!LLNotifications::instance().templateExists((*it)->getName())) continue; + + // only store notifications flagged as persisting + LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName()); + if (!templatep->mPersist) continue; + + data.append((*it)->asLLSD()); + } + + LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY); + } + + void loadPersistentNotifications() + { + llinfos << "Loading open notifications from " << mFileName << llendl; + + llifstream notify_file(mFileName.c_str()); + if (!notify_file.is_open()) + { + llwarns << "Failed to open " << mFileName << llendl; + return; + } + + LLSD input; + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) + { + llwarns << "Failed to parse open notifications" << llendl; + return; + } + + if (input.isUndefined()) return; + std::string version = input["version"]; + if (version != NOTIFICATION_PERSIST_VERSION) + { + llwarns << "Bad open notifications version: " << version << llendl; + return; + } + LLSD& data = input["data"]; + if (data.isUndefined()) return; + + LLNotifications& instance = LLNotifications::instance(); + for (LLSD::array_const_iterator notification_it = data.beginArray(); + notification_it != data.endArray(); + ++notification_it) + { + instance.add(LLNotificationPtr(new LLNotification(*notification_it))); + } + } + + //virtual + void onDelete(LLNotificationPtr pNotification) + { + // we want to keep deleted notifications in our log + mItems.insert(pNotification); + + return; + } + +private: + std::string mFileName; +}; + +bool filterIgnoredNotifications(LLNotificationPtr notification) +{ + LLNotificationFormPtr form = notification->getForm(); + // Check to see if the user wants to ignore this alert + if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO) + { + return LLUI::sConfigGroup->getWarning(notification->getName()); + } + + return true; +} + +bool handleIgnoredNotification(const LLSD& payload) +{ + if (payload["sigtype"].asString() == "add") + { + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (!pNotif) return false; + + LLNotificationFormPtr form = pNotif->getForm(); + LLSD response; + switch(form->getIgnoreType()) + { + case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE: + response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); + break; + case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: + response = LLUI::sIgnoresGroup->getLLSD("Default" + pNotif->getName()); + break; + case LLNotificationForm::IGNORE_SHOW_AGAIN: + break; + default: + return false; + } + pNotif->setIgnored(true); + pNotif->respond(response); + return true; // don't process this item any further + } + return false; +} + +namespace LLNotificationFilters +{ + // a sample filter + bool includeEverything(LLNotificationPtr p) + { + return true; + } +}; + +LLNotificationForm::LLNotificationForm() +: mFormData(LLSD::emptyArray()), + mIgnore(IGNORE_NO) +{ +} + + +LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node) +: mFormData(LLSD::emptyArray()), + mIgnore(IGNORE_NO) +{ + if (!xml_node->hasName("form")) + { + llwarns << "Bad xml node for form: " << xml_node->getName() << llendl; + } + LLXMLNodePtr child = xml_node->getFirstChild(); + while(child) + { + child = LLNotifications::instance().checkForXMLTemplate(child); + + LLSD item_entry; + std::string element_name = child->getName()->mString; + + if (element_name == "ignore") + { + bool save_option = false; + child->getAttribute_bool("save_option", save_option); + if (!save_option) + { + mIgnore = IGNORE_WITH_DEFAULT_RESPONSE; + } + else + { + // remember last option chosen by user and automatically respond with that in the future + mIgnore = IGNORE_WITH_LAST_RESPONSE; + LLUI::sIgnoresGroup->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); + } + child->getAttributeString("text", mIgnoreMsg); + LLUI::sIgnoresGroup->addWarning(name); + } + else + { + // flatten xml form entry into single LLSD map with type==name + item_entry["type"] = element_name; + const LLXMLAttribList::iterator attrib_end = child->mAttributes.end(); + for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin(); + attrib_it != attrib_end; + ++attrib_it) + { + item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue(); + } + item_entry["value"] = child->getTextContents(); + mFormData.append(item_entry); + } + + child = child->getNextSibling(); + } +} + +LLNotificationForm::LLNotificationForm(const LLSD& sd) +{ + if (sd.isArray()) + { + mFormData = sd; + } + else + { + llwarns << "Invalid form data " << sd << llendl; + mFormData = LLSD::emptyArray(); + } +} + +LLSD LLNotificationForm::asLLSD() const +{ + return mFormData; +} + +LLSD LLNotificationForm::getElement(const std::string& element_name) +{ + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return (*it); + } + return LLSD(); +} + + +bool LLNotificationForm::hasElement(const std::string& element_name) +{ + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return true; + } + return false; +} + +void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value) +{ + LLSD element; + element["type"] = type; + element["name"] = name; + element["label"] = name; + element["value"] = value; + element["index"] = mFormData.size(); + mFormData.append(element); +} + +void LLNotificationForm::append(const LLSD& sub_form) +{ + if (sub_form.isArray()) + { + for (LLSD::array_const_iterator it = sub_form.beginArray(); + it != sub_form.endArray(); + ++it) + { + mFormData.append(*it); + } + } +} + +void LLNotificationForm::formatElements(const LLSD& substitutions) +{ + for (LLSD::array_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + // format "text" component of each form element + if ((*it).has("text")) + { + std::string text = (*it)["text"].asString(); + text = LLNotification::format(text, substitutions); + (*it)["text"] = text; + } + if ((*it)["type"].asString() == "text" && (*it).has("value")) + { + std::string value = (*it)["value"].asString(); + value = LLNotification::format(value, substitutions); + (*it)["value"] = value; + } + } +} + +std::string LLNotificationForm::getDefaultOption() +{ + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["default"]) return (*it)["name"].asString(); + } + return ""; +} + +LLNotificationTemplate::LLNotificationTemplate() : + mExpireSeconds(0), + mExpireOption(-1), + mURLOption(-1), + mUnique(false), + mPriority(NOTIFICATION_PRIORITY_NORMAL) +{ + mForm = LLNotificationFormPtr(new LLNotificationForm()); +} + +LLNotification::LLNotification(const LLNotification::Params& p) : + mTimestamp(p.timestamp), + mSubstitutions(p.substitutions), + mPayload(p.payload), + mExpiresAt(0), + mResponseFunctorName(p.functor_name), + mTemporaryResponder(p.mTemporaryResponder), + mRespondedTo(false), + mPriority(p.priority), + mCancelled(false), + mIgnored(false) +{ + mId.generate(); + init(p.name, p.form_elements); +} + + +LLNotification::LLNotification(const LLSD& sd) : + mTemporaryResponder(false), + mRespondedTo(false), + mCancelled(false), + mIgnored(false) +{ + mId.generate(); + mSubstitutions = sd["substitutions"]; + mPayload = sd["payload"]; + mTimestamp = sd["time"]; + mExpiresAt = sd["expiry"]; + mPriority = (ENotificationPriority)sd["priority"].asInteger(); + mResponseFunctorName = sd["responseFunctor"].asString(); + std::string templatename = sd["name"].asString(); + init(templatename, LLSD()); + // replace form with serialized version + mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"])); +} + + +LLSD LLNotification::asLLSD() +{ + LLSD output; + output["name"] = mTemplatep->mName; + output["form"] = getForm()->asLLSD(); + output["substitutions"] = mSubstitutions; + output["payload"] = mPayload; + output["time"] = mTimestamp; + output["expiry"] = mExpiresAt; + output["priority"] = (S32)mPriority; + output["responseFunctor"] = mResponseFunctorName; + return output; +} + +void LLNotification::update() +{ + LLNotifications::instance().update(shared_from_this()); +} + +void LLNotification::updateFrom(LLNotificationPtr other) +{ + // can only update from the same notification type + if (mTemplatep != other->mTemplatep) return; + + // NOTE: do NOT change the ID, since it is the key to + // this given instance, just update all the metadata + //mId = other->mId; + + mPayload = other->mPayload; + mSubstitutions = other->mSubstitutions; + mTimestamp = other->mTimestamp; + mExpiresAt = other->mExpiresAt; + mCancelled = other->mCancelled; + mIgnored = other->mIgnored; + mPriority = other->mPriority; + mForm = other->mForm; + mResponseFunctorName = other->mResponseFunctorName; + mRespondedTo = other->mRespondedTo; + mTemporaryResponder = other->mTemporaryResponder; + + update(); +} + +const LLNotificationFormPtr LLNotification::getForm() +{ + return mForm; +} + +void LLNotification::cancel() +{ + mCancelled = true; +} + +LLSD LLNotification::getResponseTemplate(EResponseTemplateType type) +{ + LLSD response = LLSD::emptyMap(); + for (S32 element_idx = 0; + element_idx < mForm->getNumElements(); + ++element_idx) + { + LLSD element = mForm->getElement(element_idx); + if (element.has("name")) + { + response[element["name"].asString()] = element["value"]; + } + + if ((type == WITH_DEFAULT_BUTTON) + && element["default"].asBoolean()) + { + response[element["name"].asString()] = true; + } + } + return response; +} + +//static +S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) +{ + LLNotificationForm form(notification["form"]); + + for (S32 element_idx = 0; + element_idx < form.getNumElements(); + ++element_idx) + { + LLSD element = form.getElement(element_idx); + + // only look at buttons + if (element["type"].asString() == "button" + && response[element["name"].asString()].asBoolean()) + { + return element["index"].asInteger(); + } + } + + return -1; +} + +//static +std::string LLNotification::getSelectedOptionName(const LLSD& response) +{ + for (LLSD::map_const_iterator response_it = response.beginMap(); + response_it != response.endMap(); + ++response_it) + { + if (response_it->second.isBoolean() && response_it->second.asBoolean()) + { + return response_it->first; + } + } + return ""; +} + + +void LLNotification::respond(const LLSD& response) +{ + mRespondedTo = true; + LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName)(asLLSD(), response); + if (mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = ""; + mTemporaryResponder = false; + } + + if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + { + LLUI::sIgnoresGroup->setWarning(getName(), !mIgnored); + if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLUI::sIgnoresGroup->setLLSD("Default" + getName(), response); + } + } + + update(); +} + +void LLNotification::setIgnored(bool ignore) +{ + mIgnored = ignore; +} + +void LLNotification::setResponseFunctor(std::string const &responseFunctorName) +{ + if (mTemporaryResponder) + // get rid of the old one + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = responseFunctorName; + mTemporaryResponder = false; +} + +bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const +{ + for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); + required_fields_it != required_fields.end(); + required_fields_it++) + { + std::string required_field_name = *required_fields_it; + if( ! getPayload().has(required_field_name)) + { + return false; // a required field was not found + } + } + return true; // all required fields were found +} + +bool LLNotification::isEquivalentTo(LLNotificationPtr that) const +{ + if (this->mTemplatep->mName != that->mTemplatep->mName) + { + return false; // must have the same template name or forget it + } + if (this->mTemplatep->mUnique) + { + // highlander bit sez there can only be one of these + return + this->payloadContainsAll(that->mTemplatep->mUniqueContext) && + that->payloadContainsAll(this->mTemplatep->mUniqueContext); + } + return false; +} + +void LLNotification::init(const std::string& template_name, const LLSD& form_elements) +{ + mTemplatep = LLNotifications::instance().getTemplate(template_name); + if (!mTemplatep) return; + + // add default substitutions + // TODO: change this to read from the translatable strings file! + mSubstitutions["SECOND_LIFE"] = "Second Life"; + mSubstitutions["_URL"] = getURL(); + mSubstitutions["_NAME"] = template_name; + // TODO: something like this so that a missing alert is sensible: + //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); + + mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); + mForm->append(form_elements); + + // apply substitution to form labels + mForm->formatElements(mSubstitutions); + + LLDate rightnow = LLDate::now(); + if (mTemplatep->mExpireSeconds) + { + mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds); + } + + if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED) + { + mPriority = mTemplatep->mPriority; + } +} + +std::string LLNotification::summarize() const +{ + std::string s = "Notification("; + s += getName(); + s += ") : "; + s += mTemplatep ? mTemplatep->mMessage : ""; + // should also include timestamp and expiration time (but probably not payload) + return s; +} + +//static +std::string LLNotification::format(const std::string& s, const LLSD& substitutions) +{ + if (!substitutions.isMap()) + { + return s; + } + + std::ostringstream output; + // match strings like [NAME] + const boost::regex key("\\[([0-9_A-Z]+)]"); + + std::string::const_iterator start = s.begin(); + std::string::const_iterator end = s.end(); + boost::smatch match; + + while (boost::regex_search(start, end, match, key, boost::match_default)) + { + bool found_replacement = false; + std::string replacement; + + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + if (substitutions.has(std::string(match[1].first, match[1].second))) + { + replacement = substitutions[std::string(match[1].first, match[1].second)].asString(); + found_replacement = true; + } + // if not, see if there's one WITH brackets + else if (substitutions.has(std::string(match[0].first, match[0].second))) + { + replacement = substitutions[std::string(match[0].first, match[0].second)].asString(); + found_replacement = true; + } + + if (found_replacement) + { + // found a replacement + // "hello world" is output + output << std::string(start, match[0].first) << replacement; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output << std::string(start, match[0].second); + } + + // update search position + start = match[0].second; + } + // send the remainder of the string (with no further matches for bracketed names) + output << std::string(start, end); + return output.str(); +} + +std::string LLNotification::getMessage() const +{ + // all our callers cache this result, so it gives us more flexibility + // to do the substitution at call time rather than attempting to + // cache it in the notification + if (!mTemplatep) + return std::string(); + return format(mTemplatep->mMessage, mSubstitutions); +} + +std::string LLNotification::getLabel() const +{ + return (mTemplatep ? format(mTemplatep->mLabel, mSubstitutions) : ""); +} + + + +// ========================================================= +// LLNotificationChannel implementation +// --- +void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type& slot) +{ + // when someone wants to connect to a channel, we first throw them + // all of the notifications that are already in the channel + // we use a special signal called "load" in case the channel wants to care + // only about new notifications + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + slot.get_slot_function()(LLSD().insert("sigtype", "load").insert("id", (*it)->id())); + } + // and then connect the signal so that all future notifications will also be + // forwarded. + mChanged.connect(slot); +} + +void LLNotificationChannelBase::connectPassedFilter(const LLStandardSignal::slot_type& slot) +{ + // these two filters only fire for notifications added after the current one, because + // they don't participate in the hierarchy. + mPassedFilter.connect(slot); +} + +void LLNotificationChannelBase::connectFailedFilter(const LLStandardSignal::slot_type& slot) +{ + mFailedFilter.connect(slot); +} + +// external call, conforms to our standard signature +bool LLNotificationChannelBase::updateItem(const LLSD& payload) +{ + // first check to see if it's in the master list + LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]); + if (!pNotification) + return false; // not found + + return updateItem(payload, pNotification); +} + + +//FIX QUIT NOT WORKING + + +// internal call, for use in avoiding lookup +bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) +{ + std::string cmd = payload["sigtype"]; + LLNotificationSet::iterator foundItem = mItems.find(pNotification); + bool wasFound = (foundItem != mItems.end()); + bool passesFilter = mFilter(pNotification); + + // first, we offer the result of the filter test to the simple + // signals for pass/fail. One of these is guaranteed to be called. + // If either signal returns true, the change processing is NOT performed + // (so don't return true unless you know what you're doing!) + bool abortProcessing = false; + if (passesFilter) + { + abortProcessing = mPassedFilter(payload); + } + else + { + abortProcessing = mFailedFilter(payload); + } + + if (abortProcessing) + { + return true; + } + + if (cmd == "load") + { + // should be no reason we'd ever get a load if we already have it + // if passes filter send a load message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + abortProcessing = mChanged(payload); + onLoad(pNotification); + } + } + else if (cmd == "change") + { + // if it passes filter now and was found, we just send a change message + // if it passes filter now and wasn't found, we have to add it + // if it doesn't pass filter and wasn't found, we do nothing + // if it doesn't pass filter and was found, we need to delete it + if (passesFilter) + { + if (wasFound) + { + // it already existed, so this is a change + // since it changed in place, all we have to do is resend the signal + abortProcessing = mChanged(payload); + onChange(pNotification); + } + else + { + // not in our list, add it and say so + mItems.insert(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "add"; + abortProcessing = mChanged(newpayload); + onChange(pNotification); + } + } + else + { + if (wasFound) + { + // it already existed, so this is a delete + mItems.erase(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "delete"; + abortProcessing = mChanged(newpayload); + onChange(pNotification); + } + // didn't pass, not on our list, do nothing + } + } + else if (cmd == "add") + { + // should be no reason we'd ever get an add if we already have it + // if passes filter send an add message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + abortProcessing = mChanged(payload); + onAdd(pNotification); + } + } + else if (cmd == "delete") + { + // if we have it in our list, pass on the delete, then delete it, else do nothing + if (wasFound) + { + abortProcessing = mChanged(payload); + mItems.erase(pNotification); + onDelete(pNotification); + } + } + return abortProcessing; +} + +LLNotificationChannel::LLNotificationChannel(const std::string& name, + const std::string& parent, + LLNotificationFilter filter, + LLNotificationComparator comparator) : +LLNotificationChannelBase(filter, comparator), +mName(name), +mParent(parent) +{ + // store myself in the channel map + LLNotifications::instance().addChannel(LLNotificationChannelPtr(this)); + // bind to notification broadcast + if (parent.empty()) + { + LLNotifications::instance().connectChanged( + boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); + } + else + { + LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent); + LLStandardSignal::slot_type f = boost::bind(&LLNotificationChannelBase::updateItem, this, _1); + p->connectChanged(f); + } +} + + +void LLNotificationChannel::setComparator(LLNotificationComparator comparator) +{ + mComparator = comparator; + LLNotificationSet s2(mComparator); + s2.insert(mItems.begin(), mItems.end()); + mItems.swap(s2); + + // notify clients that we've been resorted + mChanged(LLSD().insert("sigtype", "sort")); +} + +bool LLNotificationChannel::isEmpty() const +{ + return mItems.empty(); +} + +LLNotificationChannel::Iterator LLNotificationChannel::begin() +{ + return mItems.begin(); +} + +LLNotificationChannel::Iterator LLNotificationChannel::end() +{ + return mItems.end(); +} + +std::string LLNotificationChannel::summarize() +{ + std::string s("Channel '"); + s += mName; + s += "'\n "; + for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it) + { + s += (*it)->summarize(); + s += "\n "; + } + return s; +} + + +// --- +// END OF LLNotificationChannel implementation +// ========================================================= + + +// ========================================================= +// LLNotifications implementation +// --- +LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything, + LLNotificationComparators::orderByUUID()) +{ +} + + +// The expiration channel gets all notifications that are cancelled +bool LLNotifications::expirationFilter(LLNotificationPtr pNotification) +{ + return pNotification->isCancelled() || pNotification->isRespondedTo(); +} + +bool LLNotifications::expirationHandler(const LLSD& payload) +{ + if (payload["sigtype"].asString() != "delete") + { + // anything added to this channel actually should be deleted from the master + cancel(find(payload["id"])); + return true; // don't process this item any further + } + return false; +} + +bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif) +{ + if (!pNotif->hasUniquenessConstraints()) + { + return true; + } + + // checks against existing unique notifications + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + return false; + } + } + + return true; +} + +bool LLNotifications::uniqueHandler(const LLSD& payload) +{ + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (pNotif && pNotif->hasUniquenessConstraints()) + { + if (payload["sigtype"].asString() == "add") + { + // not a duplicate according to uniqueness criteria, so we keep it + // and store it for future uniqueness checks + mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); + } + else if (payload["sigtype"].asString() == "delete") + { + mUniqueNotifications.erase(pNotif->getName()); + } + } + + return false; +} + +bool LLNotifications::failedUniquenessTest(const LLSD& payload) +{ + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + + if (!pNotif || !pNotif->hasUniquenessConstraints()) + { + return false; + } + + // checks against existing unique notifications + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + // copy notification instance data over to oldest instance + // of this unique notification and update it + existing_notification->updateFrom(pNotif); + // then delete the new one + pNotif->cancel(); + } + } + + return false; +} + + +void LLNotifications::addChannel(LLNotificationChannelPtr pChan) +{ + mChannels[pChan->getName()] = pChan; +} + +LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName) +{ + ChannelMap::iterator p = mChannels.find(channelName); + if(p == mChannels.end()) + { + llerrs << "Did not find channel named " << channelName << llendl; + } + return p->second; +} + + +// this function is called once at construction time, after the object is constructed. +void LLNotifications::initSingleton() +{ + loadTemplates(); + createDefaultChannels(); +} + +void LLNotifications::createDefaultChannels() +{ + // now construct the various channels AFTER loading the notifications, + // because the history channel is going to rewrite the stored notifications file + new LLNotificationChannel("Expiration", "", + boost::bind(&LLNotifications::expirationFilter, this, _1)); + new LLNotificationChannel("Unexpired", "", + !boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind + new LLNotificationChannel("Unique", "Unexpired", + boost::bind(&LLNotifications::uniqueFilter, this, _1)); + new LLNotificationChannel("Ignore", "Unique", + filterIgnoredNotifications); + new LLNotificationChannel("Visible", "Ignore", + &LLNotificationFilters::includeEverything); + + // create special history channel + //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" ); + // use ^^^ when done debugging notifications serialization + std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" ); + new LLNotificationHistoryChannel(notifications_log_file); + + // connect action methods to these channels + LLNotifications::instance().getChannel("Expiration")-> + connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); + LLNotifications::instance().getChannel("Unique")-> + connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1)); + LLNotifications::instance().getChannel("Unique")-> + connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1)); + LLNotifications::instance().getChannel("Ignore")-> + connectFailedFilter(&handleIgnoredNotification); +} + +static std::string sStringSkipNextTime("Skip this dialog next time"); +static std::string sStringAlwaysChoose("Always choose this option"); + +bool LLNotifications::addTemplate(const std::string &name, + LLNotificationTemplatePtr theTemplate) +{ + if (mTemplates.count(name)) + { + llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl; + return false; + } + mTemplates[name] = theTemplate; + return true; +} + +LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name) +{ + if (mTemplates.count(name)) + { + return mTemplates[name]; + } + else + { + return mTemplates["MissingAlert"]; + } +} + +bool LLNotifications::templateExists(const std::string& name) +{ + return (mTemplates.count(name) != 0); +} + +void LLNotifications::clearTemplates() +{ + mTemplates.clear(); +} + +void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) +{ + LLNotificationPtr temp_notify(new LLNotification(params)); + LLSD response = temp_notify->getResponseTemplate(); + LLSD selected_item = temp_notify->getForm()->getElement(option); + + if (selected_item.isUndefined()) + { + llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl; + return; + } + response[selected_item["name"].asString()] = true; + + temp_notify->respond(response); +} + +LLNotifications::TemplateNames LLNotifications::getTemplateNames() const +{ + TemplateNames names; + for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it) + { + names.push_back(it->first); + } + return names; +} + +typedef std::map<std::string, std::string> StringMap; +void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) +{ + //llwarns << "replaceSubstitutionStrings" << llendl; + // walk the list of attributes looking for replacements + for (LLXMLAttribList::iterator it=node->mAttributes.begin(); + it != node->mAttributes.end(); ++it) + { + std::string value = it->second->getValue(); + if (value[0] == '$') + { + value.erase(0, 1); // trim off the $ + std::string replacement; + StringMap::const_iterator found = replacements.find(value); + if (found != replacements.end()) + { + replacement = found->second; + //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl; + + it->second->setValue(replacement); + } + else + { + llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl; + } + } + } + + // now walk the list of children and call this recursively. + for (LLXMLNodePtr child = node->getFirstChild(); + child.notNull(); child = child->getNextSibling()) + { + replaceSubstitutionStrings(child, replacements); + } +} + +// private to this file +// returns true if the template request was invalid and there's nothing else we +// can do with this node, false if you should keep processing (it may have +// replaced the contents of the node referred to) +LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item) +{ + if (item->hasName("usetemplate")) + { + std::string replacementName; + if (item->getAttributeString("name", replacementName)) + { + StringMap replacements; + for (LLXMLAttribList::const_iterator it=item->mAttributes.begin(); + it != item->mAttributes.end(); ++it) + { + replacements[it->second->getName()->mString] = it->second->getValue(); + } + if (mXmlTemplates.count(replacementName)) + { + item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]); + + // walk the nodes looking for $(substitution) here and replace + replaceSubstitutionStrings(item, replacements); + } + else + { + llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl; + } + } + } + return item; +} + +bool LLNotifications::loadTemplates() +{ + const std::string xml_filename = "notifications.xml"; + LLXMLNodePtr root; + + BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); + + if (!success || root.isNull() || !root->hasName( "notifications" )) + { + llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; + return false; + } + + clearTemplates(); + + for (LLXMLNodePtr item = root->getFirstChild(); + item.notNull(); item = item->getNextSibling()) + { + // we do this FIRST so that item can be changed if we + // encounter a usetemplate -- we just replace the + // current xml node and keep processing + item = checkForXMLTemplate(item); + + if (item->hasName("global")) + { + std::string global_name; + if (item->getAttributeString("name", global_name)) + { + mGlobalStrings[global_name] = item->getTextContents(); + } + continue; + } + + if (item->hasName("template")) + { + // store an xml template; templates must have a single node (can contain + // other nodes) + std::string name; + item->getAttributeString("name", name); + LLXMLNodePtr ptr = item->getFirstChild(); + mXmlTemplates[name] = ptr; + continue; + } + + if (!item->hasName("notification")) + { + llwarns << "Unexpected entity " << item->getName()->mString << + " found in " << xml_filename << llendl; + continue; + } + + // now we know we have a notification entry, so let's build it + LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate()); + + if (!item->getAttributeString("name", pTemplate->mName)) + { + llwarns << "Unable to parse notification with no name" << llendl; + continue; + } + + //llinfos << "Parsing " << pTemplate->mName << llendl; + + pTemplate->mMessage = item->getTextContents(); + pTemplate->mDefaultFunctor = pTemplate->mName; + item->getAttributeString("type", pTemplate->mType); + item->getAttributeString("icon", pTemplate->mIcon); + item->getAttributeString("label", pTemplate->mLabel); + item->getAttributeU32("duration", pTemplate->mExpireSeconds); + item->getAttributeU32("expireOption", pTemplate->mExpireOption); + + std::string priority; + item->getAttributeString("priority", priority); + pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; + if (!priority.empty()) + { + if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW; + if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; + if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH; + if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL; + } + + item->getAttributeString("functor", pTemplate->mDefaultFunctor); + + BOOL persist = false; + item->getAttributeBOOL("persist", persist); + pTemplate->mPersist = persist; + + std::string sound; + item->getAttributeString("sound", sound); + if (!sound.empty()) + { + // TODO: test for bad sound effect name / missing effect + pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->getString(sound.c_str())); + } + + for (LLXMLNodePtr child = item->getFirstChild(); + !child.isNull(); child = child->getNextSibling()) + { + child = checkForXMLTemplate(child); + + // <url> + if (child->hasName("url")) + { + pTemplate->mURL = child->getTextContents(); + child->getAttributeU32("option", pTemplate->mURLOption); + } + + if (child->hasName("unique")) + { + pTemplate->mUnique = true; + for (LLXMLNodePtr formitem = child->getFirstChild(); + !formitem.isNull(); formitem = formitem->getNextSibling()) + { + if (formitem->hasName("context")) + { + std::string key; + formitem->getAttributeString("key", key); + pTemplate->mUniqueContext.push_back(key); + //llwarns << "adding " << key << " to unique context" << llendl; + } + else + { + llwarns << "'unique' has unrecognized subelement " + << formitem->getName()->mString << llendl; + } + } + } + + // <form> + if (child->hasName("form")) + { + pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child)); + } + } + addTemplate(pTemplate->mName, pTemplate); + } + + //std::ostringstream ostream; + //root->writeToOstream(ostream, "\n "); + //llwarns << ostream.str() << llendl; + + return true; +} + +// we provide a couple of simple add notification functions so that it's reasonable to create notifications in one line +LLNotificationPtr LLNotifications::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload) +{ + return add(LLNotification::Params(name).substitutions(substitutions).payload(payload)); +} + +LLNotificationPtr LLNotifications::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + const std::string& functor_name) +{ + return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor_name(functor_name)); +} + +LLNotificationPtr LLNotifications::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor) +{ + return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor(functor)); +} + +// generalized add function that takes a parameter block object for more complex instantiations +LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) +{ + LLNotificationPtr pNotif(new LLNotification(p)); + add(pNotif); + return pNotif; +} + + +void LLNotifications::add(const LLNotificationPtr pNotif) +{ + // first see if we already have it -- if so, that's a problem + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + llerrs << "Notification added a second time to the master notification channel." << llendl; + } + + updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif); +} + +void LLNotifications::cancel(LLNotificationPtr pNotif) +{ + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it == mItems.end()) + { + llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; + } + updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif); + pNotif->cancel(); +} + +void LLNotifications::update(const LLNotificationPtr pNotif) +{ + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif); + } +} + + +LLNotificationPtr LLNotifications::find(LLUUID uuid) +{ + LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid)); + LLNotificationSet::iterator it=mItems.find(target); + if (it == mItems.end()) + { + llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl; + return LLNotificationPtr((LLNotification*)NULL); + } + else + { + return *it; + } +} + +void LLNotifications::forEachNotification(NotificationProcess process) +{ + std::for_each(mItems.begin(), mItems.end(), process); +} + +std::string LLNotifications::getGlobalString(const std::string& key) const +{ + GlobalStringMap::const_iterator it = mGlobalStrings.find(key); + if (it != mGlobalStrings.end()) + { + return it->second; + } + else + { + // if we don't have the key as a global, return the key itself so that the error + // is self-diagnosing. + return key; + } +} + + +// --- +// END OF LLNotifications implementation +// ========================================================= + +std::ostream& operator<<(std::ostream& s, const LLNotification& notification) +{ + s << notification.summarize(); + return s; +} + diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h new file mode 100644 index 0000000000..2a2003f499 --- /dev/null +++ b/indra/llui/llnotifications.h @@ -0,0 +1,892 @@ +/** +* @file llnotifications.h +* @brief Non-UI manager and support for keeping a prioritized list of notifications +* @author Q (with assistance from Richard and Coco) +* +* $LicenseInfo:firstyear=2008&license=viewergpl$ +* +* Copyright (c) 2008, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLNOTIFICATIONS_H +#define LL_LLNOTIFICATIONS_H + +/** + * This system is intended to provide a singleton mechanism for adding + * notifications to one of an arbitrary set of event channels. + * + * Controlling JIRA: DEV-9061 + * + * Every notification has (see code for full list): + * - a textual name, which is used to look up its template in the XML files + * - a payload, which is a block of LLSD + * - a channel, which is normally extracted from the XML files but + * can be overridden. + * - a timestamp, used to order the notifications + * - expiration time -- if nonzero, specifies a time after which the + * notification will no longer be valid. + * - a callback name and a couple of status bits related to callbacks (see below) + * + * There is a management class called LLNotifications, which is an LLSingleton. + * The class maintains a collection of all of the notifications received + * or processed during this session, and also manages the persistence + * of those notifications that must be persisted. + * + * We also have Channels. A channel is a view on a collection of notifications; + * The collection is defined by a filter function that controls which + * notifications are in the channel, and its ordering is controlled by + * a comparator. + * + * There is a hierarchy of channels; notifications flow down from + * the management class (LLNotifications, which itself inherits from + * The channel base class) to the individual channels. + * Any change to notifications (add, delete, modify) is + * automatically propagated through the channel hierarchy. + * + * We provide methods for adding a new notification, for removing + * one, and for managing channels. Channels are relatively cheap to construct + * and maintain, so in general, human interfaces should use channels to + * select and manage their lists of notifications. + * + * We also maintain a collection of templates that are loaded from the + * XML file of template translations. The system supports substitution + * of named variables from the payload into the XML file. + * + * By default, only the "unknown message" template is built into the system. + * It is not an error to add a notification that's not found in the + * template system, but it is logged. + * + */ + +#include <string> +#include <list> +#include <vector> +#include <map> +#include <set> +#include <iomanip> +#include <sstream> + +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signal.hpp> +#include <boost/type_traits.hpp> + +// we want to minimize external dependencies, but this one is important +#include "llsd.h" + +// and we need this to manage the notification callbacks +#include "llfunctorregistry.h" +#include "llui.h" + +class LLNotification; +typedef boost::shared_ptr<LLNotification> LLNotificationPtr; + +/***************************************************************************** +* Signal and handler declarations +* Using a single handler signature means that we can have a common handler +* type, rather than needing a distinct one for each different handler. +*****************************************************************************/ + +/** + * A boost::signals Combiner that stops the first time a handler returns true + * We need this because we want to have our handlers return bool, so that + * we have the option to cause a handler to stop further processing. The + * default handler fails when the signal returns a value but has no slots. + */ +struct LLStopWhenHandled +{ + typedef bool result_type; + + template<typename InputIterator> + result_type operator()(InputIterator first, InputIterator last) const + { + for (InputIterator si = first; si != last; ++si) + { + if (*si) + { + return true; + } + } + return false; + } +}; + + +typedef enum e_notification_priority +{ + NOTIFICATION_PRIORITY_UNSPECIFIED, + NOTIFICATION_PRIORITY_LOW, + NOTIFICATION_PRIORITY_NORMAL, + NOTIFICATION_PRIORITY_HIGH, + NOTIFICATION_PRIORITY_CRITICAL +} ENotificationPriority; + +/** + * We want to have a standard signature for all signals; this way, + * we can easily document a protocol for communicating across + * dlls and into scripting languages someday. + * we want to return a bool to indicate whether the signal has been + * handled and should NOT be passed on to other listeners. + * Return true to stop further handling of the signal, and false + * to continue. + * We take an LLSD because this way the contents of the signal + * are independent of the API used to communicate it. + * It is const ref because then there's low cost to pass it; + * if you only need to inspect it, it's very cheap. + */ + +typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder; + +typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry; +typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration; + +typedef boost::signal<bool(const LLSD&), LLStopWhenHandled> LLStandardSignal; + +// context data that can be looked up via a notification's payload by the display logic +// derive from this class to implement specific contexts +class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID> +{ +public: + LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID()) + { + } + + virtual ~LLNotificationContext() {} + + LLSD asLLSD() const + { + return getKey(); + } + +private: + +}; + +// Contains notification form data, such as buttons and text fields along with +// manipulator functions +class LLNotificationForm +{ + LOG_CLASS(LLNotificationForm); + +public: + typedef enum e_ignore_type + { + IGNORE_NO, + IGNORE_WITH_DEFAULT_RESPONSE, + IGNORE_WITH_LAST_RESPONSE, + IGNORE_SHOW_AGAIN + } EIgnoreType; + + LLNotificationForm(); + LLNotificationForm(const LLSD& sd); + LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node); + + LLSD asLLSD() const; + + S32 getNumElements() { return mFormData.size(); } + LLSD getElement(S32 index) { return mFormData.get(index); } + LLSD getElement(const std::string& element_name); + bool hasElement(const std::string& element_name); + void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD()); + void formatElements(const LLSD& substitutions); + // appends form elements from another form serialized as LLSD + void append(const LLSD& sub_form); + std::string getDefaultOption(); + + EIgnoreType getIgnoreType() { return mIgnore; } + std::string getIgnoreMessage() { return mIgnoreMsg; } + +private: + LLSD mFormData; + EIgnoreType mIgnore; + std::string mIgnoreMsg; +}; + +typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr; + +// This is the class of object read from the XML file (notifications.xml, +// from the appropriate local language directory). +struct LLNotificationTemplate +{ + LLNotificationTemplate(); + // the name of the notification -- the key used to identify it + // Ideally, the key should follow variable naming rules + // (no spaces or punctuation). + std::string mName; + // The type of the notification + // used to control which queue it's stored in + std::string mType; + // The text used to display the notification. Replaceable parameters + // are enclosed in square brackets like this []. + std::string mMessage; + // The label for the notification; used for + // certain classes of notification (those with a window and a window title). + // Also used when a notification pops up underneath the current one. + // Replaceable parameters can be used in the label. + std::string mLabel; + // The name of the icon image. This should include an extension. + std::string mIcon; + // This is the Highlander bit -- "There Can Be Only One" + // An outstanding notification with this bit set + // is updated by an incoming notification with the same name, + // rather than creating a new entry in the queue. + // (used for things like progress indications, or repeating warnings + // like "the grid is going down in N minutes") + bool mUnique; + // if we want to be unique only if a certain part of the payload is constant + // specify the field names for the payload. The notification will only be + // combined if all of the fields named in the context are identical in the + // new and the old notification; otherwise, the notification will be + // duplicated. This is to support suppressing duplicate offers from the same + // sender but still differentiating different offers. Example: Invitation to + // conference chat. + std::vector<std::string> mUniqueContext; + // If this notification expires automatically, this value will be + // nonzero, and indicates the number of seconds for which the notification + // will be valid (a teleport offer, for example, might be valid for + // 300 seconds). + U32 mExpireSeconds; + // if the offer expires, one of the options is chosen automatically + // based on its "value" parameter. This controls which one. + // If expireSeconds is specified, expireOption should also be specified. + U32 mExpireOption; + // if the notification contains a url, it's stored here (and replaced + // into the message where [_URL] is found) + std::string mURL; + // if there's a URL in the message, this controls which option visits + // that URL. Obsolete this and eliminate the buttons for affected + // messages when we allow clickable URLs in the UI + U32 mURLOption; + // does this notification persist across sessions? if so, it will be + // serialized to disk on first receipt and read on startup + bool mPersist; + // This is the name of the default functor, if present, to be + // used for the notification's callback. It is optional, and used only if + // the notification is constructed without an identified functor. + std::string mDefaultFunctor; + // The form data associated with a given notification (buttons, text boxes, etc) + LLNotificationFormPtr mForm; + // default priority for notifications of this type + ENotificationPriority mPriority; + // UUID of the audio file to be played when this notification arrives + // this is loaded as a name, but looked up to get the UUID upon template load. + // If null, it wasn't specified. + LLUUID mSoundEffect; +}; + +// we want to keep a map of these by name, and it's best to manage them +// with smart pointers +typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr; + +/** + * @class LLNotification + * @brief The object that expresses the details of a notification + * + * We make this noncopyable because + * we want to manage these through LLNotificationPtr, and only + * ever create one instance of any given notification. + * + * The enable_shared_from_this flag ensures that if we construct + * a smart pointer from a notification, we'll always get the same + * shared pointer. + */ +class LLNotification : + boost::noncopyable, + public boost::enable_shared_from_this<LLNotification> +{ +LOG_CLASS(LLNotification); +friend class LLNotifications; + +public: + // parameter object used to instantiate a new notification + class Params : public LLParamBlock<Params> + { + friend class LLNotification; + public: + Params(const std::string& _name) + : name(_name), + mTemporaryResponder(false), + functor_name(_name), + priority(NOTIFICATION_PRIORITY_UNSPECIFIED), + timestamp(LLDate::now()) + { + } + + // pseudo-param + Params& functor(LLNotificationFunctorRegistry::ResponseFunctor f) + { + functor_name = LLUUID::generateNewID().asString(); + LLNotificationFunctorRegistry::instance().registerFunctor(functor_name, f); + + mTemporaryResponder = true; + return *this; + } + + LLMandatoryParam<std::string> name; + + // optional + LLOptionalParam<LLSD> substitutions; + LLOptionalParam<LLSD> payload; + LLOptionalParam<ENotificationPriority> priority; + LLOptionalParam<LLSD> form_elements; + LLOptionalParam<LLDate> timestamp; + LLOptionalParam<LLNotificationContext*> context; + LLOptionalParam<std::string> functor_name; + + private: + bool mTemporaryResponder; + }; + +private: + + LLUUID mId; + LLSD mPayload; + LLSD mSubstitutions; + LLDate mTimestamp; + LLDate mExpiresAt; + bool mCancelled; + bool mRespondedTo; // once the notification has been responded to, this becomes true + bool mIgnored; + ENotificationPriority mPriority; + LLNotificationFormPtr mForm; + + // a reference to the template + LLNotificationTemplatePtr mTemplatep; + + /* + We want to be able to store and reload notifications so that they can survive + a shutdown/restart of the client. So we can't simply pass in callbacks; + we have to specify a callback mechanism that can be used by name rather than + by some arbitrary pointer -- and then people have to initialize callbacks + in some useful location. So we use LLNotificationFunctorRegistry to manage them. + */ + std::string mResponseFunctorName; + + /* + In cases where we want to specify an explict, non-persisted callback, + we store that in the callback registry under a dynamically generated + key, and store the key in the notification, so we can still look it up + using the same mechanism. + */ + bool mTemporaryResponder; + + void init(const std::string& template_name, const LLSD& form_elements); + + LLNotification(const Params& p); + + // this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT + // for anything real! + LLNotification(LLUUID uuid) : mId(uuid) {} + + void cancel(); + + bool payloadContainsAll(const std::vector<std::string>& required_fields) const; + +public: + + // constructor from a saved notification + LLNotification(const LLSD& sd); + + // This is a string formatter for substituting into the message directly + // from LLSD without going through the hopefully-to-be-obsoleted LLString + static std::string format(const std::string& text, const LLSD& substitutions); + + void setResponseFunctor(std::string const &responseFunctorName); + + typedef enum e_response_template_type + { + WITHOUT_DEFAULT_BUTTON, + WITH_DEFAULT_BUTTON + } EResponseTemplateType; + + // return response LLSD filled in with default form contents and (optionally) the default button selected + LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON); + + // returns index of first button with value==TRUE + // usually this the button the user clicked on + // returns -1 if no button clicked (e.g. form has not been displayed) + static S32 getSelectedOption(const LLSD& notification, const LLSD& response); + // returns name of first button with value==TRUE + static std::string getSelectedOptionName(const LLSD& notification); + + // after someone responds to a notification (usually by clicking a button, + // but sometimes by filling out a little form and THEN clicking a button), + // the result of the response (the name and value of the button clicked, + // plus any other data) should be packaged up as LLSD, then passed as a + // parameter to the notification's respond() method here. This will look up + // and call the appropriate responder. + // + // response is notification serialized as LLSD: + // ["name"] = notification name + // ["form"] = LLSD tree that includes form description and any prefilled form data + // ["response"] = form data filled in by user + // (including, but not limited to which button they clicked on) + // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification), + // ["item_id"] (attached inventory item), etc. + // ["substitutions"] = string substitutions used to generate notification message + // from the template + // ["time"] = time at which notification was generated; + // ["expiry"] = time at which notification expires; + // ["responseFunctor"] = name of registered functor that handles responses to notification; + LLSD asLLSD(); + + void respond(const LLSD& sd); + + void setIgnored(bool ignore); + + bool isCancelled() const + { + return mCancelled; + } + + bool isRespondedTo() const + { + return mRespondedTo; + } + + bool isIgnored() const + { + return mIgnored; + } + + const std::string& getName() const + { + return mTemplatep->mName; + } + + const LLUUID& id() const + { + return mId; + } + + const LLSD& getPayload() const + { + return mPayload; + } + + const LLSD& getSubstitutions() const + { + return mSubstitutions; + } + + const LLDate& getDate() const + { + return mTimestamp; + } + + std::string getType() const + { + return (mTemplatep ? mTemplatep->mType : ""); + } + + std::string getMessage() const; + std::string getLabel() const; + + std::string getURL() const + { + return (mTemplatep ? mTemplatep->mURL : ""); + } + + S32 getURLOption() const + { + return (mTemplatep ? mTemplatep->mURLOption : -1); + } + + const LLNotificationFormPtr getForm(); + + const LLDate getExpiration() const + { + return mExpiresAt; + } + + ENotificationPriority getPriority() const + { + return mPriority; + } + + const LLUUID getID() const + { + return mId; + } + + // comparing two notifications normally means comparing them by UUID (so we can look them + // up quickly this way) + bool operator<(const LLNotification& rhs) const + { + return mId < rhs.mId; + } + + bool operator==(const LLNotification& rhs) const + { + return mId == rhs.mId; + } + + bool operator!=(const LLNotification& rhs) const + { + return !operator==(rhs); + } + + bool isSameObjectAs(const LLNotification* rhs) const + { + return this == rhs; + } + + // this object has been updated, so tell all our clients + void update(); + + void updateFrom(LLNotificationPtr other); + + // A fuzzy equals comparator. + // true only if both notifications have the same template and + // 1) flagged as unique (there can be only one of these) OR + // 2) all required payload fields of each also exist in the other. + bool isEquivalentTo(LLNotificationPtr that) const; + + // if the current time is greater than the expiration, the notification is expired + bool isExpired() const + { + if (mExpiresAt.secondsSinceEpoch() == 0) + { + return false; + } + + LLDate rightnow = LLDate::now(); + return rightnow > mExpiresAt; + } + + std::string summarize() const; + + bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);} + + virtual ~LLNotification() {} +}; + +std::ostream& operator<<(std::ostream& s, const LLNotification& notification); + +namespace LLNotificationFilters +{ + // a sample filter + bool includeEverything(LLNotificationPtr p); + + typedef enum e_comparison + { + EQUAL, + LESS, + GREATER, + LESS_EQUAL, + GREATER_EQUAL + } EComparison; + + // generic filter functor that takes method or member variable reference + template<typename T> + struct filterBy + { + typedef boost::function<T (LLNotificationPtr)> field_t; + typedef typename boost::remove_reference<T>::type value_t; + + filterBy(field_t field, value_t value, EComparison comparison = EQUAL) + : mField(field), + mFilterValue(value), + mComparison(comparison) + { + } + + bool operator()(LLNotificationPtr p) + { + switch(mComparison) + { + case EQUAL: + return mField(p) == mFilterValue; + case LESS: + return mField(p) < mFilterValue; + case GREATER: + return mField(p) > mFilterValue; + case LESS_EQUAL: + return mField(p) <= mFilterValue; + case GREATER_EQUAL: + return mField(p) >= mFilterValue; + default: + return false; + } + } + + field_t mField; + value_t mFilterValue; + EComparison mComparison; + }; +}; + +namespace LLNotificationComparators +{ + typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection; + + // generic order functor that takes method or member variable reference + template<typename T> + struct orderBy + { + typedef boost::function<T (LLNotificationPtr)> field_t; + orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {} + bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs) + { + if (mDirection == ORDER_DECREASING) + { + return mField(lhs) > mField(rhs); + } + else + { + return mField(lhs) < mField(rhs); + } + } + + field_t mField; + EDirection mDirection; + }; + + struct orderByUUID : public orderBy<const LLUUID&> + { + orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {} + }; + + struct orderByDate : public orderBy<const LLDate&> + { + orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {} + }; +}; + +typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter; +typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator; +typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet; +typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap; + +// ======================================================== +// Abstract base class (interface) for a channel; also used for the master container. +// This lets us arrange channels into a call hierarchy. + +// We maintain a heirarchy of notification channels; events are always started at the top +// and propagated through the hierarchy only if they pass a filter. +// Any channel can be created with a parent. A null parent (empty string) means it's +// tied to the root of the tree (the LLNotifications class itself). +// The default hierarchy looks like this: +// +// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History +// +-- Alerts +// +-- Notifications +// +// In general, new channels that want to only see notifications that pass through +// all of the built-in tests should attach to the "Visible" channel +// +class LLNotificationChannelBase : + public boost::signals::trackable +{ + LOG_CLASS(LLNotificationChannelBase); +public: + LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : + mFilter(filter), mItems(comp) + {} + virtual ~LLNotificationChannelBase() {} + // you can also connect to a Channel, so you can be notified of + // changes to this channel + virtual void connectChanged(const LLStandardSignal::slot_type& slot); + virtual void connectPassedFilter(const LLStandardSignal::slot_type& slot); + virtual void connectFailedFilter(const LLStandardSignal::slot_type& slot); + + // use this when items change or to add a new one + bool updateItem(const LLSD& payload); + const LLNotificationFilter& getFilter() { return mFilter; } + +protected: + LLNotificationSet mItems; + LLStandardSignal mChanged; + LLStandardSignal mPassedFilter; + LLStandardSignal mFailedFilter; + + // these are action methods that subclasses can override to take action + // on specific types of changes; the management of the mItems list is + // still handled by the generic handler. + virtual void onLoad(LLNotificationPtr p) {} + virtual void onAdd(LLNotificationPtr p) {} + virtual void onDelete(LLNotificationPtr p) {} + virtual void onChange(LLNotificationPtr p) {} + + bool updateItem(const LLSD& payload, LLNotificationPtr pNotification); + LLNotificationFilter mFilter; +}; + +// manages a list of notifications +// Note that if this is ever copied around, we might find ourselves with multiple copies +// of a queue with notifications being added to different nonequivalent copies. So we +// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it. +// +// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to +// do something like: +// new LLNotificationChannel("name", "parent"...); +// You can then retrieve the channel by using the registry: +// LLNotifications::instance().getChannel("name")... +// +class LLNotificationChannel : + boost::noncopyable, + public LLNotificationChannelBase +{ + LOG_CLASS(LLNotificationChannel); + +public: + virtual ~LLNotificationChannel() {} + // Notification Channels have a filter, which determines which notifications + // will be added to this channel. + // Channel filters cannot change. + LLNotificationChannel(const std::string& name, const std::string& parent, + LLNotificationFilter filter=LLNotificationFilters::includeEverything, + LLNotificationComparator comparator=LLNotificationComparators::orderByUUID()); + + typedef LLNotificationSet::iterator Iterator; + + std::string getName() const { return mName; } + std::string getParentChannelName() { return mParent; } + + bool isEmpty() const; + + Iterator begin(); + Iterator end(); + + // Channels have a comparator to control sort order; + // the default sorts by arrival date + void setComparator(LLNotificationComparator comparator); + + std::string summarize(); + +private: + std::string mName; + std::string mParent; + LLNotificationComparator mComparator; +}; + + + +// The type of the pointers that we're going to manage in the NotificationQueue system +// Because LLNotifications is a singleton, we don't actually expect to ever +// destroy it, but if it becomes necessary to do so, the shared_ptr model +// will ensure that we don't leak resources. +typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr; + +class LLNotifications : + public LLSingleton<LLNotifications>, + public LLNotificationChannelBase +{ + LOG_CLASS(LLNotifications); + + friend class LLSingleton<LLNotifications>; +public: + // load notification descriptions from file; + // OK to call more than once because it will reload + bool loadTemplates(); + LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item); + + // we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions = LLSD(), + const LLSD& payload = LLSD()); + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + const std::string& functor_name); + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor); + LLNotificationPtr add(const LLNotification::Params& p); + + void add(const LLNotificationPtr pNotif); + void cancel(LLNotificationPtr pNotif); + void update(const LLNotificationPtr pNotif); + + LLNotificationPtr find(LLUUID uuid); + + typedef boost::function<void (LLNotificationPtr)> NotificationProcess; + + void forEachNotification(NotificationProcess process); + + // This is all stuff for managing the templates + // take your template out + LLNotificationTemplatePtr getTemplate(const std::string& name); + + // get the whole collection + typedef std::vector<std::string> TemplateNames; + TemplateNames getTemplateNames() const; // returns a list of notification names + + typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap; + + TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); } + TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); } + + // test for existence + bool templateExists(const std::string& name); + // useful if you're reloading the file + void clearTemplates(); // erase all templates + + void forceResponse(const LLNotification::Params& params, S32 option); + + void createDefaultChannels(); + + typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap; + ChannelMap mChannels; + + void addChannel(LLNotificationChannelPtr pChan); + LLNotificationChannelPtr getChannel(const std::string& channelName); + + std::string getGlobalString(const std::string& key) const; + +private: + // we're a singleton, so we don't have a public constructor + LLNotifications(); + /*virtual*/ void initSingleton(); + + void loadPersistentNotifications(); + + bool expirationFilter(LLNotificationPtr pNotification); + bool expirationHandler(const LLSD& payload); + bool uniqueFilter(LLNotificationPtr pNotification); + bool uniqueHandler(const LLSD& payload); + bool failedUniquenessTest(const LLSD& payload); + LLNotificationChannelPtr pHistoryChannel; + LLNotificationChannelPtr pExpirationChannel; + + // put your template in + bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate); + TemplateMap mTemplates; + + std::string mFileName; + + typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap; + XMLTemplateMap mXmlTemplates; + + LLNotificationMap mUniqueNotifications; + + typedef std::map<std::string, std::string> GlobalStringMap; + GlobalStringMap mGlobalStrings; +}; + + +#endif//LL_LLNOTIFICATIONS_H + diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 22934450e7..2edbbe6abc 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -58,8 +58,6 @@ #include "llresizebar.h" #include "llcriticaldamp.h" -LLPanel::alert_queue_t LLPanel::sAlertQueue; - const S32 RESIZE_BAR_OVERLAP = 1; const S32 RESIZE_BAR_HEIGHT = 3; @@ -344,14 +342,14 @@ BOOL LLPanel::checkRequirements() { if (!mRequirementsError.empty()) { - LLStringUtil::format_map_t args; - args["[COMPONENTS]"] = mRequirementsError; - args["[FLOATER]"] = getName(); + LLSD args; + args["COMPONENTS"] = mRequirementsError; + args["FLOATER"] = getName(); llwarns << getName() << " failed requirements check on: \n" << mRequirementsError << llendl; - - alertXml(std::string("FailedRequirementsCheck"), args); + + LLNotifications::instance().add(LLNotification::Params("FailedRequirementsCheck").payload(args)); mRequirementsError.clear(); return FALSE; } @@ -359,25 +357,6 @@ BOOL LLPanel::checkRequirements() return TRUE; } -//static -void LLPanel::alertXml(const std::string& label, LLStringUtil::format_map_t args) -{ - sAlertQueue.push(LLAlertInfo(label,args)); -} - -//static -BOOL LLPanel::nextAlert(LLAlertInfo &alert) -{ - if (!sAlertQueue.empty()) - { - alert = sAlertQueue.front(); - sAlertQueue.pop(); - return TRUE; - } - - return FALSE; -} - void LLPanel::setFocus(BOOL b) { if( b ) @@ -1039,9 +1018,9 @@ void LLPanel::childDisplayNotFound() mExpectedMembers.insert(*itor); } mNewExpectedMembers.clear(); - LLStringUtil::format_map_t args; - args["[CONTROLS]"] = msg; - LLAlertDialog::showXml("FloaterNotFound", args); + LLSD args; + args["CONTROLS"] = msg; + LLNotifications::instance().add("FloaterNotFound", args); } void LLPanel::storeRectControl() @@ -1065,6 +1044,8 @@ struct LLLayoutStack::LLEmbeddedPanel mAutoResize(auto_resize), mUserResize(user_resize), mOrientation(orientation), + mCollapsed(FALSE), + mCollapseAmt(0.f), mVisibleAmt(1.f) // default to fully visible { LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; @@ -1095,14 +1076,28 @@ struct LLLayoutStack::LLEmbeddedPanel mResizeBar = NULL; } + F32 getCollapseFactor() + { + if (mOrientation == HORIZONTAL) + { + return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)mPanel->getRect().getWidth()); + } + else + { + return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinHeight / (F32)mPanel->getRect().getHeight()); + } + } + LLPanel* mPanel; S32 mMinWidth; S32 mMinHeight; BOOL mAutoResize; BOOL mUserResize; + BOOL mCollapsed; LLResizeBar* mResizeBar; eLayoutOrientation mOrientation; F32 mVisibleAmt; + F32 mCollapseAmt; }; static LLRegisterWidget<LLLayoutStack> r2("layout_stack"); @@ -1123,28 +1118,27 @@ LLLayoutStack::~LLLayoutStack() void LLLayoutStack::draw() { updateLayout(); + + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { - e_panel_list_t::iterator panel_it; - for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + // clip to layout rectangle, not bounding rectangle + LLRect clip_rect = (*panel_it)->mPanel->getRect(); + // scale clipping rectangle by visible amount + if (mOrientation == HORIZONTAL) { - // clip to layout rectangle, not bounding rectangle - LLRect clip_rect = (*panel_it)->mPanel->getRect(); - // scale clipping rectangle by visible amount - if (mOrientation == HORIZONTAL) - { - clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->mVisibleAmt); - } - else - { - clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->mVisibleAmt); - } + clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); + } + else + { + clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); + } - LLPanel* panelp = (*panel_it)->mPanel; + LLPanel* panelp = (*panel_it)->mPanel; - LLLocalClipRect clip(clip_rect); - // only force drawing invisible children if visible amount is non-zero - drawChild(panelp, 0, 0, !clip_rect.isNull()); - } + LLLocalClipRect clip(clip_rect); + // only force drawing invisible children if visible amount is non-zero + drawChild(panelp, 0, 0, !clip_rect.isNull()); } } @@ -1276,8 +1270,13 @@ S32 LLLayoutStack::getDefaultWidth(S32 cur_width) return cur_width; } -void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index) +void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index) { + // panel starts off invisible (collapsed) + if (animate == ANIMATE) + { + panel->setVisible(FALSE); + } LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize); mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel); @@ -1293,6 +1292,11 @@ void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL sendChildToFront(resize_barp); } + // start expanding panel animation + if (animate == ANIMATE) + { + panel->setVisible(TRUE); + } } void LLLayoutStack::removePanel(LLPanel* panel) @@ -1300,6 +1304,14 @@ void LLLayoutStack::removePanel(LLPanel* panel) removeChild(panel); } +void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed) +{ + LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel); + if (!panel_container) return; + + panel_container->mCollapsed = collapsed; +} + void LLLayoutStack::updateLayout(BOOL force_resize) { calcMinExtents(); @@ -1332,6 +1344,15 @@ void LLLayoutStack::updateLayout(BOOL force_resize) } } + if ((*panel_it)->mCollapsed) + { + (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); + } + else + { + (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); + } + if (mOrientation == HORIZONTAL) { // enforce minimize size constraint by default @@ -1339,7 +1360,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize) { panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight()); } - total_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt); + total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor()); // want n-1 panel gaps for n panels if (panel_it != mPanels.begin()) { @@ -1353,7 +1374,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize) { panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight); } - total_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt); + total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor()); if (panel_it != mPanels.begin()) { total_height += mPanelSpacing; @@ -1367,7 +1388,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize) for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { // panels that are not fully visible do not count towards shrink headroom - if ((*panel_it)->mVisibleAmt < 1.f) + if ((*panel_it)->getCollapseFactor() < 1.f) { continue; } @@ -1431,7 +1452,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize) S32 delta_size = 0; // if panel can automatically resize (not animating, and resize flag set)... - if ((*panel_it)->mVisibleAmt == 1.f + if ((*panel_it)->getCollapseFactor() == 1.f && (force_resize || (*panel_it)->mAutoResize) && !(*panel_it)->mResizeBar->hasMouseCapture()) { @@ -1515,11 +1536,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize) if (mOrientation == HORIZONTAL) { - cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + mPanelSpacing; + cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing; } else //VERTICAL { - cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + mPanelSpacing; + cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing; } } diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index c55eb6bba2..da876667e6 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -49,23 +49,13 @@ const BOOL BORDER_YES = TRUE; const BOOL BORDER_NO = FALSE; -struct LLAlertInfo -{ - std::string mLabel; - LLStringUtil::format_map_t mArgs; - - LLAlertInfo(std::string label, LLStringUtil::format_map_t args) : mLabel(label), mArgs(args) { } - LLAlertInfo(){} -}; - - /* * General purpose concrete view base class. * Transparent or opaque, * With or without border, * Can contain LLUICtrls. */ -class LLPanel : public LLUICtrl +class LLPanel : public LLUICtrl, public boost::signals::trackable { public: @@ -227,8 +217,6 @@ public: void childNotFound(const std::string& id) const; void childDisplayNotFound(); - static void alertXml(const std::string& label, LLStringUtil::format_map_t args = LLStringUtil::format_map_t()); - static BOOL nextAlert(LLAlertInfo &alert); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); protected: @@ -266,8 +254,6 @@ private: std::string mRequirementsError; - typedef std::queue<LLAlertInfo> alert_queue_t; - static alert_queue_t sAlertQueue; }; // end class LLPanel @@ -292,8 +278,16 @@ public: S32 getMinWidth() const { return mMinWidth; } S32 getMinHeight() const { return mMinHeight; } - void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index = S32_MAX); + typedef enum e_animate + { + NO_ANIMATE, + ANIMATE + } EAnimate; + + void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX); void removePanel(LLPanel* panel); + void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE); + S32 getNumPanels() { return mPanels.size(); } private: struct LLEmbeddedPanel; diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index a7163323bd..734b3ab381 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -127,6 +127,8 @@ LLScrollbar::LLScrollbar( } line_up_btn->setHeldDownCallback( &LLScrollbar::onLineUpBtnPressed ); line_up_btn->setTabStop(FALSE); + line_up_btn->setScaleImage(TRUE); + addChild(line_up_btn); LLButton* line_down_btn = new LLButton(std::string("Line Down"), line_down_rect, @@ -136,6 +138,7 @@ LLScrollbar::LLScrollbar( line_down_btn->setFollowsBottom(); line_down_btn->setHeldDownCallback( &LLScrollbar::onLineDownBtnPressed ); line_down_btn->setTabStop(FALSE); + line_down_btn->setScaleImage(TRUE); addChild(line_down_btn); } @@ -148,20 +151,29 @@ LLScrollbar::~LLScrollbar() void LLScrollbar::setDocParams( S32 size, S32 pos ) { mDocSize = size; - mDocPos = llclamp( pos, 0, getDocPosMax() ); + setDocPos(pos); mDocChanged = TRUE; updateThumbRect(); } -void LLScrollbar::setDocPos(S32 pos) +void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { + pos = llclamp(pos, 0, getDocPosMax()); if (pos != mDocPos) { - mDocPos = llclamp( pos, 0, getDocPosMax() ); + mDocPos = pos; mDocChanged = TRUE; - updateThumbRect(); + if( mChangeCallback ) + { + mChangeCallback( mDocPos, this, mCallbackUserData ); + } + + if( update_thumb ) + { + updateThumbRect(); + } } } @@ -170,7 +182,7 @@ void LLScrollbar::setDocSize(S32 size) if (size != mDocSize) { mDocSize = size; - mDocPos = llclamp( mDocPos, 0, getDocPosMax() ); + setDocPos(mDocPos); mDocChanged = TRUE; updateThumbRect(); @@ -182,7 +194,7 @@ void LLScrollbar::setPageSize( S32 page_size ) if (page_size != mPageSize) { mPageSize = page_size; - mDocPos = llclamp( mDocPos, 0, getDocPosMax() ); + setDocPos(mDocPos); mDocChanged = TRUE; updateThumbRect(); @@ -208,9 +220,9 @@ void LLScrollbar::updateThumbRect() const S32 THUMB_MIN_LENGTH = 16; S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); - S32 thumb_bg_length = window_length - 2 * SCROLLBAR_SIZE; + S32 thumb_bg_length = llmax(0, window_length - 2 * SCROLLBAR_SIZE); S32 visible_lines = llmin( mDocSize, mPageSize ); - S32 thumb_length = mDocSize ? llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH ) : thumb_bg_length; + S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length; S32 variable_lines = mDocSize - visible_lines; @@ -218,7 +230,7 @@ void LLScrollbar::updateThumbRect() { S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE; S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH; - S32 thumb_start = variable_lines ? llclamp( thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min, thumb_start_max ) : thumb_start_max; + S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max; mThumbRect.mLeft = 0; mThumbRect.mTop = thumb_start; @@ -230,7 +242,7 @@ void LLScrollbar::updateThumbRect() // Horizontal S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length; S32 thumb_start_min = SCROLLBAR_SIZE; - S32 thumb_start = variable_lines ? llclamp( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min, thumb_start_max ) : thumb_start_min; + S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min; mThumbRect.mLeft = thumb_start; mThumbRect.mTop = SCROLLBAR_SIZE; @@ -446,7 +458,7 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask) } else { - // Opaque, so don't just check children + // Opaque, so don't just check children handled = LLView::handleMouseUp( x, y, mask ); } @@ -455,13 +467,31 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask) void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) { + if (width == getRect().getWidth() && height == getRect().getHeight()) return; LLView::reshape( width, height, called_from_parent ); + LLButton* up_button = getChild<LLButton>("Line Up"); + LLButton* down_button = getChild<LLButton>("Line Down"); + + if (mOrientation == VERTICAL) + { + up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE)); + down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE)); + up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight()); + } + else + { + up_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), up_button->getRect().getHeight()); + down_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), down_button->getRect().getHeight()); + down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom); + } updateThumbRect(); } void LLScrollbar::draw() { + if (!getRect().isValid()) return; + S32 local_mouse_x; S32 local_mouse_y; LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y); @@ -531,21 +561,7 @@ void LLScrollbar::draw() void LLScrollbar::changeLine( S32 delta, BOOL update_thumb ) { - S32 new_pos = llclamp( mDocPos + delta, 0, getDocPosMax() ); - if( new_pos != mDocPos ) - { - mDocPos = new_pos; - } - - if( mChangeCallback ) - { - mChangeCallback( mDocPos, this, mCallbackUserData ); - } - - if( update_thumb ) - { - updateThumbRect(); - } + setDocPos(mDocPos + delta, update_thumb); } void LLScrollbar::setValue(const LLSD& value) @@ -561,22 +577,22 @@ BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask) switch( key ) { case KEY_HOME: - changeLine( -mDocPos, TRUE ); + setDocPos( 0 ); handled = TRUE; break; case KEY_END: - changeLine( getDocPosMax() - mDocPos, TRUE ); + setDocPos( getDocPosMax() ); handled = TRUE; break; case KEY_DOWN: - changeLine( mStepSize, TRUE ); + setDocPos( getDocPos() + mStepSize ); handled = TRUE; break; case KEY_UP: - changeLine( - mStepSize, TRUE ); + setDocPos( getDocPos() - mStepSize ); handled = TRUE; break; diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index d35dc10bd4..5fdacd43f8 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -81,7 +81,7 @@ public: // How many "lines" the "document" has scrolled. // 0 <= DocPos <= DocSize - DocVisibile - void setDocPos( S32 pos ); + void setDocPos( S32 pos, BOOL update_thumb = TRUE ); S32 getDocPos() const { return mDocPos; } BOOL isAtBeginning(); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index c0f21ba9e5..ea0c6d4b2f 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -378,6 +378,22 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col TRUE); } +LLScrollListDate::LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible) +: LLScrollListText(date.asRFC1123(), font, width, font_style, font_alignment, color, use_color, visible), + mDate(date) +{ +} + +void LLScrollListDate::setValue(const LLSD& value) +{ + mDate = value.asDate(); + LLScrollListText::setValue(mDate.asRFC1123()); +} + +const LLSD LLScrollListDate::getValue() const +{ + return mDate; +} LLScrollListItem::~LLScrollListItem() { @@ -578,6 +594,7 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mSearchColumn(0), mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), + mTotalColumnPadding(0), mSorted(TRUE), mDirty(FALSE), mOriginalSelection(-1), @@ -627,6 +644,28 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mLastSelected = NULL; } +S32 LLScrollListCtrl::getSearchColumn() +{ + // search for proper search column + if (mSearchColumn < 0) + { + LLScrollListItem* itemp = getFirstData(); + if (itemp) + { + for(S32 column = 0; column < getNumColumns(); column++) + { + LLScrollListCell* cell = itemp->getColumn(column); + if (cell && cell->isText()) + { + mSearchColumn = column; + break; + } + } + } + } + return llclamp(mSearchColumn, 0, getNumColumns()); +} + LLScrollListCtrl::~LLScrollListCtrl() { std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); @@ -890,8 +929,8 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r // *TODO: Use bookkeeping to make this an incramental cost with item additions void LLScrollListCtrl::calcColumnWidths() { - const S32 HEADING_TEXT_PADDING = 30; - const S32 COLUMN_TEXT_PADDING = 20; + const S32 HEADING_TEXT_PADDING = 25; + const S32 COLUMN_TEXT_PADDING = 10; mMaxContentWidth = 0; @@ -904,20 +943,17 @@ void LLScrollListCtrl::calcColumnWidths() if (!column) continue; // update column width - S32 new_width = column->mWidth; + S32 new_width = column->getWidth(); if (column->mRelWidth >= 0) { new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth()); } else if (column->mDynamicWidth) { - new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns; + new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns; } - if (new_width != column->mWidth) - { - column->mWidth = new_width; - } + column->setWidth(new_width); // update max content width for this column, by looking at all items column->mMaxContentWidth = column->mHeader ? LLFontGL::sSansSerifSmall->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0; @@ -971,28 +1007,13 @@ void LLScrollListCtrl::updateColumns() { calcColumnWidths(); - // propagate column widths to individual cells - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - S32 num_cols = itemp->getNumColumns(); - S32 i = 0; - for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) - { - if (i >= (S32)mColumnsIndexed.size()) break; - - cell->setWidth(mColumnsIndexed[i]->mWidth); - } - } - // update column headers std::vector<LLScrollListColumn*>::iterator column_ordered_it; S32 left = mItemListRect.mLeft; LLColumnHeader* last_header = NULL; for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) { - if ((*column_ordered_it)->mWidth < 0) + if ((*column_ordered_it)->getWidth() < 0) { // skip hidden columns continue; @@ -1001,9 +1022,11 @@ void LLScrollListCtrl::updateColumns() if (column->mHeader) { + column->mHeader->updateResizeBars(); + last_header = column->mHeader; S32 top = mItemListRect.mTop; - S32 right = left + column->mWidth; + S32 right = left + column->getWidth(); if (column->mIndex != (S32)mColumnsIndexed.size()-1) { @@ -1021,14 +1044,30 @@ void LLScrollListCtrl::updateColumns() } } - //FIXME: stretch the entire last column if it is resizable (gestures windows shows truncated text in last column) // expand last column header we encountered to full list width - if (last_header) + if (last_header && last_header->canResize()) { S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); last_header->reshape(new_width, last_header->getRect().getHeight()); last_header->setVisible(mDisplayColumnHeaders && new_width > 0); + last_header->getColumn()->setWidth(new_width); + } + + // propagate column widths to individual cells + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + S32 num_cols = itemp->getNumColumns(); + S32 i = 0; + for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) + { + if (i >= (S32)mColumnsIndexed.size()) break; + + cell->setWidth(mColumnsIndexed[i]->getWidth()); + } } + } void LLScrollListCtrl::setDisplayHeading(BOOL display) @@ -1490,7 +1529,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen { LLScrollListItem* item = *iter; // Only select enabled items with matching names - LLScrollListCell* cellp = item->getColumn(mSearchColumn); + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; if (select) { @@ -1513,7 +1552,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen LLScrollListItem* item = *iter; // Only select enabled items with matching names - LLScrollListCell* cellp = item->getColumn(mSearchColumn); + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); if (!cellp) { continue; @@ -1743,6 +1782,8 @@ void LLScrollListCtrl::drawItems() void LLScrollListCtrl::draw() { + LLLocalClipRect clip(getLocalRect()); + // if user specifies sort, make sure it is maintained if (needsSorting() && !isSorted()) { @@ -1816,7 +1857,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sti S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft; S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item)); LLRect cell_rect; - cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->mWidth, mLineHeight); + cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->getWidth(), mLineHeight); // Convert rect local to screen coordinates localPointToScreen( cell_rect.mLeft, cell_rect.mBottom, @@ -2113,7 +2154,7 @@ S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x) ordered_columns_t::const_iterator end = mColumnsIndexed.end(); for ( ; iter != end; ++iter) { - width = (*iter)->mWidth + mColumnPadding; + width = (*iter)->getWidth() + mColumnPadding; right += width; if (left <= x && x < right ) { @@ -2140,7 +2181,7 @@ S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index) { return column_offset; } - column_offset += (*iter)->mWidth + mColumnPadding; + column_offset += (*iter)->getWidth() + mColumnPadding; } // when running off the end, return the rightmost pixel @@ -2292,7 +2333,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask ) { if (getFirstSelected()) { - LLScrollListCell* cellp = getFirstSelected()->getColumn(mSearchColumn); + LLScrollListCell* cellp = getFirstSelected()->getColumn(getSearchColumn()); if (cellp) { cellp->highlightText(0, 0); @@ -2379,7 +2420,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) { LLScrollListItem* item = *iter; - LLScrollListCell* cellp = item->getColumn(mSearchColumn); + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); if (cellp) { // Only select enabled items with matching first characters @@ -2446,7 +2487,7 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it { if (mLastSelected) { - LLScrollListCell* cellp = mLastSelected->getColumn(mSearchColumn); + LLScrollListCell* cellp = mLastSelected->getColumn(getSearchColumn()); if (cellp) { cellp->highlightText(0, 0); @@ -2474,7 +2515,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp) } itemp->setSelected(FALSE); - LLScrollListCell* cellp = itemp->getColumn(mSearchColumn); + LLScrollListCell* cellp = itemp->getColumn(getSearchColumn()); if (cellp) { cellp->highlightText(0, 0); @@ -2501,9 +2542,14 @@ struct SameSortColumn bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; } }; -BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending) +BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) { - sort_column_t new_sort_column(column, ascending); + LLScrollListColumn* sort_column = getColumn(column_idx); + if (!sort_column) return FALSE; + + sort_column->mSortAscending = ascending; + + sort_column_t new_sort_column(column_idx, ascending); if (mSortColumns.empty()) { @@ -2517,7 +2563,7 @@ BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending) // remove any existing sort criterion referencing this column // and add the new one - mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column)), mSortColumns.end()); + mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column_idx)), mSortColumns.end()); mSortColumns.push_back(new_sort_column); // did the sort criteria change? @@ -2643,6 +2689,12 @@ void LLScrollListCtrl::scrollToShowSelected() } } +void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width) +{ + mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth()); +} + + // virtual LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const { @@ -2689,7 +2741,7 @@ LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const child_node->createChild("name", TRUE)->setStringValue(column->mName); child_node->createChild("label", TRUE)->setStringValue(column->mLabel); - child_node->createChild("width", TRUE)->setIntValue(column->mWidth); + child_node->createChild("width", TRUE)->setIntValue(column->getWidth()); } return node; @@ -2813,15 +2865,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac scroll_list->setSearchColumn(search_column); - if (sort_column >= 0) - { - scroll_list->sortByColumnIndex(sort_column, sort_ascending); - } - LLSD columns; S32 index = 0; LLXMLNodePtr child; - S32 total_static = 0; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("column")) @@ -2850,8 +2896,6 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac std::string tooltip; child->getAttributeString("tool_tip", tooltip); - if(!columndynamicwidth) total_static += llmax(0, columnwidth); - F32 columnrelwidth = 0.f; child->getAttributeF32("relwidth", columnrelwidth); @@ -2872,9 +2916,13 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac index++; } } - scroll_list->setTotalStaticColumnWidth(total_static); scroll_list->setColumnHeadings(columns); + if (sort_column >= 0) + { + scroll_list->sortByColumnIndex(sort_column, sort_ascending); + } + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { if (child->hasName("row")) @@ -3019,22 +3067,26 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos) if (mColumns.find(name) == mColumns.end()) { // Add column - mColumns[name] = LLScrollListColumn(column); + mColumns[name] = LLScrollListColumn(column, this); LLScrollListColumn* new_column = &mColumns[name]; new_column->mParentCtrl = this; new_column->mIndex = mColumns.size()-1; // Add button - if (new_column->mWidth > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth) + if (new_column->getWidth() > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth) { + if (getNumColumns() > 0) + { + mTotalColumnPadding += mColumnPadding; + } if (new_column->mRelWidth >= 0) { - new_column->mWidth = (S32)llround(new_column->mRelWidth*mItemListRect.getWidth()); + new_column->setWidth((S32)llround(new_column->mRelWidth*mItemListRect.getWidth())); } else if(new_column->mDynamicWidth) { mNumDynamicWidthColumns++; - new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns; + new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns); } S32 top = mItemListRect.mTop; S32 left = mItemListRect.mLeft; @@ -3043,14 +3095,14 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos) for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) { if (itor->second.mIndex < new_column->mIndex && - itor->second.mWidth > 0) + itor->second.getWidth() > 0) { - left += itor->second.mWidth + mColumnPadding; + left += itor->second.getWidth() + mColumnPadding; } } } std::string button_name = "btn_" + name; - S32 right = left+new_column->mWidth; + S32 right = left+new_column->getWidth(); if (new_column->mIndex != (S32)mColumns.size()-1) { right += mColumnPadding; @@ -3145,6 +3197,8 @@ void LLScrollListCtrl::clearColumns() } mColumns.clear(); mSortColumns.clear(); + mTotalStaticColumnWidth = 0; + mTotalColumnPadding = 0; } void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label) @@ -3244,7 +3298,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p } S32 index = columnp->mIndex; - S32 width = columnp->mWidth; + S32 width = columnp->getWidth(); LLFontGL::HAlign font_alignment = columnp->mFontAlignment; LLColor4 fcolor = LLColor4::black; @@ -3301,6 +3355,19 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p } new_item->setColumn(index, cell); } + else if (type == "date") + { + LLScrollListDate* cell = new LLScrollListDate(value.asDate(), font, width, font_style, font_alignment); + if (has_color) + { + cell->setColor(color); + } + new_item->setColumn(index, cell); + if (columnp->mHeader && !value.asString().empty()) + { + columnp->mHeader->setHasResizableElement(TRUE); + } + } else { LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment, fcolor, TRUE); @@ -3325,7 +3392,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p if (new_item->getColumn(column_idx) == NULL) { LLScrollListColumn* column_ptr = &column_it->second; - new_item->setColumn(column_idx, new LLScrollListText(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->mWidth, LLFontGL::NORMAL)); + new_item->setColumn(column_idx, new LLScrollListText(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->getWidth(), LLFontGL::NORMAL)); } } @@ -3469,6 +3536,7 @@ LLColumnHeader::LLColumnHeader(const std::string& label, const LLRect &rect, LLS mButton->setMouseDownCallback(onMouseDown); mButton->setCallbackUserData(this); + mButton->setToolTip(label); mAscendingText = std::string("[LOW]...[HIGH](Ascending)"); // *TODO: Translate mDescendingText = std::string("[HIGH]...[LOW](Descending)"); // *TODO: Translate @@ -3556,7 +3624,7 @@ void LLColumnHeader::onClick(void* user_data) LLScrollListCtrl::onClickColumn(column); - // propage new sort order to sort order list + // propagate new sort order to sort order list headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1); } @@ -3646,7 +3714,7 @@ void LLColumnHeader::showList() text_width = llmax(text_width, LLFontGL::sSansSerifSmall->getWidth(descending_string)) + 10; text_width = llmax(text_width, getRect().getWidth() - 30); - mList->getColumn(0)->mWidth = text_width; + mList->getColumn(0)->setWidth(text_width); ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string); ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string); @@ -3688,7 +3756,7 @@ LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_d llassert(snap_edge == SNAP_RIGHT); // use higher snap threshold for column headers - threshold = llmin(threshold, 15); + threshold = llmin(threshold, 10); LLRect snap_rect = getSnapRect(); @@ -3727,47 +3795,48 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect) if (delta_width != 0) { - S32 remaining_width = delta_width; + S32 remaining_width = -delta_width; S32 col; for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++) { LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp) break; + if (!columnp) continue; if (columnp->mHeader && columnp->mHeader->canResize()) { // how many pixels in width can this column afford to give up? - S32 resize_buffer_amt = llmax(0, columnp->mWidth - MIN_COLUMN_WIDTH); + S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH); // user shrinking column, need to add width to other columns if (delta_width < 0) { - if (!columnp->mDynamicWidth && columnp->mWidth > 0) + if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0) { // statically sized column, give all remaining width to this column - columnp->mWidth -= remaining_width; + columnp->setWidth(columnp->getWidth() + remaining_width); if (columnp->mRelWidth > 0.f) { - columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); + columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); } + // all padding went to this widget, we're done + break; } - break; } else { // user growing column, need to take width from other columns - remaining_width -= resize_buffer_amt; + remaining_width += resize_buffer_amt; - if (!columnp->mDynamicWidth && columnp->mWidth > 0) + if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0) { - columnp->mWidth -= llmin(columnp->mWidth - MIN_COLUMN_WIDTH, delta_width); + columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width)); if (columnp->mRelWidth > 0.f) { - columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); + columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); } } - if (remaining_width <= 0) + if (remaining_width >= 0) { // width sucked up from neighboring columns, done break; @@ -3779,14 +3848,14 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect) // clamp resize amount to maximum that can be absorbed by other columns if (delta_width > 0) { - delta_width -= llmax(remaining_width, 0); + delta_width += llmin(remaining_width, 0); } // propagate constrained delta_width to new width for this column new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding(); // use requested width - mColumn->mWidth = new_width; + mColumn->setWidth(new_width); // update proportional spacing if (mColumn->mRelWidth > 0.f) @@ -3804,36 +3873,40 @@ void LLColumnHeader::userSetShape(const LLRect& new_rect) void LLColumnHeader::setHasResizableElement(BOOL resizable) { // for now, dynamically spaced columns can't be resized - if (mColumn->mDynamicWidth) return; +// if (mColumn->mDynamicWidth) return; - if (resizable != mHasResizableElement) + if (mHasResizableElement != resizable) { + mColumn->mParentCtrl->dirtyColumns(); mHasResizableElement = resizable; + } +} - S32 num_resizable_columns = 0; - S32 col; - for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) +void LLColumnHeader::updateResizeBars() +{ + S32 num_resizable_columns = 0; + S32 col; + for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) + { + LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); + if (columnp->mHeader && columnp->mHeader->canResize()) { - LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (columnp->mHeader && columnp->mHeader->canResize()) - { - num_resizable_columns++; - } + num_resizable_columns++; } + } - S32 num_resizers_enabled = 0; + S32 num_resizers_enabled = 0; - // now enable/disable resize handles on resizable columns if we have at least two - for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) + // now enable/disable resize handles on resizable columns if we have at least two + for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) + { + LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); + if (!columnp->mHeader) continue; + BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); + columnp->mHeader->enableResizeBar(enable); + if (enable) { - LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp->mHeader) continue; - BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); - columnp->mHeader->enableResizeBar(enable); - if (enable) - { - num_resizers_enabled++; - } + num_resizers_enabled++; } } } @@ -3841,7 +3914,7 @@ void LLColumnHeader::setHasResizableElement(BOOL resizable) void LLColumnHeader::enableResizeBar(BOOL enable) { // for now, dynamically spaced columns can't be resized - if (!mColumn->mDynamicWidth) + //if (!mColumn->mDynamicWidth) { mResizeBar->setEnabled(enable); } @@ -3851,3 +3924,78 @@ BOOL LLColumnHeader::canResize() { return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth); } + +void LLScrollListColumn::setWidth(S32 width) +{ + if (!mDynamicWidth && mRelWidth <= 0.f) + { + mParentCtrl->updateStaticColumnWidth(this, width); + } + mWidth = width; +} + +// Default constructor +LLScrollListColumn::LLScrollListColumn() : + mName(), + mSortingColumn(), + mSortAscending(TRUE), + mLabel(), + mWidth(-1), + mRelWidth(-1.0), + mDynamicWidth(FALSE), + mMaxContentWidth(0), + mIndex(-1), + mParentCtrl(NULL), + mHeader(NULL), + mFontAlignment(LLFontGL::LEFT) +{ } + +LLScrollListColumn::LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent) : + mWidth(0), + mIndex (-1), + mParentCtrl(parent), + mHeader(NULL), + mMaxContentWidth(0), + mDynamicWidth(FALSE), + mRelWidth(-1.f) +{ + mName = sd.get("name").asString(); + mSortingColumn = mName; + if (sd.has("sort")) + { + mSortingColumn = sd.get("sort").asString(); + } + mSortAscending = TRUE; + if (sd.has("sort_ascending")) + { + mSortAscending = sd.get("sort_ascending").asBoolean(); + } + mLabel = sd.get("label").asString(); + if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0) + { + mRelWidth = (F32)sd.get("relwidth").asReal(); + if (mRelWidth < 0) mRelWidth = 0; + if (mRelWidth > 1) mRelWidth = 1; + mDynamicWidth = FALSE; + } + else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE) + { + mDynamicWidth = TRUE; + mRelWidth = -1; + } + else + { + + setWidth(sd.get("width").asInteger()); + } + + if (sd.has("halign")) + { + mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER); + } + else + { + mFontAlignment = LLFontGL::LEFT; + } + +} diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 0128c01eba..d8ef955042 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -47,6 +47,7 @@ #include "llcombobox.h" #include "llscrollbar.h" #include "llresizebar.h" +#include "lldate.h" /* * Represents a cell in a scrollable table. @@ -133,6 +134,18 @@ private: static U32 sCount; }; + +class LLScrollListDate : public LLScrollListText +{ +public: + LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width=0, U8 font_style = LLFontGL::NORMAL, LLFontGL::HAlign font_alignment = LLFontGL::LEFT, LLColor4& color = LLColor4::black, BOOL use_color = FALSE, BOOL visible = TRUE); + virtual void setValue(const LLSD& value); + virtual const LLSD getValue() const; + +private: + LLDate mDate; +}; + /* * Cell displaying an image. */ @@ -185,88 +198,11 @@ private: class LLScrollListColumn { public: - // Default constructor - LLScrollListColumn() : - mName(), - mSortingColumn(), - mSortAscending(TRUE), - mLabel(), - mWidth(-1), - mRelWidth(-1.0), - mDynamicWidth(FALSE), - mMaxContentWidth(0), - mIndex(-1), - mParentCtrl(NULL), - mHeader(NULL), - mFontAlignment(LLFontGL::LEFT) - { } - - LLScrollListColumn(std::string name, std::string label, S32 width, F32 relwidth) : - mName(name), - mSortingColumn(name), - mSortAscending(TRUE), - mLabel(label), - mWidth(width), - mRelWidth(relwidth), - mDynamicWidth(FALSE), - mMaxContentWidth(0), - mIndex(-1), - mParentCtrl(NULL), - mHeader(NULL), - mFontAlignment(LLFontGL::LEFT) - { } - - LLScrollListColumn(const LLSD &sd) - { - mMaxContentWidth = 0; - - mName = sd.get("name").asString(); - mSortingColumn = mName; - if (sd.has("sort")) - { - mSortingColumn = sd.get("sort").asString(); - } - mSortAscending = TRUE; - if (sd.has("sort_ascending")) - { - mSortAscending = sd.get("sort_ascending").asBoolean(); - } - mLabel = sd.get("label").asString(); - if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0) - { - mRelWidth = (F32)sd.get("relwidth").asReal(); - if (mRelWidth < 0) mRelWidth = 0; - if (mRelWidth > 1) mRelWidth = 1; - mDynamicWidth = FALSE; - mWidth = 0; - } - else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE) - { - mDynamicWidth = TRUE; - mRelWidth = -1; - mWidth = 0; - } - else - { - mWidth = sd.get("width").asInteger(); - mDynamicWidth = FALSE; - mRelWidth = -1; - } - - if (sd.has("halign")) - { - mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER); - } - else - { - mFontAlignment = LLFontGL::LEFT; - } - - mIndex = -1; - mParentCtrl = NULL; - mHeader = NULL; - mFontAlignment = LLFontGL::LEFT; - } + LLScrollListColumn(); + LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent); + + void setWidth(S32 width); + S32 getWidth() const { return mWidth; } // Public data is fine so long as this remains a simple struct-like data class. // If it ever gets any smarter than that, these should all become private @@ -275,7 +211,6 @@ public: std::string mSortingColumn; BOOL mSortAscending; std::string mLabel; - S32 mWidth; F32 mRelWidth; BOOL mDynamicWidth; S32 mMaxContentWidth; @@ -283,6 +218,10 @@ public: LLScrollListCtrl* mParentCtrl; class LLColumnHeader* mHeader; LLFontGL::HAlign mFontAlignment; + +private: + S32 mWidth; + }; class LLColumnHeader : public LLComboBox @@ -301,6 +240,7 @@ public: void setImage(const std::string &image_name); LLScrollListColumn* getColumn() { return mColumn; } void setHasResizableElement(BOOL resizable); + void updateResizeBars(); BOOL canResize(); void enableResizeBar(BOOL enable); std::string getLabel() { return mOrigLabel; } @@ -551,8 +491,7 @@ public: virtual S32 getScrollPos() const; virtual void setScrollPos( S32 pos ); - - S32 getSearchColumn() { return mSearchColumn; } + S32 getSearchColumn(); void setSearchColumn(S32 column) { mSearchColumn = column; } S32 getColumnIndexFromOffset(S32 x); S32 getColumnOffsetFromIndex(S32 index); @@ -613,8 +552,9 @@ public: virtual void deselect(); virtual BOOL canDeselect() const; - void setNumDynamicColumns(int num) { mNumDynamicWidthColumns = num; } - void setTotalStaticColumnWidth(int width) { mTotalStaticColumnWidth = width; } + void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } + void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); + S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } std::string getSortColumnName(); BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } @@ -719,6 +659,7 @@ private: S32 mSearchColumn; S32 mNumDynamicWidthColumns; S32 mTotalStaticColumnWidth; + S32 mTotalColumnPadding; BOOL mSorted; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index a4b16dc2de..7b2c97af67 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -30,6 +30,7 @@ */ // Utilities functions the user interface needs + #include "linden_common.h" #include <string> @@ -65,6 +66,7 @@ std::map<std::string, std::string> gTranslation; std::list<std::string> gUntranslated; LLControlGroup* LLUI::sConfigGroup = NULL; +LLControlGroup* LLUI::sIgnoresGroup = NULL; LLControlGroup* LLUI::sColorsGroup = NULL; LLImageProviderInterface* LLUI::sImageProvider = NULL; LLUIAudioCallback LLUI::sAudioCallback = NULL; @@ -90,7 +92,7 @@ void make_ui_sound(const char* namep) LLUUID uuid(LLUI::sConfigGroup->getString(name)); if (uuid.isNull()) { - if ("00000000-0000-0000-0000-000000000000" == LLUI::sConfigGroup->getString(name)) + if (LLUI::sConfigGroup->getString(name) == LLUUID::null.asString()) { if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle")) { @@ -1552,6 +1554,7 @@ bool handleShowXUINamesChanged(const LLSD& newvalue) } void LLUI::initClass(LLControlGroup* config, + LLControlGroup* ignores, LLControlGroup* colors, LLImageProviderInterface* image_provider, LLUIAudioCallback audio_callback, @@ -1559,7 +1562,16 @@ void LLUI::initClass(LLControlGroup* config, const std::string& language) { sConfigGroup = config; + sIgnoresGroup = ignores; sColorsGroup = colors; + + if (sConfigGroup == NULL + || sIgnoresGroup == NULL + || sColorsGroup == NULL) + { + llerrs << "Failure to initialize configuration groups" << llendl; + } + sImageProvider = image_provider; sAudioCallback = audio_callback; sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor; @@ -1567,7 +1579,7 @@ void LLUI::initClass(LLControlGroup* config, LLFontGL::sShadowColor = colors->getColor("ColorDropShadow"); LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames"); - LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(boost::bind(&handleShowXUINamesChanged, _1)); + LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(&handleShowXUINamesChanged); } void LLUI::cleanupClass() diff --git a/indra/llui/llui.h b/indra/llui/llui.h index e2629ee2a4..4366c38740 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -42,6 +42,7 @@ #include "llgl.h" // *TODO: break this dependency #include <stack> //#include "llimagegl.h" +#include <boost/signal.hpp> // LLUIFactory #include "llsd.h" @@ -150,11 +151,13 @@ typedef void (*LLUIAudioCallback)(const LLUUID& uuid); class LLUI { + LOG_CLASS(LLUI); public: // // Methods // static void initClass(LLControlGroup* config, + LLControlGroup* ignores, LLControlGroup* colors, LLImageProviderInterface* image_provider, LLUIAudioCallback audio_callback = NULL, @@ -190,6 +193,7 @@ public: // Data // static LLControlGroup* sConfigGroup; + static LLControlGroup* sIgnoresGroup; static LLControlGroup* sColorsGroup; static LLImageProviderInterface* sImageProvider; static LLUIAudioCallback sAudioCallback; @@ -597,4 +601,237 @@ public: virtual void cleanUp() = 0; }; +// This mix-in class adds support for tracking all instances of the specificed class parameter T +// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup +// If KEY is not provided, then instances are stored in a simple list +template<typename T, typename KEY = T*> +class LLInstanceTracker : boost::noncopyable +{ +public: + typedef typename std::map<KEY, T*>::iterator instance_iter; + typedef typename std::map<KEY, T*>::const_iterator instance_const_iter; + + static T* getInstance(KEY k) { instance_iter found = sInstances.find(k); return (found == sInstances.end()) ? NULL : found->second; } + + static instance_iter beginInstances() { return sInstances.begin(); } + static instance_iter endInstances() { return sInstances.end(); } + static S32 instanceCount() { return sInstances.size(); } +protected: + LLInstanceTracker(KEY key) { add(key); } + virtual ~LLInstanceTracker() { remove(); } + virtual void setKey(KEY key) { remove(); add(key); } + virtual const KEY& getKey() const { return mKey; } + +private: + void add(KEY key) + { + mKey = key; + sInstances[key] = static_cast<T*>(this); + } + void remove() { sInstances.erase(mKey); } + +private: + + KEY mKey; + static std::map<KEY, T*> sInstances; +}; + +template<typename T> +class LLInstanceTracker<T, T*> : boost::noncopyable +{ +public: + typedef typename std::set<T*>::iterator instance_iter; + typedef typename std::set<T*>::const_iterator instance_const_iter; + + static instance_iter instancesBegin() { return sInstances.begin(); } + static instance_iter instancesEnd() { return sInstances.end(); } + static S32 instanceCount() { return sInstances.size(); } + +protected: + LLInstanceTracker() { sInstances.insert(static_cast<T*>(this)); } + virtual ~LLInstanceTracker() { sInstances.erase(static_cast<T*>(this)); } + + static std::set<T*> sInstances; +}; + +template <typename T, typename KEY> std::map<KEY, T*> LLInstanceTracker<T, KEY>::sInstances; +template <typename T> std::set<T*> LLInstanceTracker<T, T*>::sInstances; + +class LLCallbackRegistry +{ +public: + typedef boost::signal<void()> callback_signal_t; + + void registerCallback(const callback_signal_t::slot_type& slot) + { + mCallbacks.connect(slot); + } + + void fireCallbacks() + { + mCallbacks(); + } + +private: + callback_signal_t mCallbacks; +}; + +class LLInitClassList : + public LLCallbackRegistry, + public LLSingleton<LLInitClassList> +{ + friend class LLSingleton<LLInitClassList>; +private: + LLInitClassList() {} +}; + +class LLDestroyClassList : + public LLCallbackRegistry, + public LLSingleton<LLDestroyClassList> +{ + friend class LLSingleton<LLDestroyClassList>; +private: + LLDestroyClassList() {} +}; + +template<typename T> +class LLRegisterWith +{ +public: + LLRegisterWith(boost::function<void ()> func) + { + T::instance().registerCallback(func); + } + + // this avoids a MSVC bug where non-referenced static members are "optimized" away + // even if their constructors have side effects + void reference() + { + S32 dummy; + dummy = 0; + } +}; + +template<typename T> +class LLInitClass +{ +public: + LLInitClass() { sRegister.reference(); } + + static LLRegisterWith<LLInitClassList> sRegister; +private: + + static void initClass() + { + llerrs << "No static initClass() method defined for " << typeid(T).name() << llendl; + } +}; + +template<typename T> +class LLDestroyClass +{ +public: + LLDestroyClass() { sRegister.reference(); } + + static LLRegisterWith<LLDestroyClassList> sRegister; +private: + + static void destroyClass() + { + llerrs << "No static destroyClass() method defined for " << typeid(T).name() << llendl; + } +}; + +template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass); +template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass); + + +template <typename DERIVED> +class LLParamBlock +{ +protected: + LLParamBlock() { sBlock = (DERIVED*)this; } + + typedef typename boost::add_const<DERIVED>::type Tconst; + + template <typename T> + class LLMandatoryParam + { + public: + typedef typename boost::add_const<T>::type T_const; + + LLMandatoryParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {} + LLMandatoryParam(const LLMandatoryParam<T>& other) : mVal(other.mVal) {} + + DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; } + operator T() const { return mVal; } + T operator=(T_const set_value) { mVal = set_value; return mVal; } + + private: + T mVal; + DERIVED* mBlock; + }; + + template <typename T> + class LLOptionalParam + { + public: + typedef typename boost::add_const<T>::type T_const; + + LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {} + LLOptionalParam() : mBlock(sBlock) {} + LLOptionalParam(const LLOptionalParam<T>& other) : mVal(other.mVal) {} + + DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; } + operator T() const { return mVal; } + T operator=(T_const set_value) { mVal = set_value; return mVal; } + + private: + T mVal; + DERIVED* mBlock; + }; + + // specialization that requires initialization for reference types + template <typename T> + class LLOptionalParam <T&> + { + public: + typedef typename boost::add_const<T&>::type T_const; + + LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {} + LLOptionalParam(const LLOptionalParam<T&>& other) : mVal(other.mVal) {} + + DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; } + operator T&() const { return mVal; } + T& operator=(T_const set_value) { mVal = set_value; return mVal; } + + private: + T& mVal; + DERIVED* mBlock; + }; + + // specialization that initializes pointer params to NULL + template<typename T> + class LLOptionalParam<T*> + { + public: + typedef typename boost::add_const<T*>::type T_const; + + LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {} + LLOptionalParam() : mVal((T*)NULL), mBlock(sBlock) {} + LLOptionalParam(const LLOptionalParam<T*>& other) : mVal(other.mVal) {} + + DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; } + operator T*() const { return mVal; } + T* operator=(T_const set_value) { mVal = set_value; return mVal; } + private: + T* mVal; + DERIVED* mBlock; + }; + + static DERIVED* sBlock; +}; + +template <typename T> T* LLParamBlock<T>::sBlock = NULL; + #endif diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index f7419d615b..6e822f7c03 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -475,10 +475,10 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only) return focusPrev(result); } -LLUICtrl* LLUICtrl::findRootMostFocusRoot() const +LLUICtrl* LLUICtrl::findRootMostFocusRoot() { - const LLUICtrl* focus_root = NULL; - const LLUICtrl* next_view = this; + LLUICtrl* focus_root = NULL; + LLUICtrl* next_view = this; while(next_view) { if (next_view->isFocusRoot()) @@ -487,9 +487,8 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot() const } next_view = next_view->getParentUICtrl(); } - // since focus_root could be this, need to cast away const to return - // a non-const result - return const_cast<LLUICtrl*>(focus_root); + + return focus_root; } diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 4ad9042b9a..7d1f504f79 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -141,7 +141,7 @@ public: static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); - LLUICtrl* findRootMostFocusRoot() const; + LLUICtrl* findRootMostFocusRoot(); class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter> { diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 3e22e196b0..dfcea7290e 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -78,6 +78,7 @@ public: static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); private: + bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root); typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t; built_panel_t mBuiltPanels; diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 0dde20934c..51768ad885 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -31,6 +31,7 @@ #include "linden_common.h" #include "lluistring.h" +#include "llsd.h" const LLStringUtil::format_map_t LLUIString::sNullArgs; @@ -54,6 +55,18 @@ void LLUIString::setArgList(const LLStringUtil::format_map_t& args) format(); } +void LLUIString::setArgs(const LLSD& sd) +{ + if (!sd.isMap()) return; + for(LLSD::map_const_iterator sd_it = sd.beginMap(); + sd_it != sd.endMap(); + ++sd_it) + { + setArg(sd_it->first, sd_it->second.asString()); + } + format(); +} + void LLUIString::setArg(const std::string& key, const std::string& replacement) { mArgs[key] = replacement; diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 773bc09763..c99aeb50c6 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -50,9 +50,9 @@ // llinfos << mMessage.getString() << llendl; // outputs "Welcome Steve to Second Life" // mMessage.setArg("[USERNAME]", "Joe"); // llinfos << mMessage.getString() << llendl; // outputs "Welcome Joe to Second Life" -// mMessage = "Recepción a la [SECONDLIFE] [USERNAME]" +// mMessage = "Recepci￳n a la [SECONDLIFE] [USERNAME]" // mMessage.setArg("[SECONDLIFE]", "Segunda Vida"); -// llinfos << mMessage.getString() << llendl; // outputs "Recepción a la Segunda Vida Joe" +// llinfos << mMessage.getString() << llendl; // outputs "Recepci￳n a la Segunda Vida Joe" // Implementation Notes: // Attempting to have operator[](const std::string& s) return mArgs[s] fails because we have @@ -71,6 +71,8 @@ public: LLUIString& operator=(const std::string& s) { assign(s); return *this; } void setArgList(const LLStringUtil::format_map_t& args); + void setArgs(const LLStringUtil::format_map_t& args) { setArgList(args); } + void setArgs(const class LLSD& sd); void setArg(const std::string& key, const std::string& replacement); const std::string& getString() const { return mResult; } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 3e7e59876c..65e9417b8b 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1260,7 +1260,7 @@ void LLView::draw() { LLView *viewp = *child_iter; - if (viewp->getVisible() && viewp != focus_view) + if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) { // Only draw views that are within the root view localRectToScreen(viewp->getRect(),&screenRect); @@ -1357,7 +1357,8 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr { ++sDepth; - if (childp->getVisible() || force_draw) + if ((childp->getVisible() && childp->getRect().isValid()) + || force_draw) { glMatrixMode(GL_MODELVIEW); LLUI::pushMatrix(); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index ff7a1afb38..ae0df61599 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -485,7 +485,7 @@ public: // did we find *something* with that name? if (child) { - llwarns << "Found child named " << name << " but of wrong type" << llendl; + llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T).name() << llendl; } if (create_if_missing) { @@ -496,6 +496,11 @@ public: return result; } + template <class T> T& getChildRef(const std::string& name, BOOL recurse = TRUE) const + { + return *getChild<T>(name, recurse, TRUE); + } + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; template <class T> T* createDummyWidget(const std::string& name) const diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 750c1fc1ef..aef1488e51 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -65,6 +65,9 @@ LLXMLNode::LLXMLNode() : mEncoding(ENCODING_DEFAULT), mParent(NULL), mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), mName(NULL), mValue(""), mDefault(NULL) @@ -83,6 +86,9 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : mEncoding(ENCODING_DEFAULT), mParent(NULL), mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), mValue(""), mDefault(NULL) { @@ -101,17 +107,65 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : mEncoding(ENCODING_DEFAULT), mParent(NULL), mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), mName(name), mValue(""), mDefault(NULL) { } +// copy constructor (except for the children) +LLXMLNode::LLXMLNode(const LLXMLNode& rhs) : + mID(rhs.mID), + mIsAttribute(rhs.mIsAttribute), + mVersionMajor(rhs.mVersionMajor), + mVersionMinor(rhs.mVersionMinor), + mLength(rhs.mLength), + mPrecision(rhs.mPrecision), + mType(rhs.mType), + mEncoding(rhs.mEncoding), + mParent(NULL), + mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), + mName(rhs.mName), + mValue(rhs.mValue), + mDefault(rhs.mDefault) +{ +} + +// returns a new copy of this node and all its children +LLXMLNodePtr LLXMLNode::deepCopy() +{ + LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this)); + if (mChildren.notNull()) + { + for (LLXMLChildList::iterator iter = mChildren->map.begin(); + iter != mChildren->map.end(); ++iter) + { + newnode->addChild(iter->second->deepCopy()); + } + } + for (LLXMLAttribList::iterator iter = mAttributes.begin(); + iter != mAttributes.end(); ++iter) + { + newnode->addChild(iter->second->deepCopy()); + } + + return newnode; +} + // virtual LLXMLNode::~LLXMLNode() { // Strictly speaking none of this should be required execept 'delete mChildren'... - if (mChildren) + // Sadly, that's only true if we hadn't had reference-counted smart pointers linked + // in three different directions. This entire class is a frightening, hard-to-maintain + // mess. + if (mChildren.notNull()) { for (LLXMLChildList::iterator iter = mChildren->map.begin(); iter != mChildren->map.end(); ++iter) @@ -124,7 +178,7 @@ LLXMLNode::~LLXMLNode() mChildren->map.clear(); mChildren->head = NULL; mChildren->tail = NULL; - delete mChildren; + mChildren = NULL; } for (LLXMLAttribList::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter) @@ -160,7 +214,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) return TRUE; } } - else if (mChildren) + else if (mChildren.notNull()) { LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName); while (children_itr != mChildren->map.end()) @@ -183,7 +237,6 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) mChildren->map.erase(children_itr); if (mChildren->map.empty()) { - delete mChildren; mChildren = NULL; } return TRUE; @@ -201,7 +254,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) return FALSE; } -void LLXMLNode::addChild(LLXMLNodePtr new_child) +void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child) { if (new_child->mParent != NULL) { @@ -219,7 +272,7 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child) } else { - if (!mChildren) + if (mChildren.isNull()) { mChildren = new LLXMLChildren(); mChildren->head = new_child; @@ -227,11 +280,33 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child) } mChildren->map.insert(std::make_pair(new_child->mName, new_child)); - if (mChildren->tail != new_child) + // if after_child is specified, it damn well better be in the list of children + // for this node. I'm not going to assert that, because it would be expensive, + // but don't specify that parameter if you didn't get the value for it from the + // list of children of this node! + if (after_child.isNull()) { - mChildren->tail->mNext = new_child; - new_child->mPrev = mChildren->tail; - mChildren->tail = new_child; + if (mChildren->tail != new_child) + { + mChildren->tail->mNext = new_child; + new_child->mPrev = mChildren->tail; + mChildren->tail = new_child; + } + } + else + { + if (after_child->mNext.notNull()) + { + // if after_child was not the last item, fix up some pointers + after_child->mNext->mPrev = new_child; + new_child->mNext = after_child->mNext; + } + new_child->mPrev = after_child; + after_child->mNext = new_child; + if (mChildren->tail == after_child) + { + mChildren->tail = new_child; + } } } @@ -293,7 +368,7 @@ void LLXMLNode::updateDefault() } } - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator children_itr; LLXMLChildList::const_iterator children_end = mChildren->map.end(); @@ -566,6 +641,24 @@ bool LLXMLNode::updateNode( } +// static +LLXMLNodePtr LLXMLNode::replaceNode(LLXMLNodePtr node, LLXMLNodePtr update_node) +{ + if (!node || !update_node) + { + llwarns << "Node invalid" << llendl; + return node; + } + + LLXMLNodePtr cloned_node = update_node->deepCopy(); + node->mParent->addChild(cloned_node, node); // add after node + LLXMLNodePtr parent = node->mParent; + parent->removeChild(node); + parent->updateDefault(); + + return cloned_node; +} + // static @@ -618,7 +711,7 @@ bool LLXMLNode::parseBuffer( { llwarns << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) - << " on lne " << XML_GetCurrentLineNumber(my_parser) + << " on line " << XML_GetCurrentLineNumber(my_parser) << llendl; } @@ -722,7 +815,7 @@ BOOL LLXMLNode::isFullyDefault() && has_default_length && has_default_attribute) { - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator children_itr; LLXMLChildList::const_iterator children_end = mChildren->map.end(); @@ -888,7 +981,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i } } - if (!mChildren && mValue == "") + if (mChildren.isNull() && mValue == "") { output_stream << " />\n"; return; @@ -896,7 +989,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i else { output_stream << ">\n"; - if (mChildren) + if (mChildren.notNull()) { // stream non-attributes std::string next_indent = indent + "\t"; @@ -922,7 +1015,7 @@ void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results) results.insert(std::make_pair(this->mName->mString, this)); return; } - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator children_itr; LLXMLChildList::const_iterator children_end = mChildren->map.end(); @@ -941,7 +1034,7 @@ void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results) results.insert(std::make_pair(this->mName->mString, this)); return; } - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator children_itr; LLXMLChildList::const_iterator children_end = mChildren->map.end(); @@ -960,7 +1053,7 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results) results.insert(std::make_pair(this->mName->mString, this)); return; } - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator children_itr; LLXMLChildList::const_iterator children_end = mChildren->map.end(); @@ -974,11 +1067,11 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results) void LLXMLNode::scrubToTree(LLXMLNode *tree) { - if (!tree || !tree->mChildren) + if (!tree || tree->mChildren.isNull()) { return; } - if (mChildren) + if (mChildren.notNull()) { std::vector<LLXMLNodePtr> to_delete_list; LLXMLChildList::iterator itor = mChildren->map.begin(); @@ -1023,7 +1116,7 @@ bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, BOOL use_default_ bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing) { - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); if (child_itr != mChildren->map.end()) @@ -1047,7 +1140,7 @@ void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, BOOL use_ void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const { - if (mChildren) + if (mChildren.notNull()) { LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); if (child_itr != mChildren->map.end()) @@ -1071,6 +1164,25 @@ void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &child } } +// recursively walks the tree and returns all children at all nesting levels matching the name +void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const +{ + if (mChildren.notNull()) + { + for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin(); + child_itr != mChildren->map.end(); ++child_itr) + { + LLXMLNodePtr child = (*child_itr).second; + if (name == child->mName) + { + children.insert(std::make_pair(child->mName->mString, child)); + } + // and check each child as well + child->getDescendants(name, children); + } + } +} + bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing) { return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing); @@ -1111,6 +1223,23 @@ BOOL LLXMLNode::hasAttribute(const char* name ) return getAttribute(name, node); } +// the structure of these getAttribute_ functions is ugly, but it's because the +// underlying system is based on BOOL and LLString; if we change +// so that they're based on more generic mechanisms, these will be +// simplified. +bool LLXMLNode::getAttribute_bool(const char* name, bool& value ) +{ + LLXMLNodePtr node; + if (!getAttribute(name, node)) + { + return false; + } + BOOL temp; + bool retval = node->getBoolValue(1, &temp); + value = temp; + return retval; +} + BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value ) { LLXMLNodePtr node; @@ -2521,7 +2650,7 @@ void LLXMLNode::setName(LLStringTableEntry* name) U32 LLXMLNode::getChildCount() const { - if (mChildren) + if (mChildren.notNull()) { return mChildren->map.size(); } @@ -2540,7 +2669,7 @@ U32 get_rand(U32 max_value) LLXMLNode *get_rand_node(LLXMLNode *node) { - if (node->mChildren) + if (node->mChildren.notNull()) { U32 num_children = node->mChildren->map.size(); if (get_rand(2) == 0) @@ -2748,7 +2877,7 @@ void LLXMLNode::createUnitTest(S32 max_num_children) BOOL LLXMLNode::performUnitTest(std::string &error_buffer) { - if (!mChildren) + if (mChildren.isNull()) { error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); return FALSE; @@ -3007,14 +3136,14 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) return TRUE; } -LLXMLNodePtr LLXMLNode::getFirstChild() +LLXMLNodePtr LLXMLNode::getFirstChild() const { - if (!mChildren) return NULL; + if (mChildren.isNull()) return NULL; LLXMLNodePtr ret = mChildren->head; return ret; } -LLXMLNodePtr LLXMLNode::getNextSibling() +LLXMLNodePtr LLXMLNode::getNextSibling() const { LLXMLNodePtr ret = mNext; return ret; diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index 5ca726effe..dec225dde6 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -87,12 +87,13 @@ class LLVector3d; class LLVector4; class LLVector4U; -struct LLXMLChildren +struct LLXMLChildren : public LLThreadSafeRefCount { LLXMLChildList map; // Map of children names->pointers LLXMLNodePtr head; // Head of the double-linked list LLXMLNodePtr tail; // Tail of the double-linked list }; +typedef LLPointer<LLXMLChildren> LLXMLChildrenPtr; class LLXMLNode : public LLThreadSafeRefCount { @@ -124,11 +125,13 @@ public: LLXMLNode(); LLXMLNode(const char* name, BOOL is_attribute); LLXMLNode(LLStringTableEntry* name, BOOL is_attribute); + LLXMLNode(const LLXMLNode& rhs); + LLXMLNodePtr deepCopy(); BOOL isNull(); BOOL deleteChild(LLXMLNode* child); - void addChild(LLXMLNodePtr new_parent); + void addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child = LLXMLNodePtr(NULL)); void setParent(LLXMLNodePtr new_parent); // reparent if necessary // Serialization @@ -146,8 +149,9 @@ public: LLXMLNodePtr& node, LLXMLNode* defaults); static bool updateNode( - LLXMLNodePtr& node, - LLXMLNodePtr& update_node); + LLXMLNodePtr& node, + LLXMLNodePtr& update_node); + static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node); static void writeHeaderToFile(LLFILE *fOut); void writeToFile(LLFILE *fOut, const std::string& indent = std::string()); void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string()); @@ -176,6 +180,10 @@ public: BOOL hasAttribute(const char* name ); + // these are designed to be more generic versions of the functions + // rather than relying on LL-types + bool getAttribute_bool(const char* name, bool& value ); + BOOL getAttributeBOOL(const char* name, BOOL& value ); BOOL getAttributeU8(const char* name, U8& value ); BOOL getAttributeS8(const char* name, S8& value ); @@ -211,13 +219,16 @@ public: bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); void getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const; void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const; + + // recursively finds all children at any level matching name + void getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const; bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); // The following skip over attributes - LLXMLNodePtr getFirstChild(); - LLXMLNodePtr getNextSibling(); + LLXMLNodePtr getFirstChild() const; + LLXMLNodePtr getNextSibling() const; LLXMLNodePtr getRoot(); @@ -251,7 +262,6 @@ public: void setName(LLStringTableEntry* name); // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt) - // TomY TODO: Make this private static std::string escapeXML(const std::string& xml); // Set the default node corresponding to this default node @@ -291,7 +301,7 @@ public: Encoding mEncoding; // The value encoding LLXMLNode* mParent; // The parent node - LLXMLChildren* mChildren; // The child nodes + LLXMLChildrenPtr mChildren; // The child nodes LLXMLAttribList mAttributes; // The attribute nodes LLXMLNodePtr mPrev; // Double-linked list previous node LLXMLNodePtr mNext; // Double-linked list next node diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 21e491e1b5..0be8b53d41 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -169,6 +169,7 @@ set(viewer_SOURCE_FILES llfloatermute.cpp llfloaternamedesc.cpp llfloaternewim.cpp + llfloaternotificationsconsole.cpp llfloaterobjectiminfo.cpp llfloateropenobject.cpp llfloaterparcel.cpp @@ -570,6 +571,7 @@ set(viewer_HEADER_FILES llfloatermute.h llfloaternamedesc.h llfloaternewim.h + llfloaternotificationsconsole.h llfloaterobjectiminfo.h llfloateropenobject.h llfloaterparcel.h @@ -1091,6 +1093,8 @@ set(viewer_XUI_FILES skins/default/xui/en-us/floater_name_description.xml skins/default/xui/en-us/floater_new_im.xml skins/default/xui/en-us/floater_new_outfit_dialog.xml + skins/default/xui/en-us/floater_notifications_console.xml + skins/default/xui/en-us/floater_notification.xml skins/default/xui/en-us/floater_object_im_info.xml skins/default/xui/en-us/floater_openobject.xml skins/default/xui/en-us/floater_pay_object.xml @@ -1149,6 +1153,7 @@ set(viewer_XUI_FILES skins/default/xui/en-us/menu_slurl.xml skins/default/xui/en-us/menu_viewer.xml skins/default/xui/en-us/mime_types.xml + skins/default/xui/en-us/notifications.xml skins/default/xui/en-us/notify.xml skins/default/xui/en-us/panel_audio_device.xml skins/default/xui/en-us/panel_audio.xml @@ -1177,6 +1182,7 @@ set(viewer_XUI_FILES skins/default/xui/en-us/panel_media_controls.xml skins/default/xui/en-us/panel_media_remote_expanded.xml skins/default/xui/en-us/panel_media_remote.xml + skins/default/xui/en-us/panel_notifications_channel.xml skins/default/xui/en-us/panel_overlaybar.xml skins/default/xui/en-us/panel_place_small.xml skins/default/xui/en-us/panel_place.xml diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 13fc165010..b2f9f0a2ca 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -55,6 +55,17 @@ <real>1.0</real> </array> </map> + <key>AlertedUnsupportedHardware</key> + <map> + <key>Comment</key> + <string>Set if there's unsupported hardware and we've already done a notification.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>AllowIdleAFK</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 7eca956f7d..55b74abd62 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -583,7 +583,7 @@ void LLAgent::onAppFocusGained() void LLAgent::ageChat() { - if (mAvatarObject) + if (mAvatarObject.notNull()) { // get amount of time since I last chatted F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32(); @@ -600,7 +600,7 @@ void LLAgent::unlockView() { if (getFocusOnAvatar()) { - if (mAvatarObject) + if (mAvatarObject.notNull()) { setFocusGlobal( LLVector3d::zero, mAvatarObject->mID ); } @@ -1017,7 +1017,7 @@ void LLAgent::sendReliableMessage() //----------------------------------------------------------------------------- LLVector3 LLAgent::getVelocity() const { - if (mAvatarObject) + if (mAvatarObject.notNull()) { return mAvatarObject->getVelocity(); } @@ -1038,7 +1038,7 @@ void LLAgent::setPositionAgent(const LLVector3 &pos_agent) llerrs << "setPositionAgent is not a number" << llendl; } - if (!mAvatarObject.isNull() && mAvatarObject->getParent()) + if (mAvatarObject.notNull() && mAvatarObject->getParent()) { LLVector3 pos_agent_sitting; LLVector3d pos_agent_d; @@ -1076,7 +1076,7 @@ void LLAgent::slamLookAt(const LLVector3 &look_at) //----------------------------------------------------------------------------- const LLVector3d &LLAgent::getPositionGlobal() const { - if (!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull()) + if (mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull()) { mPositionGlobal = getPosGlobalFromAgent(mAvatarObject->getRenderPosition()); } @@ -1093,7 +1093,7 @@ const LLVector3d &LLAgent::getPositionGlobal() const //----------------------------------------------------------------------------- const LLVector3 &LLAgent::getPositionAgent() { - if(!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull()) + if(mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull()) { mFrameAgent.setOrigin(mAvatarObject->getRenderPosition()); } @@ -2345,11 +2345,11 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) if (user_cancel && !mAutoPilotBehaviorName.empty()) { if (mAutoPilotBehaviorName == "Sit") - LLNotifyBox::showXml("CancelledSit"); + LLNotifications::instance().add("CancelledSit"); else if (mAutoPilotBehaviorName == "Attach") - LLNotifyBox::showXml("CancelledAttach"); + LLNotifications::instance().add("CancelledAttach"); else - LLNotifyBox::showXml("Cancelled"); + LLNotifications::instance().add("Cancelled"); } } } @@ -2374,7 +2374,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) mAutoPilotTargetGlobal = object->getPositionGlobal(); } - if (!mAvatarObject) + if (mAvatarObject.isNull()) { return; } @@ -2455,7 +2455,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) // If we're flying, handle autopilot points above or below you. if (getFlying() && xy_distance < AUTOPILOT_HEIGHT_ADJUST_DISTANCE) { - if (mAvatarObject) + if (mAvatarObject.notNull()) { F64 current_height = mAvatarObject->getPositionGlobal().mdV[VZ]; F32 delta_z = (F32)(mAutoPilotTargetGlobal.mdV[VZ] - current_height); @@ -2540,7 +2540,7 @@ void LLAgent::propagate(const F32 dt) pitch(PITCH_RATE * (F32) mPitchKey * dt); // handle auto-land behavior - if (mAvatarObject) + if (mAvatarObject.notNull()) { BOOL in_air = mAvatarObject->mInAir; LLVector3 land_vel = getVelocity(); @@ -2591,7 +2591,7 @@ void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y) static LLVector3 last_at_axis; - if ( mAvatarObject.isNull() ) + if (mAvatarObject.isNull()) { return; } @@ -2864,7 +2864,7 @@ void LLAgent::endAnimationUpdateUI() } // Disable mouselook-specific animations - if (mAvatarObject) + if (mAvatarObject.notNull()) { if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) ) { @@ -2910,7 +2910,7 @@ void LLAgent::endAnimationUpdateUI() gMorphView->setVisible( FALSE ); } - if (mAvatarObject) + if (mAvatarObject.notNull()) { if(mCustomAnim) { @@ -2953,7 +2953,7 @@ void LLAgent::endAnimationUpdateUI() gIMMgr->setFloaterOpen( FALSE ); gConsole->setVisible( TRUE ); - if (mAvatarObject) + if (mAvatarObject.notNull()) { // Trigger mouselook-specific animations if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_HOLD_ANIMS, NUM_AGENT_GUN_HOLD_ANIMS) ) @@ -3014,7 +3014,7 @@ void LLAgent::endAnimationUpdateUI() } // freeze avatar - if (mAvatarObject) + if (mAvatarObject.notNull()) { mPauseRequest = mAvatarObject->requestPause(); } @@ -3048,7 +3048,7 @@ void LLAgent::updateCamera() validateFocusObject(); - if (!mAvatarObject.isNull() && + if (mAvatarObject.notNull() && mAvatarObject->mIsSitting && camera_mode == CAMERA_MODE_MOUSELOOK) { @@ -3162,7 +3162,7 @@ void LLAgent::updateCamera() //Ventrella if ( mCameraMode == CAMERA_MODE_FOLLOW ) { - if ( !mAvatarObject.isNull() ) + if ( mAvatarObject.notNull() ) { //-------------------------------------------------------------------------------- // this is where the avatar's position and rotation are given to followCam, and @@ -3472,7 +3472,7 @@ LLVector3d LLAgent::calcFocusPositionTargetGlobal() { LLVector3d at_axis(1.0, 0.0, 0.0); LLQuaternion agent_rot = mFrameAgent.getQuaternion(); - if (!mAvatarObject.isNull() && mAvatarObject->getParent()) + if (mAvatarObject.notNull() && mAvatarObject->getParent()) { LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot(); if (!root_object->flagCameraDecoupled()) @@ -3770,7 +3770,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) camera_offset.setVec( local_camera_offset ); camera_position_global = frame_center_global + head_offset + camera_offset; - if (!mAvatarObject.isNull()) + if (mAvatarObject.notNull()) { LLVector3d camera_lag_d; F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE); @@ -4001,7 +4001,7 @@ void LLAgent::changeCameraToMouselook(BOOL animate) gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE); gSavedSettings.setBOOL("BuildBtnState", FALSE); - if (mAvatarObject) + if (mAvatarObject.notNull()) { mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE ); mAvatarObject->stopMotion( ANIM_AGENT_BREATHE_ROT ); @@ -4089,7 +4089,7 @@ void LLAgent::changeCameraToFollow(BOOL animate) LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); } - if (mAvatarObject) + if (mAvatarObject.notNull()) { mAvatarObject->mPelvisp->setPosition(LLVector3::zero); mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE ); @@ -4137,7 +4137,7 @@ void LLAgent::changeCameraToThirdPerson(BOOL animate) mCameraZoomFraction = INITIAL_ZOOM_FRACTION; - if (mAvatarObject) + if (mAvatarObject.notNull()) { if (!mAvatarObject->mIsSitting) { @@ -4183,7 +4183,7 @@ void LLAgent::changeCameraToThirdPerson(BOOL animate) } // Remove any pitch from the avatar - if (!mAvatarObject.isNull() && mAvatarObject->getParent()) + if (mAvatarObject.notNull() && mAvatarObject->getParent()) { LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation(); at_axis = LLViewerCamera::getInstance()->getAtAxis(); @@ -4262,7 +4262,7 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_ani LLVOAvatar::onCustomizeStart(); } - if (!mAvatarObject.isNull()) + if (mAvatarObject.notNull()) { if(avatar_animate) { @@ -4362,7 +4362,7 @@ void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id) { if (focus.isExactlyZero()) { - if (!mAvatarObject.isNull()) + if (mAvatarObject.notNull()) { mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition()); } @@ -4407,7 +4407,7 @@ void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id) { if (focus.isExactlyZero()) { - if (!mAvatarObject.isNull()) + if (mAvatarObject.notNull()) { mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition()); } @@ -4544,7 +4544,7 @@ void LLAgent::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate) if (mCameraMode == CAMERA_MODE_THIRD_PERSON) { LLVector3 at_axis; - if (!mAvatarObject.isNull() && mAvatarObject->getParent()) + if (mAvatarObject.notNull() && mAvatarObject->getParent()) { LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation(); at_axis = LLViewerCamera::getInstance()->getAtAxis(); @@ -4611,7 +4611,7 @@ void LLAgent::lookAtLastChat() if (chatter->isAvatar()) { LLVOAvatar *chatter_av = (LLVOAvatar*)chatter; - if (!mAvatarObject.isNull() && chatter_av->mHeadp) + if (mAvatarObject.notNull() && chatter_av->mHeadp) { delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition(); } @@ -4692,7 +4692,7 @@ void LLAgent::setStartPosition( U32 location_id ) LLVector3 agent_pos = getPositionAgent(); LLVector3 agent_look_at = mFrameAgent.getAtAxis(); - if (mAvatarObject) + if (mAvatarObject.notNull()) { // the z height is at the agent's feet agent_pos.mV[VZ] -= 0.5f * mAvatarObject->mBodySize.mV[VZ]; @@ -4853,7 +4853,7 @@ void LLAgent::setTeen(bool teen) void LLAgent::buildFullname(std::string& name) const { - if (mAvatarObject) + if (mAvatarObject.notNull()) { name = mAvatarObject->getFullname(); } @@ -4871,7 +4871,7 @@ void LLAgent::buildFullnameAndTitle(std::string& name) const name.erase(0, name.length()); } - if (mAvatarObject) + if (mAvatarObject.notNull()) { name += mAvatarObject->getFullname(); } @@ -5226,7 +5226,7 @@ void LLAgent::getName(std::string& name) { name.clear(); - if (mAvatarObject) + if (mAvatarObject.notNull()) { LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName"); LLNameValue *last_nv = mAvatarObject->getNVPair("LastName"); @@ -6726,7 +6726,7 @@ void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdat void LLAgent::recoverMissingWearable( EWearableType type ) { // Try to recover by replacing missing wearable with a new one. - LLNotifyBox::showXml("ReplacedMissingWearable"); + LLNotifications::instance().add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* new_wearable = gWearableList.createNewWearable(type); @@ -7157,8 +7157,10 @@ void LLAgent::removeWearable( EWearableType type ) { if( old_wearable->isDirty() ) { + LLSD payload; + payload["wearable_type"] = (S32)type; // Bring up view-modal dialog: Save changes? Yes, No, Cancel - gViewerWindow->alertXml("WearableSave", LLAgent::onRemoveWearableDialog, (void*)type ); + LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgent::onRemoveWearableDialog); return; } else @@ -7169,9 +7171,10 @@ void LLAgent::removeWearable( EWearableType type ) } // static -void LLAgent::onRemoveWearableDialog( S32 option, void* userdata ) +bool LLAgent::onRemoveWearableDialog(const LLSD& notification, const LLSD& response ) { - EWearableType type = (EWearableType)(intptr_t)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); + EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger(); switch( option ) { case 0: // "Save" @@ -7190,6 +7193,7 @@ void LLAgent::onRemoveWearableDialog( S32 option, void* userdata ) llassert(0); break; } + return false; } // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. @@ -7388,8 +7392,9 @@ void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable ) if( old_wearable->isDirty() ) { // Bring up modal dialog: Save changes? Yes, No, Cancel - gViewerWindow->alertXml( "WearableSave", LLAgent::onSetWearableDialog, - new LLSetWearableData( new_item->getUUID(), new_wearable )); + LLSD payload; + payload["item_id"] = new_item->getUUID(); + LLNotifications::instance().add( "WearableSave", LLSD(), payload, boost::bind(LLAgent::onSetWearableDialog, _1, _2, new_wearable)); return; } } @@ -7398,25 +7403,25 @@ void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable ) } // static -void LLAgent::onSetWearableDialog( S32 option, void* userdata ) +bool LLAgent::onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable ) { - LLSetWearableData* data = (LLSetWearableData*)userdata; - LLInventoryItem* new_item = gInventory.getItem( data->mNewItemID ); + S32 option = LLNotification::getSelectedOption(notification, response); + LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); if( !new_item ) { - delete data; - return; + delete wearable; + return false; } switch( option ) { case 0: // "Save" - gAgent.saveWearable( data->mNewWearable->getType() ); - gAgent.setWearableFinal( new_item, data->mNewWearable ); + gAgent.saveWearable( wearable->getType() ); + gAgent.setWearableFinal( new_item, wearable ); break; case 1: // "Don't Save" - gAgent.setWearableFinal( new_item, data->mNewWearable ); + gAgent.setWearableFinal( new_item, wearable ); break; case 2: // "Cancel" @@ -7427,7 +7432,8 @@ void LLAgent::onSetWearableDialog( S32 option, void* userdata ) break; } - delete data; + delete wearable; + return false; } // Called from setWearable() and onSetWearableDialog() to actually set the wearable. diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index f561f55e46..f1e0bc9308 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -591,10 +591,8 @@ public: //-------------------------------------------------------------------- // Wearables //-------------------------------------------------------------------- - BOOL getWearablesLoaded() const { return mWearablesLoaded; } - void setWearable( LLInventoryItem* new_item, LLWearable* wearable ); - static void onSetWearableDialog( S32 option, void* userdata ); + static bool onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable ); void setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ); void setWearableOutfit( const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove ); void queryWearableCache(); @@ -624,7 +622,7 @@ public: void makeNewOutfitDone(S32 index); void removeWearable( EWearableType type ); - static void onRemoveWearableDialog( S32 option, void* userdata ); + static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response ); void removeWearableFinal( EWearableType type ); void sendAgentWearablesUpdate(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b8b08855a8..54fdcc3894 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -652,6 +652,7 @@ bool LLAppViewer::init() // Widget construction depends on LLUI being initialized LLUI::initClass(&gSavedSettings, + &gSavedSettings, &gColors, LLUIImageList::getInstance(), ui_audio_callback, @@ -663,7 +664,7 @@ bool LLAppViewer::init() &LLURLDispatcher::dispatchFromTextEditor); LLUICtrlFactory::getInstance()->setupPaths(); // update paths with correct language set - + ///////////////////////////////////////////////// // // Load settings files @@ -736,7 +737,10 @@ bool LLAppViewer::init() // initWindow(); -#if LL_LCD_COMPILE + // call all self-registered classes + LLInitClassList::instance().fireCallbacks(); + + #if LL_LCD_COMPILE // start up an LCD window on a logitech keyboard, if there is one HINSTANCE hInstance = GetModuleHandle(NULL); gLcdScreen = new LLLCD(hInstance); @@ -762,64 +766,67 @@ bool LLAppViewer::init() // If we don't have the right GL requirements, exit. if (!gGLManager.mHasRequirements && !gNoRender) { - // can't use an alert here since we're existing and + // can't use an alert here since we're exiting and // all hell breaks lose. OSMessageBox( - LLAlertDialog::getTemplateMessage("UnsupportedGLRequirements"), + LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"), LLStringUtil::null, OSMB_OK); return 0; } - - bool unsupported = false; - LLStringUtil::format_map_t args; - std::string minSpecs; - - // get cpu data from xml - std::stringstream minCPUString(LLAlertDialog::getTemplateMessage("UnsupportedCPUAmount")); - S32 minCPU = 0; - minCPUString >> minCPU; - - // get RAM data from XML - std::stringstream minRAMString(LLAlertDialog::getTemplateMessage("UnsupportedRAMAmount")); - U64 minRAM = 0; - minRAMString >> minRAM; - minRAM = minRAM * 1024 * 1024; - - if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) - { - minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedGPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysCPU.getMhz() < minCPU) - { - minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedCPU"); - minSpecs += "\n"; - unsupported = true; - } - if(gSysMemory.getPhysicalMemoryClamped() < minRAM) - { - minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedRAM"); - minSpecs += "\n"; - unsupported = true; - } - - if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) + // alert the user if they are using unsupported hardware + if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) { - gViewerWindow->alertXml("UnknownGPU"); - } + bool unsupported = false; + LLSD args; + std::string minSpecs; - if(unsupported) - { - if(!gSavedSettings.controlExists("WarnUnsupportedHardware") - || gSavedSettings.getBOOL("WarnUnsupportedHardware")) + // get cpu data from xml + std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount")); + S32 minCPU = 0; + minCPUString >> minCPU; + + // get RAM data from XML + std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount")); + U64 minRAM = 0; + minRAMString >> minRAM; + minRAM = minRAM * 1024 * 1024; + + if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysCPU.getMhz() < minCPU) + { + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU"); + minSpecs += "\n"; + unsupported = true; + } + if(gSysMemory.getPhysicalMemoryClamped() < minRAM) { - args["MINSPECS"] = minSpecs; - gViewerWindow->alertXml("UnsupportedHardware", args ); + minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM"); + minSpecs += "\n"; + unsupported = true; } + if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN) + { + LLNotifications::instance().add("UnknownGPU"); + } + + if(unsupported) + { + if(!gSavedSettings.controlExists("WarnUnsupportedHardware") + || gSavedSettings.getBOOL("WarnUnsupportedHardware")) + { + args["MINSPECS"] = minSpecs; + LLNotifications::instance().add("UnsupportedHardware", args ); + } + + } } // save the graphics card @@ -1153,8 +1160,6 @@ bool LLAppViewer::cleanup() // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. - LLNotifyBox::cleanup(); - LLWorldMap::getInstance()->reset(); // release any images llinfos << "Global stuff deleted" << llendflush; @@ -1705,25 +1710,6 @@ bool LLAppViewer::initConfiguration() LLFirstUse::addConfigVariable("FirstVoice"); LLFirstUse::addConfigVariable("FirstMedia"); - ////// - // *FIX:Mani - Find a way to remove the gUICtrlFactory and - // LLAlertDialog::parseAlerts dependecies on the being loaded - // *before* the user settings. Having to do this init here - // seems odd. - - // This is where gUICtrlFactory used to be instantiated with a new LLUICtrlFactory - // which needed to happen before calling parseAlerts below. - // TODO: That method is still dependant upon the base LLUICtrlFactory constructor being called - // which registers some callbacks so I'm leaving in a call to getInstance here to cause that to - // still happen. This needs to be cleaned up later when the base and derived classes - // are planned to be combined. -MG - LLUICtrlFactory::getInstance(); - - - // Pre-load alerts.xml to define the warnings settings (always loads from skins/xui/en-us/) - // Do this *before* loading the settings file - LLAlertDialog::parseAlerts("alerts.xml", &gSavedSettings, TRUE); - // - read command line settings. LLControlGroupCLP clp; std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, @@ -2151,8 +2137,6 @@ bool LLAppViewer::initWindow() LLUI::sWindow = gViewerWindow->getWindow(); - LLAlertDialog::parseAlerts("alerts.xml"); - LLNotifyBox::parseNotify("notify.xml"); LLTrans::parseStrings("strings.xml"); // Show watch cursor @@ -2614,32 +2598,34 @@ void LLAppViewer::requestQuit() mQuitRequested = true; } -static void finish_quit(S32 option, void *userdata) +static bool finish_quit(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) { LLAppViewer::instance()->requestQuit(); } + return false; } +static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit); void LLAppViewer::userQuit() { - gViewerWindow->alertXml("ConfirmQuit", finish_quit, NULL); + LLNotifications::instance().add("ConfirmQuit"); } -static void finish_early_exit(S32 option, void* userdata) +static bool finish_early_exit(const LLSD& notification, const LLSD& response) { LLAppViewer::instance()->forceQuit(); + return false; } -void LLAppViewer::earlyExit(const std::string& msg) +void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) { - llwarns << "app_early_exit: " << msg << llendl; + llwarns << "app_early_exit: " << name << llendl; gDoDisconnect = TRUE; -// LLStringUtil::format_map_t args; -// args["[MESSAGE]"] = mesg; -// gViewerWindow->alertXml("AppEarlyExit", args, finish_early_exit); - LLAlertDialog::showCritical(msg, finish_early_exit, NULL); + LLNotifications::instance().add(name, substitutions, LLSD(), finish_early_exit); } void LLAppViewer::forceExit(S32 arg) @@ -2953,18 +2939,22 @@ const std::string& LLAppViewer::getWindowTitle() const } // Callback from a dialog indicating user was logged out. -void finish_disconnect(S32 option, void* userdata) +bool finish_disconnect(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); + if (1 == option) { LLAppViewer::instance()->forceQuit(); } + return false; } // Callback from an early disconnect dialog, force an exit -void finish_forced_disconnect(S32 /* option */, void* /* userdata */) +bool finish_forced_disconnect(const LLSD& notification, const LLSD& response) { LLAppViewer::instance()->forceQuit(); + return false; } @@ -2984,19 +2974,19 @@ void LLAppViewer::forceDisconnect(const std::string& mesg) big_reason = mesg; } - LLStringUtil::format_map_t args; + LLSD args; gDoDisconnect = TRUE; if (LLStartUp::getStartupState() < STATE_STARTED) { // Tell users what happened - args["[ERROR_MESSAGE]"] = big_reason; - gViewerWindow->alertXml("ErrorMessage", args, finish_forced_disconnect); + args["ERROR_MESSAGE"] = big_reason; + LLNotifications::instance().add("ErrorMessage", args, LLSD(), &finish_forced_disconnect); } else { - args["[MESSAGE]"] = big_reason; - gViewerWindow->alertXml("YouHaveBeenLoggedOut", args, finish_disconnect ); + args["MESSAGE"] = big_reason; + LLNotifications::instance().add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); } } @@ -3763,6 +3753,9 @@ void LLAppViewer::disconnectViewer() // Now we just ask the LLWorld singleton to cleanly shut down. LLWorld::getInstance()->destroyClass(); + // call all self-registered classes + LLDestroyClassList::instance().fireCallbacks(); + cleanup_xfer_manager(); gDisconnected = TRUE; } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 41081237c7..f8940322c5 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -63,7 +63,8 @@ public: void forceQuit(); // Puts the viewer into 'shutting down without error' mode. void requestQuit(); // Request a quit. A kinder, gentler quit. void userQuit(); // The users asks to quit. Confirm, then requestQuit() - void earlyExit(const std::string& msg); // Display an error dialog and forcibly quit. + void earlyExit(const std::string& name, + const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit. void forceExit(S32 arg); // exit() immediately (after some cleanup). void abortQuit(); // Called to abort a quit request. diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index d25f827a72..a90532b451 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -102,21 +102,21 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) { llinfos << "LLAssetUploadResponder::error " << statusNum << " reason: " << reason << llendl; - LLStringUtil::format_map_t args; + LLSD args; switch(statusNum) { case 400: - args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["[REASON]"] = "Error in upload request. Please visit " + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "Error in upload request. Please visit " "http://secondlife.com/support for help fixing this problem."; - gViewerWindow->alertXml("CannotUploadReason", args); + LLNotifications::instance().add("CannotUploadReason", args); break; case 500: default: - args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["[REASON]"] = "The server is experiencing unexpected " + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = "The server is experiencing unexpected " "difficulties."; - gViewerWindow->alertXml("CannotUploadReason", args); + LLNotifications::instance().add("CannotUploadReason", args); break; } LLUploadDialog::modalUploadFinished(); @@ -171,10 +171,10 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) } else { - LLStringUtil::format_map_t args; - args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["[REASON]"] = content["message"].asString(); - gViewerWindow->alertXml("CannotUploadReason", args); + LLSD args; + args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); + args["REASON"] = content["message"].asString(); + LLNotifications::instance().add("CannotUploadReason", args); } } @@ -220,9 +220,9 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) gMessageSystem->addUUIDFast(_PREHASH_TransactionID, LLUUID::null ); gAgent.sendReliableMessage(); - LLStringUtil::format_map_t args; - args["[AMOUNT]"] = llformat("%d",LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); - LLNotifyBox::showXml("UploadPayment", args); + LLSD args; + args["AMOUNT"] = llformat("%d",LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); + LLNotifications::instance().add("UploadPayment", args); } // Actually add the upload to viewer inventory diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 1fdefbac49..2395d1daab 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -592,19 +592,19 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^ new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS) { std::string first, last; - LLStringUtil::format_map_t args; + LLSD args; if(gCacheName->getName(agent_id, first, last)) { - args["[FIRST_NAME]"] = first; - args["[LAST_NAME]"] = last; + args["FIRST_NAME"] = first; + args["LAST_NAME"] = last; } if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights) { - gViewerWindow->alertXml("GrantedModifyRights",args); + LLNotifications::instance().add("GrantedModifyRights",args); } else { - gViewerWindow->alertXml("RevokedModifyRights",args); + LLNotifications::instance().add("RevokedModifyRights",args); } } (mBuddyInfo[agent_id])->setRightsFrom(new_rights); @@ -638,7 +638,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) tracking_id = mTrackingData->mAvatarID; } BOOL notify = FALSE; - LLStringUtil::format_map_t args; + LLSD args; for(S32 i = 0; i < count; ++i) { msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_AgentID, agent_id, i); @@ -652,8 +652,8 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) if(gCacheName->getName(agent_id, first, last)) { notify = TRUE; - args["[FIRST]"] = first; - args["[LAST]"] = last; + args["FIRST"] = first; + args["LAST"] = last; } } } @@ -674,14 +674,14 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) if(notify) { // Popup a notify box with online status of this agent - LLNotifyBox::showXml(online ? "FriendOnline" : "FriendOffline", args); + LLNotificationPtr notification = LLNotifications::instance().add(online ? "FriendOnline" : "FriendOffline", args); // If there's an open IM session with this agent, send a notification there too. LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id); LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id); if (floater) { - LLUIString notifyMsg = LLNotifyBox::getTemplateMessage((online ? "FriendOnline" : "FriendOffline"),args); + std::string notifyMsg = notification->getMessage(); if (!notifyMsg.empty()) floater->addHistoryLine(notifyMsg,gSavedSettings.getColor4("SystemChatColor")); } diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index e9dbc69bce..299a2cc33a 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -524,9 +524,9 @@ void LLFloaterCompileQueue::onSaveTextComplete(const LLUUID& asset_id, void* use if (status) { llwarns << "Unable to save text for script." << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("CompileQueueSaveText", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("CompileQueueSaveText", args); } } @@ -545,9 +545,9 @@ void LLFloaterCompileQueue::onSaveBytecodeComplete(const LLUUID& asset_id, void* else { llwarns << "Unable to save bytecode for script." << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("CompileQueueSaveBytecode", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("CompileQueueSaveBytecode", args); } delete data; data = NULL; diff --git a/indra/newview/llconfirmationmanager.cpp b/indra/newview/llconfirmationmanager.cpp index 167afb8062..6c465ccf92 100644 --- a/indra/newview/llconfirmationmanager.cpp +++ b/indra/newview/llconfirmationmanager.cpp @@ -45,24 +45,22 @@ LLConfirmationManager::ListenerBase::~ListenerBase() } -static void onConfirmAlert(S32 option, void* data) +static bool onConfirmAlert(const LLSD& notification, const LLSD& response, LLConfirmationManager::ListenerBase* listener) { - LLConfirmationManager::ListenerBase* listener - = (LLConfirmationManager::ListenerBase*)data; - + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { listener->confirmed(""); } delete listener; + return false; } -static void onConfirmAlertPassword( - S32 option, const std::string& text, void* data) +static bool onConfirmAlertPassword(const LLSD& notification, const LLSD& response, LLConfirmationManager::ListenerBase* listener) { - LLConfirmationManager::ListenerBase* listener - = (LLConfirmationManager::ListenerBase*)data; + std::string text = response["message"].asString(); + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { @@ -70,6 +68,7 @@ static void onConfirmAlertPassword( } delete listener; + return false; } @@ -77,22 +76,17 @@ void LLConfirmationManager::confirm(Type type, const std::string& action, ListenerBase* listener) { - LLStringUtil::format_map_t args; - args["[ACTION]"] = action; + LLSD args; + args["ACTION"] = action; switch (type) { case TYPE_CLICK: - gViewerWindow->alertXml("ConfirmPurchase", args, - onConfirmAlert, listener); + LLNotifications::instance().add("ConfirmPurchase", args, LLSD(), boost::bind(onConfirmAlert, _1, _2, listener)); break; case TYPE_PASSWORD: - gViewerWindow->alertXmlEditText("ConfirmPurchasePassword", args, - NULL, NULL, - onConfirmAlertPassword, listener, - LLStringUtil::format_map_t(), - TRUE); + LLNotifications::instance().add("ConfirmPurchasePassword", args, LLSD(), boost::bind(onConfirmAlertPassword, _1, _2, listener)); break; case TYPE_NONE: default: diff --git a/indra/newview/lldelayedgestureerror.cpp b/indra/newview/lldelayedgestureerror.cpp index 832b1b9130..9799bc1240 100644 --- a/indra/newview/lldelayedgestureerror.cpp +++ b/indra/newview/lldelayedgestureerror.cpp @@ -98,18 +98,18 @@ void LLDelayedGestureError::onIdle(void *userdata) //static bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) { - LLStringUtil::format_map_t args; + LLSD args; LLInventoryItem *item = gInventory.getItem( ent.mItemID ); if ( item ) { - args["[NAME]"] = item->getName(); + args["NAME"] = item->getName(); } else { if ( uuid_ok || ent.mTimer.getElapsedTimeF32() > MAX_NAME_WAIT_TIME ) { - args["[NAME]"] = std::string( ent.mItemID.asString() ); + args["NAME"] = ent.mItemID.asString(); } else { @@ -118,7 +118,7 @@ bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) } - LLNotifyBox::showXml(ent.mNotifyName, args); + LLNotifications::instance().add(ent.mNotifyName, args); return true; } diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index 343a572a6a..59f5cd342b 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -77,11 +77,11 @@ void LLEventNotifier::update() if (np->getEventDate() < (alert_time)) { - LLStringUtil::format_map_t args; - args["[NAME]"] = np->getEventName(); - args["[DATE]"] = np->getEventDateStr(); - LLNotifyBox::showXml("EventNotification", args, - notifyCallback, np); + LLSD args; + args["NAME"] = np->getEventName(); + args["DATE"] = np->getEventDateStr(); + LLNotifications::instance().add("EventNotification", args, LLSD(), + boost::bind(&LLEventNotification::handleResponse, np, _1, _2)); mEventNotifications.erase(iter++); } else @@ -173,47 +173,38 @@ void LLEventNotifier::remove(const U32 event_id) mEventNotifications.erase(iter); } -//static -void LLEventNotifier::notifyCallback(S32 option, void *user_data) +LLEventNotification::LLEventNotification() : + mEventID(0), + mEventName("") { - LLEventNotification *np = (LLEventNotification *)user_data; - if (!np) - { - llwarns << "Event notification callback without data!" << llendl; - return; - } +} + + +LLEventNotification::~LLEventNotification() +{ +} + +bool LLEventNotification::handleResponse(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); switch (option) { case 0: - gAgent.teleportViaLocation(np->getEventPosGlobal()); - gFloaterWorldMap->trackLocation(np->getEventPosGlobal()); + gAgent.teleportViaLocation(getEventPosGlobal()); + gFloaterWorldMap->trackLocation(getEventPosGlobal()); break; case 1: gDisplayEventHack = TRUE; - LLFloaterDirectory::showEvents(np->getEventID()); + LLFloaterDirectory::showEvents(getEventID()); break; case 2: break; } // We could clean up the notification on the server now if we really wanted to. + return false; } - - -LLEventNotification::LLEventNotification() : - mEventID(0), - mEventName(""), - mEventDate(0) -{ -} - - -LLEventNotification::~LLEventNotification() -{ -} - - BOOL LLEventNotification::load(const LLUserAuth::response_t &response) { diff --git a/indra/newview/lleventnotifier.h b/indra/newview/lleventnotifier.h index bbd1facf31..ac906521d2 100644 --- a/indra/newview/lleventnotifier.h +++ b/indra/newview/lleventnotifier.h @@ -56,7 +56,6 @@ public: typedef std::map<U32, LLEventNotification *> en_map; - static void notifyCallback(S32 option, void *user_data); protected: en_map mEventNotifications; LLFrameTimer mNotificationTimer; @@ -78,6 +77,7 @@ public: time_t getEventDate() const { return mEventDate; } const std::string &getEventDateStr() const { return mEventDateStr; } LLVector3d getEventPosGlobal() const { return mEventPosGlobal; } + bool handleResponse(const LLSD& notification, const LLSD& payload); protected: U32 mEventID; // EventID for this event std::string mEventName; diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 475473abe7..fce4d41207 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -85,9 +85,9 @@ void LLFirstUse::useBalanceIncrease(S32 delta) { gSavedSettings.setWarning("FirstBalanceIncrease", FALSE); - LLStringUtil::format_map_t args; - args["[AMOUNT]"] = llformat("%d",delta); - LLNotifyBox::showXml("FirstBalanceIncrease", args); + LLSD args; + args["AMOUNT"] = llformat("%d",delta); + LLNotifications::instance().add("FirstBalanceIncrease", args); } } @@ -99,9 +99,9 @@ void LLFirstUse::useBalanceDecrease(S32 delta) { gSavedSettings.setWarning("FirstBalanceDecrease", FALSE); - LLStringUtil::format_map_t args; - args["[AMOUNT]"] = llformat("%d",-delta); - LLNotifyBox::showXml("FirstBalanceDecrease", args); + LLSD args; + args["AMOUNT"] = llformat("%d",-delta); + LLNotifications::instance().add("FirstBalanceDecrease", args); } } @@ -114,8 +114,8 @@ void LLFirstUse::useSit() //if (gSavedSettings.getWarning("FirstSit")) //{ // gSavedSettings.setWarning("FirstSit", FALSE); - - // LLNotifyBox::showXml("FirstSit"); + // + // LLNotifications::instance().add("FirstSit"); //} } @@ -126,7 +126,7 @@ void LLFirstUse::useMap() { gSavedSettings.setWarning("FirstMap", FALSE); - LLNotifyBox::showXml("FirstMap"); + LLNotifications::instance().add("FirstMap"); } } @@ -143,7 +143,7 @@ void LLFirstUse::useBuild() { gSavedSettings.setWarning("FirstBuild", FALSE); - LLNotifyBox::showXml("FirstBuild"); + LLNotifications::instance().add("FirstBuild"); } } @@ -154,7 +154,7 @@ void LLFirstUse::useLeftClickNoHit() { gSavedSettings.setWarning("FirstLeftClickNoHit", FALSE); - LLNotifyBox::showXml("FirstLeftClickNoHit"); + LLNotifications::instance().add("FirstLeftClickNoHit"); } } @@ -168,7 +168,7 @@ void LLFirstUse::useTeleport() { gSavedSettings.setWarning("FirstTeleport", FALSE); - LLNotifyBox::showXml("FirstTeleport"); + LLNotifications::instance().add("FirstTeleport"); } } } @@ -184,7 +184,7 @@ void LLFirstUse::useOverrideKeys() { gSavedSettings.setWarning("FirstOverrideKeys", FALSE); - LLNotifyBox::showXml("FirstOverrideKeys"); + LLNotifications::instance().add("FirstOverrideKeys"); } } } @@ -202,7 +202,7 @@ void LLFirstUse::useAppearance() { gSavedSettings.setWarning("FirstAppearance", FALSE); - LLNotifyBox::showXml("FirstAppearance"); + LLNotifications::instance().add("FirstAppearance"); } } @@ -213,7 +213,7 @@ void LLFirstUse::useInventory() { gSavedSettings.setWarning("FirstInventory", FALSE); - LLNotifyBox::showXml("FirstInventory"); + LLNotifications::instance().add("FirstInventory"); } } @@ -225,10 +225,10 @@ void LLFirstUse::useSandbox() { gSavedSettings.setWarning("FirstSandbox", FALSE); - LLStringUtil::format_map_t args; - args["[HOURS]"] = llformat("%d",SANDBOX_CLEAN_FREQ); - args["[TIME]"] = llformat("%d",SANDBOX_FIRST_CLEAN_HOUR); - LLNotifyBox::showXml("FirstSandbox", args); + LLSD args; + args["HOURS"] = llformat("%d",SANDBOX_CLEAN_FREQ); + args["TIME"] = llformat("%d",SANDBOX_FIRST_CLEAN_HOUR); + LLNotifications::instance().add("FirstSandbox", args); } } @@ -239,7 +239,7 @@ void LLFirstUse::useFlexible() { gSavedSettings.setWarning("FirstFlexible", FALSE); - LLNotifyBox::showXml("FirstFlexible"); + LLNotifications::instance().add("FirstFlexible"); } } @@ -250,7 +250,7 @@ void LLFirstUse::useDebugMenus() { gSavedSettings.setWarning("FirstDebugMenus", FALSE); - LLNotifyBox::showXml("FirstDebugMenus"); + LLNotifications::instance().add("FirstDebugMenus"); } } @@ -261,7 +261,7 @@ void LLFirstUse::useSculptedPrim() { gSavedSettings.setWarning("FirstSculptedPrim", FALSE); - LLNotifyBox::showXml("FirstSculptedPrim"); + LLNotifications::instance().add("FirstSculptedPrim"); } } @@ -273,6 +273,6 @@ void LLFirstUse::useMedia() { gSavedSettings.setWarning("FirstMedia", FALSE); - LLNotifyBox::showXml("FirstMedia"); + LLNotifications::instance().add("FirstMedia"); } } diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index c7e35bcfb5..a84026e132 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -1001,7 +1001,7 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata) else { llwarns << "Failure writing animation data." << llendl; - gViewerWindow->alertXml("WriteAnimationFail"); + LLNotifications::instance().add("WriteAnimationFail"); } } diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index a90d11f6ea..100c6ee20d 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -238,7 +238,7 @@ void LLFloaterAuction::onClickOK(void* data) FALSE); self->getWindow()->incBusyCount(); - LLNotifyBox::showXml("UploadingAuctionSnapshot"); + LLNotifications::instance().add("UploadingAuctionSnapshot"); } LLMessageSystem* msg = gMessageSystem; @@ -277,13 +277,13 @@ void auction_tga_upload_done(const LLUUID& asset_id, void* user_data, S32 status if (0 == status) { - LLNotifyBox::showXml("UploadWebSnapshotDone"); + LLNotifications::instance().add("UploadWebSnapshotDone"); } else { - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("UploadAuctionSnapshotFail", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("UploadAuctionSnapshotFail", args); } } @@ -298,12 +298,12 @@ void auction_j2c_upload_done(const LLUUID& asset_id, void* user_data, S32 status if (0 == status) { - LLNotifyBox::showXml("UploadSnapshotDone"); + LLNotifications::instance().add("UploadSnapshotDone"); } else { - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("UploadAuctionSnapshotFail", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("UploadAuctionSnapshotFail", args); } } diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 9edb0afb5c..5bdb4a2374 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -86,7 +86,7 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) if (selection->getRootObjectCount() != 1) { - gViewerWindow->alertXml("BuyOneObjectOnly"); + LLNotifications::instance().add("BuyOneObjectOnly"); return; } @@ -136,7 +136,7 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); if (!owners_identical) { - gViewerWindow->alertXml("BuyObjectOneOwner"); + LLNotifications::instance().add("BuyObjectOneOwner"); return; } diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index d74707f6b1..1dd12413cc 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -83,7 +83,7 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) if (selection->getRootObjectCount() != 1) { - gViewerWindow->alertXml("BuyContentsOneOnly"); + LLNotifications::instance().add("BuyContentsOneOnly"); return; } @@ -113,7 +113,7 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); if (!owners_identical) { - gViewerWindow->alertXml("BuyContentsOneOwner"); + LLNotifications::instance().add("BuyContentsOneOwner"); return; } diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 7aa6af2fea..65cea37a0f 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -213,7 +213,7 @@ void LLFloaterBuyLand::buyLand( { if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED)) { - gViewerWindow->alertXml("OnlyOfficerCanBuyLand"); + LLNotifications::instance().add("OnlyOfficerCanBuyLand"); return; } @@ -976,7 +976,7 @@ BOOL LLFloaterBuyLandUI::canClose() if (!can_close) { // explain to user why they can't do this, see DEV-9605 - gViewerWindow->alertXml("CannotCloseFloaterBuyLand"); + LLNotifications::instance().add("CannotCloseFloaterBuyLand"); } return can_close; } diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp index af42a92ed8..de308b5425 100644 --- a/indra/newview/llfloaterdaycycle.cpp +++ b/indra/newview/llfloaterdaycycle.cpp @@ -98,17 +98,9 @@ LLFloaterDayCycle::~LLFloaterDayCycle() void LLFloaterDayCycle::onClickHelp(void* data) { LLFloaterDayCycle* self = LLFloaterDayCycle::instance(); - const std::string* xml_alert = (std::string*)data; - LLAlertDialog* dialogp = gViewerWindow->alertXml(*xml_alert); - if (dialogp) - { - LLFloater* root_floater = gFloaterView->getParentFloater(self); - if (root_floater) - { - root_floater->addDependentFloater(dialogp); - } - } + std::string xml_alert = *(std::string *) data; + LLNotifications::instance().add(self->contextualNotification(xml_alert)); } void LLFloaterDayCycle::initHelpBtn(const std::string& name, const std::string& xml_alert) diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp index b28cc04047..90225ecfa1 100644 --- a/indra/newview/llfloaterenvsettings.cpp +++ b/indra/newview/llfloaterenvsettings.cpp @@ -67,18 +67,8 @@ LLFloaterEnvSettings::~LLFloaterEnvSettings() void LLFloaterEnvSettings::onClickHelp(void* data) { - LLFloaterEnvSettings* self = static_cast<LLFloaterEnvSettings*>(data); - - const char* xml_alert = "EnvSettingsHelpButton"; - LLAlertDialog* dialogp = gViewerWindow->alertXml(xml_alert); - if (dialogp) - { - LLFloater* root_floater = gFloaterView->getParentFloater(self); - if (root_floater) - { - root_floater->addDependentFloater(dialogp); - } - } + LLFloaterEnvSettings* self = (LLFloaterEnvSettings*)data; + LLNotifications::instance().add(self->contextualNotification("EnvSettingsHelpButton")); } void LLFloaterEnvSettings::initCallbacks(void) diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 2d7d2ee15d..f5493172ba 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -523,9 +523,9 @@ void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data) //static void LLPanelFriends::onMaximumSelect(void* user_data) { - LLStringUtil::format_map_t args; - args["[MAX_SELECT]"] = llformat("%d", MAX_FRIEND_SELECT); - LLNotifyBox::showXml("MaxListSelectMessage", args); + LLSD args; + args["MAX_SELECT"] = llformat("%d", MAX_FRIEND_SELECT); + LLNotifications::instance().add("MaxListSelectMessage", args); }; // static @@ -585,27 +585,22 @@ void LLPanelFriends::requestFriendship(const LLUUID& target_id, const std::strin calling_card_folder_id); } -struct LLAddFriendData -{ - LLUUID mID; - std::string mName; -}; - // static -void LLPanelFriends::callbackAddFriendWithMessage(S32 option, const std::string& text, void* data) +bool LLPanelFriends::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response) { - LLAddFriendData* add = (LLAddFriendData*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { - requestFriendship(add->mID, add->mName, text); + requestFriendship(notification["payload"]["id"].asUUID(), + notification["payload"]["name"].asString(), + response["message"].asString()); } - delete add; + return false; } -// static -void LLPanelFriends::callbackAddFriend(S32 option, void* data) +bool LLPanelFriends::callbackAddFriend(const LLSD& notification, const LLSD& response) { - LLAddFriendData* add = (LLAddFriendData*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { // Servers older than 1.25 require the text of the message to be the @@ -613,9 +608,11 @@ void LLPanelFriends::callbackAddFriend(S32 option, void* data) LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); std::string message = calling_card_folder_id.asString(); - requestFriendship(add->mID, add->mName, message); + requestFriendship(notification["payload"]["id"].asUUID(), + notification["payload"]["name"].asString(), + message); } - delete add; + return false; } // static @@ -634,27 +631,25 @@ void LLPanelFriends::requestFriendshipDialog(const LLUUID& id, { if(id == gAgentID) { - LLNotifyBox::showXml("AddSelfFriend"); + LLNotifications::instance().add("AddSelfFriend"); return; } - LLAddFriendData* data = new LLAddFriendData(); - data->mID = id; - data->mName = name; - - LLStringUtil::format_map_t args; - args["[NAME]"] = name; - - // Look for server versions like: Second Life Server 1.24.4.95600 + LLSD args; + args["NAME"] = name; + LLSD payload; + payload["id"] = id; + payload["name"] = name; + // Look for server versions like: Second Life Server 1.24.4.95600 if (gLastVersionChannel.find(" 1.24.") != std::string::npos) { // Old and busted server version, doesn't support friend // requests with messages. - gViewerWindow->alertXml("AddFriend", args, callbackAddFriend, data); + LLNotifications::instance().add("AddFriend", args, payload, &callbackAddFriend); } else { - gViewerWindow->alertXmlEditText("AddFriendWithMessage", args, NULL, NULL, callbackAddFriendWithMessage, data); + LLNotifications::instance().add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage); } } @@ -677,7 +672,7 @@ void LLPanelFriends::onClickRemove(void* user_data) //llinfos << "LLPanelFriends::onClickRemove()" << llendl; LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs(); - LLStringUtil::format_map_t args; + LLSD args; if(ids.size() > 0) { std::string msgType = "RemoveFromFriends"; @@ -687,18 +682,27 @@ void LLPanelFriends::onClickRemove(void* user_data) std::string first, last; if(gCacheName->getName(agent_id, first, last)) { - args["[FIRST_NAME]"] = first; - args["[LAST_NAME]"] = last; + args["FIRST_NAME"] = first; + args["LAST_NAME"] = last; } } else { msgType = "RemoveMultipleFromFriends"; } - gViewerWindow->alertXml(msgType, + LLSD payload; + + for (LLDynamicArray<LLUUID>::iterator it = ids.begin(); + it != ids.end(); + ++it) + { + payload["ids"].append(*it); + } + + LLNotifications::instance().add(msgType, args, - &handleRemove, - (void*)new LLDynamicArray<LLUUID>(ids)); + payload, + &handleRemove); } } @@ -730,13 +734,10 @@ void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command { if (ids.empty()) return; - LLStringUtil::format_map_t args; + LLSD args; if(ids.size() > 0) { - // copy map of ids onto heap - rights_map_t* rights = new rights_map_t(ids); - // package with panel pointer - std::pair<LLPanelFriends*, rights_map_t*>* user_data = new std::pair<LLPanelFriends*, rights_map_t*>(this, rights); + rights_map_t* rights = new rights_map_t(ids); // for single friend, show their name if(ids.size() == 1) @@ -745,62 +746,65 @@ void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command std::string first, last; if(gCacheName->getName(agent_id, first, last)) { - args["[FIRST_NAME]"] = first; - args["[LAST_NAME]"] = last; + args["FIRST_NAME"] = first; + args["LAST_NAME"] = last; } if (command == GRANT) { - gViewerWindow->alertXml("GrantModifyRights", args, modifyRightsConfirmation, user_data); + LLNotifications::instance().add("GrantModifyRights", + args, + LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } else { - gViewerWindow->alertXml("RevokeModifyRights", args, modifyRightsConfirmation, user_data); + LLNotifications::instance().add("RevokeModifyRights", + args, + LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } } else { if (command == GRANT) { - gViewerWindow->alertXml("GrantModifyRightsMultiple", args, modifyRightsConfirmation, user_data); + LLNotifications::instance().add("GrantModifyRightsMultiple", + args, + LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } else { - gViewerWindow->alertXml("RevokeModifyRightsMultiple", args, modifyRightsConfirmation, user_data); + LLNotifications::instance().add("RevokeModifyRightsMultiple", + args, + LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } } } } -// static -void LLPanelFriends::modifyRightsConfirmation(S32 option, void* user_data) +bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights) { - std::pair<LLPanelFriends*, rights_map_t*>* data = (std::pair<LLPanelFriends*, rights_map_t*>*)user_data; - LLPanelFriends* panelp = data->first; - - if(panelp) + S32 option = LLNotification::getSelectedOption(notification, response); + if(0 == option) { - if(0 == option) - { - panelp->sendRightsGrant(*(data->second)); - } - else + sendRightsGrant(*rights); + } + else + { + // need to resync view with model, since user cancelled operation + rights_map_t::iterator rights_it; + for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it) { - // need to resync view with model, since user cancelled operation - rights_map_t* rights = data->second; - rights_map_t::iterator rights_it; - for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it) - { - const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first); - panelp->updateFriendItem(rights_it->first, info); - // Might have changed the column the user is sorted on. - panelp->mFriendsList->sortItems(); - } + const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first); + updateFriendItem(rights_it->first, info); } - panelp->refreshUI(); } + refreshUI(); - delete data->second; - delete data; + delete rights; + return false; } void LLPanelFriends::applyRightsToFriends() @@ -924,12 +928,14 @@ void LLPanelFriends::sendRightsGrant(rights_map_t& ids) // static -void LLPanelFriends::handleRemove(S32 option, void* user_data) +bool LLPanelFriends::handleRemove(const LLSD& notification, const LLSD& response) { - LLDynamicArray<LLUUID>* ids = static_cast<LLDynamicArray<LLUUID>*>(user_data); - for(LLDynamicArray<LLUUID>::iterator itr = ids->begin(); itr != ids->end(); ++itr) + S32 option = LLNotification::getSelectedOption(notification, response); + + const LLSD& ids = notification["payload"]["ids"]; + for(LLSD::array_const_iterator itr = ids.beginArray(); itr != ids.endArray(); ++itr) { - LLUUID id = (*itr); + LLUUID id = itr->asUUID(); const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id); if(ip) { @@ -955,5 +961,5 @@ void LLPanelFriends::handleRemove(S32 option, void* user_data) } } - delete ids; + return false; } diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h index e3f3f96d00..58f7cc3bb2 100644 --- a/indra/newview/llfloaterfriends.h +++ b/indra/newview/llfloaterfriends.h @@ -119,8 +119,8 @@ private: // callback methods static void onSelectName(LLUICtrl* ctrl, void* user_data); - static void callbackAddFriendWithMessage(S32 option, const std::string& text, void* user_data); - static void callbackAddFriend(S32 option, void* user_data); + static bool callbackAddFriend(const LLSD& notification, const LLSD& response); + static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response); static void onPickAvatar(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* user_data); static void onMaximumSelect(void* user_data); @@ -134,8 +134,8 @@ private: static void onClickModifyStatus(LLUICtrl* ctrl, void* user_data); - static void handleRemove(S32 option, void* user_data); - static void modifyRightsConfirmation(S32 option, void* user_data); + static bool handleRemove(const LLSD& notification, const LLSD& response); + bool modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights); private: // member data diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index a4022d844a..c1eb273acc 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -918,34 +918,31 @@ void LLPanelGridTools::refresh() // static void LLPanelGridTools::onClickKickAll(void* userdata) { - LLPanelGridTools* self = (LLPanelGridTools*) userdata; - S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect(left, top, left+400, top-300); - gViewerWindow->alertXmlEditText("KickAllUsers", LLStringUtil::format_map_t(), - NULL, NULL, - LLPanelGridTools::confirmKick, self); + LLNotifications::instance().add("KickAllUsers", LLSD(), LLSD(), LLPanelGridTools::confirmKick); } -void LLPanelGridTools::confirmKick(S32 option, const std::string& text, void* userdata) +bool LLPanelGridTools::confirmKick(const LLSD& notification, const LLSD& response) { - LLPanelGridTools* self = (LLPanelGridTools*) userdata; - - if (option == 0) + if (LLNotification::getSelectedOption(notification, response) == 0) { - self->mKickMessage = text; - gViewerWindow->alertXml("ConfirmKick",LLPanelGridTools::finishKick, self); + LLSD payload; + payload["kick_message"] = response["message"].asString(); + LLNotifications::instance().add("ConfirmKick", LLSD(), payload, LLPanelGridTools::finishKick); } + return false; } // static -void LLPanelGridTools::finishKick(S32 option, void* userdata) +bool LLPanelGridTools::finishKick(const LLSD& notification, const LLSD& response) { - LLPanelGridTools* self = (LLPanelGridTools*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) { @@ -957,26 +954,24 @@ void LLPanelGridTools::finishKick(S32 option, void* userdata) msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); msg->addUUIDFast(_PREHASH_AgentID, LL_UUID_ALL_AGENTS ); msg->addU32("KickFlags", KICK_FLAGS_DEFAULT ); - msg->addStringFast(_PREHASH_Reason, self->mKickMessage ); + msg->addStringFast(_PREHASH_Reason, notification["payload"]["kick_message"].asString()); gAgent.sendReliableMessage(); } + return false; } // static void LLPanelGridTools::onClickFlushMapVisibilityCaches(void* data) { - gViewerWindow->alertXml("FlushMapVisibilityCaches", - flushMapVisibilityCachesConfirm, data); + LLNotifications::instance().add("FlushMapVisibilityCaches", LLSD(), LLSD(), flushMapVisibilityCachesConfirm); } // static -void LLPanelGridTools::flushMapVisibilityCachesConfirm(S32 option, void* data) +bool LLPanelGridTools::flushMapVisibilityCachesConfirm(const LLSD& notification, const LLSD& response) { - if (option != 0) return; - - LLPanelGridTools* self = (LLPanelGridTools*)data; - if (!self) return; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; // HACK: Send this as an EstateOwnerRequest so it gets routed // correctly by the spaceserver. JC @@ -992,6 +987,7 @@ void LLPanelGridTools::flushMapVisibilityCachesConfirm(S32 option, void* data) msg->nextBlock("ParamList"); msg->addString("Parameter", gAgent.getID().asString()); gAgent.sendReliableMessage(); + return false; } @@ -1182,13 +1178,16 @@ void LLPanelObjectTools::onClickDeletePublicOwnedBy(void* userdata) panelp->mSimWideDeletesFlags = SWD_SCRIPTED_ONLY | SWD_OTHERS_LAND_ONLY; - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD args; + args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD payload; + payload["avatar_id"] = panelp->mTargetAvatar; + payload["flags"] = (S32)panelp->mSimWideDeletesFlags; - gViewerWindow->alertXml( "GodDeleteAllScriptedPublicObjectsByUser", + LLNotifications::instance().add( "GodDeleteAllScriptedPublicObjectsByUser", args, - callbackSimWideDeletes, - userdata); + payload, + callbackSimWideDeletes); } } @@ -1201,13 +1200,16 @@ void LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy(void* userdata) { panelp->mSimWideDeletesFlags = SWD_SCRIPTED_ONLY; - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD args; + args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD payload; + payload["avatar_id"] = panelp->mTargetAvatar; + payload["flags"] = (S32)panelp->mSimWideDeletesFlags; - gViewerWindow->alertXml( "GodDeleteAllScriptedObjectsByUser", + LLNotifications::instance().add( "GodDeleteAllScriptedObjectsByUser", args, - callbackSimWideDeletes, - userdata); + payload, + callbackSimWideDeletes); } } @@ -1220,28 +1222,32 @@ void LLPanelObjectTools::onClickDeleteAllOwnedBy(void* userdata) { panelp->mSimWideDeletesFlags = 0; - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD args; + args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD payload; + payload["avatar_id"] = panelp->mTargetAvatar; + payload["flags"] = (S32)panelp->mSimWideDeletesFlags; - gViewerWindow->alertXml( "GodDeleteAllObjectsByUser", + LLNotifications::instance().add( "GodDeleteAllObjectsByUser", args, - callbackSimWideDeletes, - userdata); + payload, + callbackSimWideDeletes); } } // static -void LLPanelObjectTools::callbackSimWideDeletes( S32 option, void* userdata ) +bool LLPanelObjectTools::callbackSimWideDeletes( const LLSD& notification, const LLSD& response ) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { - LLPanelObjectTools* object_tools = (LLPanelObjectTools*) userdata; - if (!object_tools->mTargetAvatar.isNull()) + if (!notification["payload"]["avatar_id"].asUUID().isNull()) { - send_sim_wide_deletes(object_tools->mTargetAvatar, - object_tools->mSimWideDeletesFlags); + send_sim_wide_deletes(notification["payload"]["avatar_id"].asUUID(), + notification["payload"]["flags"].asInteger()); } } + return false; } void LLPanelObjectTools::onClickSet(void* data) @@ -1420,7 +1426,7 @@ void LLPanelRequestTools::onClickRequest(void* data) void terrain_download_done(void** data, S32 status, LLExtStat ext_status) { - LLNotifyBox::showXml("TerrainDownloaded"); + LLNotifications::instance().add("TerrainDownloaded"); } diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index 7cc840cc97..b70b9d795d 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -201,11 +201,11 @@ public: void refresh(); static void onClickKickAll(void *data); - static void confirmKick(S32 option, const std::string& text, void* userdata); - static void finishKick(S32 option, void* userdata); + static bool confirmKick(const LLSD& notification, const LLSD& response); + static bool finishKick(const LLSD& notification, const LLSD& response); static void onDragSunPhase(LLUICtrl *ctrl, void *userdata); static void onClickFlushMapVisibilityCaches(void* data); - static void flushMapVisibilityCachesConfirm(S32 option, void* data); + static bool flushMapVisibilityCachesConfirm(const LLSD& notification, const LLSD& response); protected: std::string mKickMessage; // Message to send on kick @@ -240,7 +240,7 @@ public: static void onClickDeletePublicOwnedBy(void* data); static void onClickDeleteAllScriptedOwnedBy(void* data); static void onClickDeleteAllOwnedBy(void* data); - static void callbackSimWideDeletes(S32 option, void* userdata); + static bool callbackSimWideDeletes(const LLSD& notification, const LLSD& response); static void onGetTopColliders(void* data); static void onGetTopScripts(void* data); static void onGetScriptDigest(void* data); diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index ca3332e4ad..e798327bb7 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -388,10 +388,11 @@ void LLPanelGroups::leave() } if(i < count) { - LLUUID* cb_data = new LLUUID((const LLUUID&)group_id); - LLStringUtil::format_map_t args; - args["[GROUP]"] = gAgent.mGroups.get(i).mName; - gViewerWindow->alertXml("GroupLeaveConfirmMember", args, callbackLeaveGroup, (void*)cb_data); + LLSD args; + args["GROUP"] = gAgent.mGroups.get(i).mName; + LLSD payload; + payload["group_id"] = group_id; + LLNotifications::instance().add("GroupLeaveConfirmMember", args, payload, callbackLeaveGroup); } } } @@ -402,10 +403,11 @@ void LLPanelGroups::search() } // static -void LLPanelGroups::callbackLeaveGroup(S32 option, void* userdata) +bool LLPanelGroups::callbackLeaveGroup(const LLSD& notification, const LLSD& response) { - LLUUID* group_id = (LLUUID*)userdata; - if(option == 0 && group_id) + S32 option = LLNotification::getSelectedOption(notification, response); + LLUUID group_id = notification["payload"]["group_id"].asUUID(); + if(option == 0) { LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_LeaveGroupRequest); @@ -413,10 +415,10 @@ void LLPanelGroups::callbackLeaveGroup(S32 option, void* userdata) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, *group_id); + msg->addUUIDFast(_PREHASH_GroupID, group_id); gAgent.sendReliableMessage(); } - delete group_id; + return false; } void LLPanelGroups::onGroupList(LLUICtrl* ctrl, void* userdata) diff --git a/indra/newview/llfloatergroups.h b/indra/newview/llfloatergroups.h index 6d99f34085..a94b143d39 100644 --- a/indra/newview/llfloatergroups.h +++ b/indra/newview/llfloatergroups.h @@ -120,7 +120,7 @@ protected: void search(); void callVote(); - static void callbackLeaveGroup(S32 option, void* userdata); + static bool callbackLeaveGroup(const LLSD& notification, const LLSD& response); }; diff --git a/indra/newview/llfloaterhardwaresettings.cpp b/indra/newview/llfloaterhardwaresettings.cpp index e4c13b2ae4..1db153434f 100644 --- a/indra/newview/llfloaterhardwaresettings.cpp +++ b/indra/newview/llfloaterhardwaresettings.cpp @@ -62,7 +62,7 @@ LLFloaterHardwareSettings::~LLFloaterHardwareSettings() void LLFloaterHardwareSettings::onClickHelp(void* data) { const char* xml_alert = "HardwareSettingsHelpButton"; - gViewerWindow->alertXml(xml_alert); + LLNotifications::instance().add(xml_alert); } void LLFloaterHardwareSettings::initCallbacks(void) diff --git a/indra/newview/llfloaterhud.cpp b/indra/newview/llfloaterhud.cpp index 848068ee9d..8c97628e4e 100644 --- a/indra/newview/llfloaterhud.cpp +++ b/indra/newview/llfloaterhud.cpp @@ -102,7 +102,7 @@ void LLFloaterHUD::showHUD() // do not build the floater if there the url is empty if (gSavedSettings.getString("TutorialURL") == "") { - LLAlertDialog::showXml("TutorialNotFound"); + LLNotifications::instance().add("TutorialNotFound"); return; } diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index a92634bc31..8b4b3805ee 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -85,8 +85,6 @@ static const BOOL BUY_PERSONAL_LAND = FALSE; LLParcelSelectionObserver* LLFloaterLand::sObserver = NULL; S32 LLFloaterLand::sLastTab = 0; -LLHandle<LLFloater> LLPanelLandGeneral::sBuyPassDialogHandle; - // Local classes class LLParcelSelectionObserver : public LLParcelObserver { @@ -872,12 +870,12 @@ void LLPanelLandGeneral::onClickBuyPass(void* data) cost = llformat("%d", pass_price); time = llformat("%.2f", pass_hours); - LLStringUtil::format_map_t args; - args["[COST]"] = cost; - args["[PARCEL_NAME]"] = parcel_name; - args["[TIME]"] = time; + LLSD args; + args["COST"] = cost; + args["PARCEL_NAME"] = parcel_name; + args["TIME"] = time; - sBuyPassDialogHandle = gViewerWindow->alertXml("LandBuyPass", args, cbBuyPass)->getHandle(); + LLNotifications::instance().add("LandBuyPass", args, LLSD(), cbBuyPass); } // static @@ -889,7 +887,7 @@ void LLPanelLandGeneral::onClickStartAuction(void* data) { if(parcelp->getForSale()) { - gViewerWindow->alertXml("CannotStartAuctionAlreadForSale"); + LLNotifications::instance().add("CannotStartAuctionAlreadForSale"); } else { @@ -899,19 +897,15 @@ void LLPanelLandGeneral::onClickStartAuction(void* data) } // static -void LLPanelLandGeneral::cbBuyPass(S32 option, void* data) +bool LLPanelLandGeneral::cbBuyPass(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { // User clicked OK LLViewerParcelMgr::getInstance()->buyPass(); } -} - -//static -BOOL LLPanelLandGeneral::buyPassDialogVisible() -{ - return sBuyPassDialogHandle.get() != NULL; + return false; } // static @@ -1249,28 +1243,27 @@ void send_return_objects_message(S32 parcel_local_id, S32 return_type, msg->sendReliable(region->getHost()); } -// static -void LLPanelLandObjects::callbackReturnOwnerObjects(S32 option, void* userdata) +bool LLPanelLandObjects::callbackReturnOwnerObjects(const LLSD& notification, const LLSD& response) { - LLPanelLandObjects *lop = (LLPanelLandObjects *)userdata; - LLParcel *parcel = lop->mParcel->getParcel(); + S32 option = LLNotification::getSelectedOption(notification, response); + LLParcel *parcel = mParcel->getParcel(); if (0 == option) { if (parcel) { LLUUID owner_id = parcel->getOwnerID(); - LLStringUtil::format_map_t args; + LLSD args; if (owner_id == gAgentID) { - LLNotifyBox::showXml("OwnedObjectsReturned"); + LLNotifications::instance().add("OwnedObjectsReturned"); } else { std::string first, last; gCacheName->getName(owner_id, first, last); - args["[FIRST]"] = first; - args["[LAST]"] = last; - LLNotifyBox::showXml("OtherObjectsReturned", args); + args["FIRST"] = first; + args["LAST"] = last; + LLNotifications::instance().add("OtherObjectsReturned", args); } send_return_objects_message(parcel->getLocalID(), RT_OWNER); } @@ -1278,81 +1271,82 @@ void LLPanelLandObjects::callbackReturnOwnerObjects(S32 option, void* userdata) LLSelectMgr::getInstance()->unhighlightAll(); LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - lop->refresh(); + refresh(); + return false; } -// static -void LLPanelLandObjects::callbackReturnGroupObjects(S32 option, void* userdata) +bool LLPanelLandObjects::callbackReturnGroupObjects(const LLSD& notification, const LLSD& response) { - LLPanelLandObjects *lop = (LLPanelLandObjects *)userdata; - LLParcel *parcel = lop->mParcel->getParcel(); + S32 option = LLNotification::getSelectedOption(notification, response); + LLParcel *parcel = mParcel->getParcel(); if (0 == option) { if (parcel) { std::string group_name; gCacheName->getGroupName(parcel->getGroupID(), group_name); - LLStringUtil::format_map_t args; - args["[GROUPNAME]"] = group_name; - LLNotifyBox::showXml("GroupObjectsReturned", args); + LLSD args; + args["GROUPNAME"] = group_name; + LLNotifications::instance().add("GroupObjectsReturned", args); send_return_objects_message(parcel->getLocalID(), RT_GROUP); } } LLSelectMgr::getInstance()->unhighlightAll(); LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - lop->refresh(); + refresh(); + return false; } -// static -void LLPanelLandObjects::callbackReturnOtherObjects(S32 option, void* userdata) +bool LLPanelLandObjects::callbackReturnOtherObjects(const LLSD& notification, const LLSD& response) { - LLPanelLandObjects *lop = (LLPanelLandObjects *)userdata; - LLParcel *parcel = lop->mParcel->getParcel(); + S32 option = LLNotification::getSelectedOption(notification, response); + LLParcel *parcel = mParcel->getParcel(); if (0 == option) { if (parcel) { - LLNotifyBox::showXml("UnOwnedObjectsReturned"); + LLNotifications::instance().add("UnOwnedObjectsReturned"); send_return_objects_message(parcel->getLocalID(), RT_OTHER); } } LLSelectMgr::getInstance()->unhighlightAll(); LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - lop->refresh(); + refresh(); + return false; } -// static -void LLPanelLandObjects::callbackReturnOwnerList(S32 option, void* userdata) +bool LLPanelLandObjects::callbackReturnOwnerList(const LLSD& notification, const LLSD& response) { - LLPanelLandObjects *self = (LLPanelLandObjects *)userdata; - LLParcel *parcel = self->mParcel->getParcel(); + S32 option = LLNotification::getSelectedOption(notification, response); + LLParcel *parcel = mParcel->getParcel(); if (0 == option) { if (parcel) { // Make sure we have something selected. - uuid_list_t::iterator selected = self->mSelectedOwners.begin(); - if (selected != self->mSelectedOwners.end()) + uuid_list_t::iterator selected = mSelectedOwners.begin(); + if (selected != mSelectedOwners.end()) { - LLStringUtil::format_map_t args; - if (self->mSelectedIsGroup) + LLSD args; + if (mSelectedIsGroup) { - args["[GROUPNAME]"] = self->mSelectedName; - LLNotifyBox::showXml("GroupObjectsReturned", args); + args["GROUPNAME"] = mSelectedName; + LLNotifications::instance().add("GroupObjectsReturned", args); } else { - args["[NAME]"] = self->mSelectedName; - LLNotifyBox::showXml("OtherObjectsReturned2", args); + args["NAME"] = mSelectedName; + LLNotifications::instance().add("OtherObjectsReturned2", args); } - send_return_objects_message(parcel->getLocalID(), RT_LIST, &(self->mSelectedOwners)); + send_return_objects_message(parcel->getLocalID(), RT_LIST, &(mSelectedOwners)); } } } LLSelectMgr::getInstance()->unhighlightAll(); LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - self->refresh(); + refresh(); + return false; } @@ -1374,16 +1368,16 @@ void LLPanelLandObjects::onClickReturnOwnerList(void* userdata) send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &(self->mSelectedOwners)); - LLStringUtil::format_map_t args; - args["[NAME]"] = self->mSelectedName; - args["[N]"] = llformat("%d",self->mSelectedCount); + LLSD args; + args["NAME"] = self->mSelectedName; + args["N"] = llformat("%d",self->mSelectedCount); if (self->mSelectedIsGroup) { - gViewerWindow->alertXml("ReturnObjectsDeededToGroup", args, callbackReturnOwnerList, userdata); + LLNotifications::instance().add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); } else { - gViewerWindow->alertXml("ReturnObjectsOwnedByUser", args, callbackReturnOwnerList, userdata); + LLNotifications::instance().add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); } } @@ -1591,19 +1585,19 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata) LLUUID owner_id = parcel->getOwnerID(); - LLStringUtil::format_map_t args; - args["[N]"] = llformat("%d",owned); + LLSD args; + args["N"] = llformat("%d",owned); if (owner_id == gAgent.getID()) { - gViewerWindow->alertXml("ReturnObjectsOwnedBySelf", args, callbackReturnOwnerObjects, userdata); + LLNotifications::instance().add("ReturnObjectsOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); } else { std::string name; gCacheName->getFullName(owner_id, name); - args["[NAME]"] = name; - gViewerWindow->alertXml("ReturnObjectsOwnedByUser", args, callbackReturnOwnerObjects, userdata); + args["NAME"] = name; + LLNotifications::instance().add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); } } @@ -1619,12 +1613,12 @@ void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata) std::string group_name; gCacheName->getGroupName(parcel->getGroupID(), group_name); - LLStringUtil::format_map_t args; - args["[NAME]"] = group_name; - args["[N]"] = llformat("%d", parcel->getGroupPrimCount()); + LLSD args; + args["NAME"] = group_name; + args["N"] = llformat("%d", parcel->getGroupPrimCount()); // create and show confirmation textbox - gViewerWindow->alertXml("ReturnObjectsDeededToGroup", args, callbackReturnGroupObjects, userdata); + LLNotifications::instance().add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnGroupObjects, panelp, _1, _2)); } // static @@ -1640,16 +1634,16 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) send_parcel_select_objects(parcel->getLocalID(), RT_OTHER); - LLStringUtil::format_map_t args; - args["[N]"] = llformat("%d", other); + LLSD args; + args["N"] = llformat("%d", other); if (parcel->getIsGroupOwned()) { std::string group_name; gCacheName->getGroupName(parcel->getGroupID(), group_name); - args["[NAME]"] = group_name; + args["NAME"] = group_name; - gViewerWindow->alertXml("ReturnObjectsNotOwnedByGroup", args, callbackReturnOtherObjects, userdata); + LLNotifications::instance().add("ReturnObjectsNotOwnedByGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); } else { @@ -1657,15 +1651,15 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) if (owner_id == gAgent.getID()) { - gViewerWindow->alertXml("ReturnObjectsNotOwnedBySelf", args, callbackReturnOtherObjects, userdata); + LLNotifications::instance().add("ReturnObjectsNotOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); } else { std::string name; gCacheName->getFullName(owner_id, name); - args["[NAME]"] = name; + args["NAME"] = name; - gViewerWindow->alertXml("ReturnObjectsNotOwnedByUser", args, callbackReturnOtherObjects, userdata); + LLNotifications::instance().add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); } } } @@ -2073,7 +2067,7 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) if (!allow_other_scripts && region && region->getAllowDamage()) { - gViewerWindow->alertXml("UnableToDisableOutsideScripts"); + LLNotifications::instance().add("UnableToDisableOutsideScripts"); return; } @@ -2117,7 +2111,7 @@ void LLPanelLandOptions::onClickSet(void* userdata) if (agent_parcel->getLocalID() != selected_parcel->getLocalID()) { - gViewerWindow->alertXml("MustBeInParcel"); + LLNotifications::instance().add("MustBeInParcel"); return; } @@ -2160,11 +2154,11 @@ void LLPanelLandOptions::onClickPublishHelp(void*) if(! can_change_identity) { - gViewerWindow->alertXml("ClickPublishHelpLandDisabled"); + LLNotifications::instance().add("ClickPublishHelpLandDisabled"); } else { - gViewerWindow->alertXml("ClickPublishHelpLand"); + LLNotifications::instance().add("ClickPublishHelpLand"); } } diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 9bed9d53ae..1d95a3e3f6 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -151,8 +151,7 @@ public: static void finalizeSetSellChange(void * userdata); static void onSalePriceChange(LLUICtrl *ctrl, void * userdata); - static void cbBuyPass(S32 option, void*); - static BOOL buyPassDialogVisible(); + static bool cbBuyPass(const LLSD& notification, const LLSD& response); static void onClickSellLand(void* data); static void onClickStopSellLand(void* data); @@ -234,10 +233,10 @@ public: void refresh(); virtual void draw(); - static void callbackReturnOwnerObjects(S32, void*); - static void callbackReturnGroupObjects(S32, void*); - static void callbackReturnOtherObjects(S32, void*); - static void callbackReturnOwnerList(S32, void*); + bool callbackReturnOwnerObjects(const LLSD& notification, const LLSD& response); + bool callbackReturnGroupObjects(const LLSD& notification, const LLSD& response); + bool callbackReturnOtherObjects(const LLSD& notification, const LLSD& response); + bool callbackReturnOwnerList(const LLSD& notification, const LLSD& response); static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = 0); static void onClickShowOwnerObjects(void*); diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp new file mode 100644 index 0000000000..12dcd58254 --- /dev/null +++ b/indra/newview/llfloaternotificationsconsole.cpp @@ -0,0 +1,292 @@ +/** + * @file llnotificationsconsole.cpp + * @brief Debugging console for unified notifications. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaternotificationsconsole.h" +#include "llnotifications.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llscrolllistctrl.h" +#include "llpanel.h" +#include "llcombobox.h" +#include "llviewertexteditor.h" + +const S32 NOTIFICATION_PANEL_HEADER_HEIGHT = 20; +const S32 HEADER_PADDING = 38; + +class LLNotificationChannelPanel : public LLPanel +{ +public: + LLNotificationChannelPanel(const std::string& channel_name); + BOOL postBuild(); + +private: + bool update(const LLSD& payload, bool passed_filter); + static void toggleClick(void* user_data); + static void onClickNotification(void* user_data); + static void onClickNotificationReject(void* user_data); + LLNotificationChannelPtr mChannelPtr; + LLNotificationChannelPtr mChannelRejectsPtr; +}; + +LLNotificationChannelPanel::LLNotificationChannelPanel(const std::string& channel_name) + : LLPanel(channel_name) +{ + mChannelPtr = LLNotifications::instance().getChannel(channel_name); + mChannelRejectsPtr = LLNotificationChannelPtr( + new LLNotificationChannel(channel_name + "rejects", mChannelPtr->getParentChannelName(), !boost::bind(mChannelPtr->getFilter(), _1))); + LLUICtrlFactory::instance().buildPanel(this, "panel_notifications_channel.xml"); +} + +BOOL LLNotificationChannelPanel::postBuild() +{ + LLButton* header_button = getChild<LLButton>("header"); + header_button->setLabel(mChannelPtr->getName()); + header_button->setClickedCallback(toggleClick, this); + + mChannelPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, true)); + mChannelRejectsPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, false)); + + LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("notifications_list"); + scroll->setDoubleClickCallback(onClickNotification); + scroll->setCallbackUserData(this); + + scroll = getChild<LLScrollListCtrl>("notification_rejects_list"); + scroll->setDoubleClickCallback(onClickNotificationReject); + scroll->setCallbackUserData(this); + + return TRUE; +} + +//static +void LLNotificationChannelPanel::toggleClick(void *user_data) +{ + LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data; + if (!self) return; + + LLButton* header_button = self->getChild<LLButton>("header"); + + LLLayoutStack* stack = dynamic_cast<LLLayoutStack*>(self->getParent()); + if (stack) + { + stack->collapsePanel(self, header_button->getToggleState()); + } + + // turn off tab stop for collapsed panel + self->getChild<LLScrollListCtrl>("notifications_list")->setTabStop(!header_button->getToggleState()); + self->getChild<LLScrollListCtrl>("notifications_list")->setVisible(!header_button->getToggleState()); + self->getChild<LLScrollListCtrl>("notification_rejects_list")->setTabStop(!header_button->getToggleState()); + self->getChild<LLScrollListCtrl>("notification_rejects_list")->setVisible(!header_button->getToggleState()); +} + +/*static*/ +void LLNotificationChannelPanel::onClickNotification(void* user_data) +{ + LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data; + if (!self) return; + void* data = self->getChild<LLScrollListCtrl>("notifications_list")->getFirstSelected()->getUserdata(); + if (data) + { + gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE); + } +} + +/*static*/ +void LLNotificationChannelPanel::onClickNotificationReject(void* user_data) +{ + LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data; + if (!self) return; + void* data = self->getChild<LLScrollListCtrl>("notification_rejects_list")->getFirstSelected()->getUserdata(); + if (data) + { + gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE); + } +} + +bool LLNotificationChannelPanel::update(const LLSD& payload, bool passed_filter) +{ + LLNotificationPtr notification = LLNotifications::instance().find(payload["id"].asUUID()); + if (notification) + { + LLSD row; + row["columns"][0]["value"] = notification->getName(); + row["columns"][0]["column"] = "name"; + + row["columns"][1]["value"] = notification->getMessage(); + row["columns"][1]["column"] = "content"; + + row["columns"][2]["value"] = notification->getDate(); + row["columns"][2]["column"] = "date"; + row["columns"][2]["type"] = "date"; + + LLScrollListItem* sli = passed_filter ? + getChild<LLScrollListCtrl>("notifications_list")->addElement(row) : + getChild<LLScrollListCtrl>("notification_rejects_list")->addElement(row); + sli->setUserdata(&(*notification)); + } + + return false; +} + +// +// LLFloaterNotificationConsole +// +LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key) +{ + LLUICtrlFactory::instance().buildFloater(this, "floater_notifications_console.xml"); +} + +void LLFloaterNotificationConsole::onClose(bool app_quitting) +{ + setVisible(FALSE); + //destroy(); +} + + +BOOL LLFloaterNotificationConsole::postBuild() +{ + // these are in the order of processing + addChannel("Unexpired"); + addChannel("Ignore"); + addChannel("Visible", true); + // all the ones below attach to the Visible channel + addChannel("History"); + addChannel("Alerts"); + addChannel("AlertModal"); + addChannel("Group Notifications"); + addChannel("Notifications"); + addChannel("NotificationTips"); + + getChild<LLButton>("add_notification")->setClickedCallback(onClickAdd, this); + + LLComboBox* notifications = getChild<LLComboBox>("notification_types"); + LLNotifications::TemplateNames names = LLNotifications::instance().getTemplateNames(); + for (LLNotifications::TemplateNames::iterator template_it = names.begin(); + template_it != names.end(); + ++template_it) + { + notifications->add(*template_it); + } + notifications->sortByName(); + + return TRUE; +} + +void LLFloaterNotificationConsole::addChannel(const std::string& name, bool open) +{ + LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels"); + LLNotificationChannelPanel* panelp = new LLNotificationChannelPanel(name); + stack.addPanel(panelp, 0, NOTIFICATION_PANEL_HEADER_HEIGHT, TRUE, TRUE, LLLayoutStack::ANIMATE); + + LLButton& header_button = panelp->getChildRef<LLButton>("header"); + header_button.setToggleState(!open); + stack.collapsePanel(panelp, !open); + + updateResizeLimits(); +} + +void LLFloaterNotificationConsole::removeChannel(const std::string& name) +{ + LLPanel* panelp = getChild<LLPanel>(name, TRUE, FALSE); + if (panelp) + { + getChildRef<LLLayoutStack>("notification_channels").removePanel(panelp); + delete panelp; + } + + updateResizeLimits(); +} + +//static +void LLFloaterNotificationConsole::updateResizeLimits() +{ + LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels"); + setResizeLimits(getMinWidth(), LLFLOATER_HEADER_SIZE + HEADER_PADDING + ((NOTIFICATION_PANEL_HEADER_HEIGHT + 3) * stack.getNumPanels())); +} + +void LLFloaterNotificationConsole::onClickAdd(void* user_data) +{ + LLFloaterNotificationConsole* floater = (LLFloaterNotificationConsole*)user_data; + + std::string message_name = floater->getChild<LLComboBox>("notification_types")->getValue().asString(); + if (!message_name.empty()) + { + LLNotifications::instance().add(message_name, LLSD()); + } +} + + +//=============== LLFloaterNotification ================ + +LLFloaterNotification::LLFloaterNotification(LLNotification* note) : mNote(note) +{ + LLUICtrlFactory::instance().buildFloater(this, "floater_notification.xml"); +} + +BOOL LLFloaterNotification::postBuild() +{ + setTitle(mNote->getName()); + getChild<LLViewerTextEditor>("payload")->setText(mNote->getMessage()); + + LLComboBox* responses_combo = getChild<LLComboBox>("response"); + LLCtrlListInterface* response_list = responses_combo->getListInterface(); + LLNotificationFormPtr form(mNote->getForm()); + if(!form) + { + return TRUE; + } + + responses_combo->setCommitCallback(onCommitResponse); + responses_combo->setCallbackUserData(this); + + LLSD form_sd = form->asLLSD(); + + for (LLSD::array_const_iterator form_item = form_sd.beginArray(); form_item != form_sd.endArray(); ++form_item) + { + if ( (*form_item)["type"].asString() != "button") continue; + std::string text = (*form_item)["text"].asString(); + response_list->addSimpleElement(text); + } + + return TRUE; +} + +void LLFloaterNotification::respond() +{ + LLComboBox* responses_combo = getChild<LLComboBox>("response"); + LLCtrlListInterface* response_list = responses_combo->getListInterface(); + const std::string& trigger = response_list->getSelectedValue().asString(); + //llinfos << trigger << llendl; + + LLSD response = mNote->getResponseTemplate(); + response[trigger] = true; + mNote->respond(response); +} diff --git a/indra/newview/llfloaternotificationsconsole.h b/indra/newview/llfloaternotificationsconsole.h new file mode 100644 index 0000000000..5b8e79f0bb --- /dev/null +++ b/indra/newview/llfloaternotificationsconsole.h @@ -0,0 +1,78 @@ +/** + * @file llfloaternotificationsconsole.h + * @brief Debugging console for unified notifications. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATER_NOTIFICATIONS_CONSOLE_H +#define LL_LLFLOATER_NOTIFICATIONS_CONSOLE_H + +#include "llfloater.h" +#include "llnotifications.h" + +class LLFloaterNotificationConsole : + public LLFloater, + public LLFloaterSingleton<LLFloaterNotificationConsole> +{ +public: + LLFloaterNotificationConsole(const LLSD& key); + + // LLPanel + BOOL postBuild(); + void onClose(bool app_quitting); + + void addChannel(const std::string& type, bool open = false); + void updateResizeLimits(LLLayoutStack &stack); + + void removeChannel(const std::string& type); + void updateResizeLimits(); + +private: + static void onClickAdd(void* user_data); +}; + + +/* + * @brief Pop-up debugging view of a generic new notification. + */ +class LLFloaterNotification : public LLFloater +{ +public: + LLFloaterNotification(LLNotification* note); + + // LLPanel + BOOL postBuild(); + void respond(); + void onClose(bool app_quitting) { setVisible(FALSE); } + +private: + static void onCommitResponse(LLUICtrl* ctrl, void* data) { ((LLFloaterNotification*)data)->respond(); } + LLNotification* mNote; +}; +#endif + diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index b1380ccd8c..55376c5634 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -109,7 +109,7 @@ void LLFloaterOpenObject::show() LLObjectSelectionHandle object_selection = LLSelectMgr::getInstance()->getSelection(); if (object_selection->getRootObjectCount() != 1) { - gViewerWindow->alertXml("UnableToViewContentsMoreThanOne"); + LLNotifications::instance().add("UnableToViewContentsMoreThanOne"); return; } @@ -131,7 +131,7 @@ void LLFloaterOpenObject::moveToInventory(bool wear) { if (mObjectSelection->getRootObjectCount() != 1) { - gViewerWindow->alertXml("OnlyCopyContentsOfSingleItem"); + LLNotifications::instance().add("OnlyCopyContentsOfSingleItem"); return; } @@ -172,7 +172,7 @@ void LLFloaterOpenObject::moveToInventory(bool wear) delete data; data = NULL; - gViewerWindow->alertXml("OpenObjectCannotCopy"); + LLNotifications::instance().add("OpenObjectCannotCopy"); } } diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 9405bc61b2..c2d67d602a 100644 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -153,5 +153,5 @@ U32 LLFloaterPerms::getNextOwnerPerms(std::string prefix) //static void LLFloaterPerms::onClickHelp(void* data) { - gViewerWindow->alertXml("ClickUploadHelpPermissions"); + LLNotifications::instance().add("ClickUploadHelpPermissions"); } diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index 3182568fe8..f5a7a65abf 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -249,20 +249,20 @@ void LLFloaterPostcard::onClickSend(void* data) if (to.empty() || !boost::regex_match(to, emailFormat)) { - gViewerWindow->alertXml("PromptRecipientEmail"); + LLNotifications::instance().add("PromptRecipientEmail"); return; } if (from.empty() || !boost::regex_match(from, emailFormat)) { - gViewerWindow->alertXml("PromptSelfEmail"); + LLNotifications::instance().add("PromptSelfEmail"); return; } std::string subject(self->childGetValue("subject_form").asString()); if(subject.empty() || !self->mHasFirstMsgFocus) { - gViewerWindow->alertXml("PromptMissingSubjMsg", missingSubjMsgAlertCallback, self); + LLNotifications::instance().add("PromptMissingSubjMsg", LLSD(), LLSD(), boost::bind(&LLFloaterPostcard::missingSubjMsgAlertCallback, self, _1, _2)); return; } @@ -272,7 +272,7 @@ void LLFloaterPostcard::onClickSend(void* data) } else { - gViewerWindow->alertXml("ErrorProcessingSnapshot"); + LLNotifications::instance().add("ErrorProcessingSnapshot"); } } } @@ -286,9 +286,9 @@ void LLFloaterPostcard::uploadCallback(const LLUUID& asset_id, void *user_data, if (result) { - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(result)); - gViewerWindow->alertXml("ErrorUploadingPostcard", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotifications::instance().add("ErrorUploadingPostcard", args); } else { @@ -345,30 +345,28 @@ void LLFloaterPostcard::onMsgFormFocusRecieved(LLFocusableElement* receiver, voi } } -void LLFloaterPostcard::missingSubjMsgAlertCallback(S32 option, void* data) +bool LLFloaterPostcard::missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response) { - if(data) + S32 option = LLNotification::getSelectedOption(notification, response); + if(0 == option) { - LLFloaterPostcard* self = static_cast<LLFloaterPostcard*>(data); - if(0 == option) + // User clicked OK + if((childGetValue("subject_form").asString()).empty()) { - // User clicked OK - if((self->childGetValue("subject_form").asString()).empty()) - { - // Stuff the subject back into the form. - self->childSetValue("subject_form", self->getString("default_subject")); - } - - if(!self->mHasFirstMsgFocus) - { - // The user never switched focus to the messagee window. - // Using the default string. - self->childSetValue("msg_form", self->getString("default_message")); - } + // Stuff the subject back into the form. + childSetValue("subject_form", getString("default_subject")); + } - self->sendPostcard(); + if(!mHasFirstMsgFocus) + { + // The user never switched focus to the messagee window. + // Using the default string. + childSetValue("msg_form", getString("default_message")); } + + sendPostcard(); } + return false; } void LLFloaterPostcard::sendPostcard() diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h index 28248f65df..94c619c7e5 100644 --- a/indra/newview/llfloaterpostcard.h +++ b/indra/newview/llfloaterpostcard.h @@ -65,7 +65,7 @@ public: static void updateUserInfo(const std::string& email); static void onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data); - static void missingSubjMsgAlertCallback(S32 option, void* data); + bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response); void sendPostcard(); diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp index 692b7e036f..ce5f9c124f 100644 --- a/indra/newview/llfloaterpostprocess.cpp +++ b/indra/newview/llfloaterpostprocess.cpp @@ -169,11 +169,13 @@ void LLFloaterPostProcess::onSaveEffect(void* userData) { LLLineEditor* editBox = static_cast<LLLineEditor*>(userData); - LLSD::String effectName(editBox->getValue().asString()); + std::string effectName(editBox->getValue().asString()); if (gPostProcess->mAllEffects.has(effectName)) { - gViewerWindow->alertXml("PPSaveEffectAlert", &LLFloaterPostProcess::saveAlertCallback, userData); + LLSD payload; + payload["effect_name"] = effectName; + LLNotifications::instance().add("PPSaveEffectAlert", LLSD(), payload, &LLFloaterPostProcess::saveAlertCallback); } else { @@ -192,20 +194,18 @@ void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl, void * userData) editBox->setValue(comboBox->getSelectedValue()); } -void LLFloaterPostProcess::saveAlertCallback(S32 option, void* userData) +bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLSD& response) { - LLLineEditor* editBox = static_cast<LLLineEditor*>(userData); + S32 option = LLNotification::getSelectedOption(notification, response); // if they choose save, do it. Otherwise, don't do anything if (option == 0) { - LLSD::String effectName(editBox->getValue().asString()); - - gPostProcess->saveEffect(effectName); + gPostProcess->saveEffect(notification["payload"]["effect_name"].asString()); sPostProcess->syncMenu(); } - + return false; } void LLFloaterPostProcess::show() diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h index 8b590f8b8e..88d3fd04e7 100644 --- a/indra/newview/llfloaterpostprocess.h +++ b/indra/newview/llfloaterpostprocess.h @@ -68,7 +68,7 @@ public: static void onChangeEffectName(LLUICtrl* ctrl, void * userData); /// prompts a user when overwriting an effect - static void saveAlertCallback(S32 option, void* userData); + static bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// show off our menu static void show(); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 737a2afbb7..1e10f90609 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -59,6 +59,7 @@ #include "llfloatergroups.h" #include "llfloatertelehub.h" #include "llfloaterwindlight.h" +#include "llinventorymodel.h" #include "lllineeditor.h" #include "llalertdialog.h" #include "llnamelistctrl.h" @@ -540,8 +541,8 @@ void LLPanelRegionInfo::initHelpBtn(const std::string& name, const std::string& // static void LLPanelRegionInfo::onClickHelp(void* data) { - const std::string* xml_alert = (std::string*)data; - gViewerWindow->alertXml(*xml_alert); + std::string* xml_alert = (std::string*)data; + LLNotifications::instance().add(*xml_alert); } ///////////////////////////////////////////////////////////////////////////// @@ -638,16 +639,17 @@ void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& name void LLPanelRegionGeneralInfo::onClickKickAll(void* userdata) { llinfos << "LLPanelRegionGeneralInfo::onClickKickAll" << llendl; - gViewerWindow->alertXml("KickUsersFromRegion", onKickAllCommit, userdata); + LLNotifications::instance().add("KickUsersFromRegion", + LLSD(), + LLSD(), + boost::bind(&LLPanelRegionGeneralInfo::onKickAllCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); } -// static -void LLPanelRegionGeneralInfo::onKickAllCommit(S32 option, void* userdata) +bool LLPanelRegionGeneralInfo::onKickAllCommit(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { - LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata; - if(!self) return; strings_t strings; // [0] = our agent id std::string buffer; @@ -656,26 +658,29 @@ void LLPanelRegionGeneralInfo::onKickAllCommit(S32 option, void* userdata) LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); // historical message name - self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeallusers", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "teleporthomeallusers", invoice, strings); } + return false; } // static void LLPanelRegionGeneralInfo::onClickMessage(void* userdata) { llinfos << "LLPanelRegionGeneralInfo::onClickMessage" << llendl; - gViewerWindow->alertXmlEditText("MessageRegion", LLStringUtil::format_map_t(), - NULL, NULL, - onMessageCommit, userdata); + LLNotifications::instance().add("MessageRegion", + LLSD(), + LLSD(), + boost::bind(&LLPanelRegionGeneralInfo::onMessageCommit, (LLPanelRegionGeneralInfo*)userdata, _1, _2)); } // static -void LLPanelRegionGeneralInfo::onMessageCommit(S32 option, const std::string& text, void* userdata) +bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const LLSD& response) { - if(option != 0) return; - if(text.empty()) return; - LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata; - if(!self) return; + if(LLNotification::getSelectedOption(notification, response) != 0) return false; + + std::string text = response["message"].asString(); + if (text.empty()) return false; + llinfos << "Message to everyone: " << text << llendl; strings_t strings; // [0] grid_x, unused here @@ -693,7 +698,8 @@ void LLPanelRegionGeneralInfo::onMessageCommit(S32 option, const std::string& te strings.push_back(strings_t::value_type(name)); strings.push_back(strings_t::value_type(text)); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "simulatormessage", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "simulatormessage", invoice, strings); + return false; } // static @@ -780,7 +786,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() LLViewerRegion* region = gAgent.getRegion(); if (region && access != region->getSimAccess() ) { - gViewerWindow->alertXml("RegionMaturityChange"); + LLNotifications::instance().add("RegionMaturityChange"); } } @@ -881,48 +887,56 @@ void LLPanelRegionDebugInfo::onClickReturn(void* data) LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data; if (panelp->mTargetAvatar.isNull()) return; - LLStringUtil::format_map_t args; - args["[USER_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); - gViewerWindow->alertXml("EstateObjectReturn", args, callbackReturn, data); + LLSD args; + args["USER_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + LLSD payload; + payload["avatar_id"] = panelp->mTargetAvatar; + + U32 flags = SWD_ALWAYS_RETURN_OBJECTS; + + if (panelp->childGetValue("return_scripts").asBoolean()) + { + flags |= SWD_SCRIPTED_ONLY; + } + + if (panelp->childGetValue("return_other_land").asBoolean()) + { + flags |= SWD_OTHERS_LAND_ONLY; + } + payload["flags"] = int(flags); + payload["return_estate_wide"] = panelp->childGetValue("return_estate_wide").asBoolean(); + LLNotifications::instance().add("EstateObjectReturn", args, payload, + boost::bind(&LLPanelRegionDebugInfo::callbackReturn, panelp, _1, _2)); } -// static -void LLPanelRegionDebugInfo::callbackReturn( S32 option, void* userdata ) +bool LLPanelRegionDebugInfo::callbackReturn(const LLSD& notification, const LLSD& response) { - if (option != 0) return; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) userdata; - if (!self->mTargetAvatar.isNull()) + LLUUID target_avatar = notification["payload"]["avatar_id"].asUUID(); + if (!target_avatar.isNull()) { - U32 flags = SWD_ALWAYS_RETURN_OBJECTS; - - if (self->childGetValue("return_scripts").asBoolean()) - { - flags |= SWD_SCRIPTED_ONLY; - } - - if (self->childGetValue("return_other_land").asBoolean()) - { - flags |= SWD_OTHERS_LAND_ONLY; - } - - if (self->childGetValue("return_estate_wide").asBoolean()) + U32 flags = notification["payload"]["flags"].asInteger(); + bool return_estate_wide = notification["payload"]["return_estate_wide"]; + if (return_estate_wide) { // send as estate message - routed by spaceserver to all regions in estate strings_t strings; strings.push_back(llformat("%d", flags)); - strings.push_back(self->mTargetAvatar.asString()); + strings.push_back(target_avatar.asString()); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "estateobjectreturn", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "estateobjectreturn", invoice, strings); } else { // send to this simulator only - send_sim_wide_deletes(self->mTargetAvatar, flags); - } + send_sim_wide_deletes(target_avatar, flags); + } } + return false; } @@ -953,19 +967,20 @@ void LLPanelRegionDebugInfo::onClickTopScripts(void* data) // static void LLPanelRegionDebugInfo::onClickRestart(void* data) { - gViewerWindow->alertXml("ConfirmRestart", callbackRestart, data); + LLNotifications::instance().add("ConfirmRestart", LLSD(), LLSD(), + boost::bind(&LLPanelRegionDebugInfo::callbackRestart, (LLPanelRegionDebugInfo*)data, _1, _2)); } -// static -void LLPanelRegionDebugInfo::callbackRestart(S32 option, void* data) +bool LLPanelRegionDebugInfo::callbackRestart(const LLSD& notification, const LLSD& response) { - if (option != 0) return; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data; strings_t strings; strings.push_back("120"); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); + return false; } // static @@ -1123,21 +1138,21 @@ BOOL LLPanelRegionTextureInfo::validateTextureSizes() if (components != 3) { - LLStringUtil::format_map_t args; - args["[TEXTURE_NUM]"] = llformat("%d",i+1); - args["[TEXTURE_BIT_DEPTH]"] = llformat("%d",components * 8); - gViewerWindow->alertXml("InvalidTerrainBitDepth", args); + LLSD args; + args["TEXTURE_NUM"] = i+1; + args["TEXTURE_BIT_DEPTH"] = llformat("%d",components * 8); + LLNotifications::instance().add("InvalidTerrainBitDepth", args); return FALSE; } if (width > 512 || height > 512) { - LLStringUtil::format_map_t args; - args["[TEXTURE_NUM]"] = llformat("%d",i+1); - args["[TEXTURE_SIZE_X]"] = llformat("%d",width); - args["[TEXTURE_SIZE_Y]"] = llformat("%d",height); - gViewerWindow->alertXml("InvalidTerrainSize", args); + LLSD args; + args["TEXTURE_NUM"] = i+1; + args["TEXTURE_SIZE_X"] = width; + args["TEXTURE_SIZE_Y"] = height; + LLNotifications::instance().add("InvalidTerrainSize", args); return FALSE; } @@ -1334,26 +1349,27 @@ void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); - gViewerWindow->alertXml("RawUploadStarted"); + LLNotifications::instance().add("RawUploadStarted"); } // static void LLPanelRegionTerrainInfo::onClickBakeTerrain(void* data) { - gViewerWindow->alertXml("ConfirmBakeTerrain", - callbackBakeTerrain, data); + LLNotifications::instance().add( + LLNotification::Params("ConfirmBakeTerrain") + .functor(boost::bind(&LLPanelRegionTerrainInfo::callbackBakeTerrain, (LLPanelRegionTerrainInfo*)data, _1, _2))); } -// static -void LLPanelRegionTerrainInfo::callbackBakeTerrain(S32 option, void* data) +bool LLPanelRegionTerrainInfo::callbackBakeTerrain(const LLSD& notification, const LLSD& response) { - if (option != 0) return; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; strings_t strings; strings.push_back("bake"); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + return false; } ///////////////////////////////////////////////////////////////////////////// @@ -1440,9 +1456,9 @@ void LLPanelEstateInfo::onClickAddAllowedAgent(void* user_data) { //args - LLStringUtil::format_map_t args; - args["[MAX_AGENTS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - gViewerWindow->alertXml("MaxAllowedAgentOnRegion", args); + LLSD args; + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAllowedAgentOnRegion", args); return; } accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd"); @@ -1462,35 +1478,36 @@ void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data) if (!list) return; if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) { - LLStringUtil::format_map_t args; - args["[MAX_GROUPS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - gViewerWindow->alertXml("MaxAllowedGroupsOnRegion", args); + LLSD args; + args["MAX_GROUPS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAllowedGroupsOnRegion", args); return; } + + LLNotification::Params params("ChangeLindenAccess"); + params.functor(boost::bind(&LLPanelEstateInfo::addAllowedGroup, self, _1, _2)); if (isLindenEstate()) { - gViewerWindow->alertXml("ChangeLindenAccess", addAllowedGroup, user_data); + LLNotifications::instance().add(params); } else { - addAllowedGroup(0, user_data); + LLNotifications::instance().forceResponse(params, 0); } } -// static -void LLPanelEstateInfo::addAllowedGroup(S32 option, void* user_data) +bool LLPanelEstateInfo::addAllowedGroup(const LLSD& notification, const LLSD& response) { - if (option != 0) return; + S32 option = LLNotification::getSelectedOption(notification, response); + if (option != 0) return false; - LLPanelEstateInfo* panelp = (LLPanelEstateInfo*)user_data; - - LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); + LLFloater* parent_floater = gFloaterView->getParentFloater(this); LLFloaterGroupPicker* widget; widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); if (widget) { - widget->setSelectCallback(addAllowedGroup2, user_data); + widget->setSelectCallback(addAllowedGroup2, NULL); if (parent_floater) { LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); @@ -1498,6 +1515,8 @@ void LLPanelEstateInfo::addAllowedGroup(S32 option, void* user_data) parent_floater->addDependentFloater(widget); } } + + return false; } // static @@ -1514,9 +1533,9 @@ void LLPanelEstateInfo::onClickAddBannedAgent(void* user_data) if (!list) return; if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) { - LLStringUtil::format_map_t args; - args["[MAX_BANNED]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - gViewerWindow->alertXml("MaxBannedAgentsOnRegion", args); + LLSD args; + args["MAX_BANNED"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxBannedAgentsOnRegion", args); return; } accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd"); @@ -1536,9 +1555,9 @@ void LLPanelEstateInfo::onClickAddEstateManager(void* user_data) if (!list) return; if (list->getItemCount() >= ESTATE_MAX_MANAGERS) { // Tell user they can't add more managers - LLStringUtil::format_map_t args; - args["[MAX_MANAGER]"] = llformat("%d",ESTATE_MAX_MANAGERS); - gViewerWindow->alertXml("MaxManagersOnRegion", args); + LLSD args; + args["MAX_MANAGER"] = llformat("%d",ESTATE_MAX_MANAGERS); + LLNotifications::instance().add("MaxManagersOnRegion", args); } else { // Go pick managers to add @@ -1558,7 +1577,6 @@ void LLPanelEstateInfo::onClickRemoveEstateManager(void* user_data) struct LLKickFromEstateInfo { LLPanelEstateInfo *mEstatePanelp; - std::string mDialogName; LLUUID mAgentID; }; @@ -1590,45 +1608,42 @@ void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, //keep track of what user they want to kick and other misc info LLKickFromEstateInfo *kick_info = new LLKickFromEstateInfo(); kick_info->mEstatePanelp = self; - kick_info->mDialogName = "EstateKickUser"; kick_info->mAgentID = ids[0]; //Bring up a confirmation dialog - LLStringUtil::format_map_t args; - args["[EVIL_USER]"] = names[0]; - gViewerWindow->alertXml(kick_info->mDialogName, args, LLPanelEstateInfo::kickUserConfirm, (void*)kick_info); + LLSD args; + args["EVIL_USER"] = names[0]; + LLSD payload; + payload["agent_id"] = ids[0]; + LLNotifications::instance().add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, self, _1, _2)); } -void LLPanelEstateInfo::kickUserConfirm(S32 option, void* userdata) +bool LLPanelEstateInfo::kickUserConfirm(const LLSD& notification, const LLSD& response) { - //extract the callback parameter - LLKickFromEstateInfo *kick_info = (LLKickFromEstateInfo*) userdata; - if (!kick_info) return; - - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - strings_t strings; - std::string buffer; - + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: - //Kick User - kick_info->mAgentID.toString(buffer); - strings.push_back(buffer); + { + //Kick User + strings_t strings; + strings.push_back(notification["payload"]["agent_id"].asString()); - kick_info->mEstatePanelp->sendEstateOwnerMessage(gMessageSystem, "kickestate", invoice, strings); - break; + sendEstateOwnerMessage(gMessageSystem, "kickestate", LLFloaterRegionInfo::getLastInvoice(), strings); + break; + } default: break; } - - delete kick_info; - kick_info = NULL; + return false; } //--------------------------------------------------------------------------- // Core Add/Remove estate access methods +// TODO: INTERNATIONAL: don't build message text here; +// instead, create multiple translatable messages and choose +// one based on the status. //--------------------------------------------------------------------------- std::string all_estates_text() { @@ -1669,6 +1684,33 @@ bool LLPanelEstateInfo::isLindenEstate() typedef std::vector<LLUUID> AgentOrGroupIDsVector; struct LLEstateAccessChangeInfo { + LLEstateAccessChangeInfo(const LLSD& sd) + { + mDialogName = sd["dialog_name"].asString(); + mOperationFlag = (U32)sd["operation"].asInteger(); + LLSD::array_const_iterator end_it = sd["allowed_ids"].endArray(); + for (LLSD::array_const_iterator id_it = sd["allowed_ids"].beginArray(); + id_it != end_it; + ++id_it) + { + mAgentOrGroupIDs.push_back(id_it->asUUID()); + } + } + + const LLSD asLLSD() const + { + LLSD sd; + sd["name"] = mDialogName; + sd["operation"] = (S32)mOperationFlag; + for (AgentOrGroupIDsVector::const_iterator it = mAgentOrGroupIDs.begin(); + it != mAgentOrGroupIDs.end(); + ++it) + { + sd["allowed_ids"].append(*it); + } + return sd; + } + U32 mOperationFlag; // ESTATE_ACCESS_BANNED_AGENT_ADD, _REMOVE, etc. std::string mDialogName; AgentOrGroupIDsVector mAgentOrGroupIDs; // List of agent IDs to apply to this change @@ -1678,56 +1720,65 @@ struct LLEstateAccessChangeInfo // static void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data) { - LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo; - change_info->mOperationFlag = ESTATE_ACCESS_ALLOWED_GROUP_ADD; - change_info->mDialogName = "EstateAllowedGroupAdd"; - change_info->mAgentOrGroupIDs.push_back(id); + LLSD payload; + payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; + payload["dialog_name"] = "EstateAllowedGroupAdd"; + payload["allowed_ids"].append(id); + + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + LLNotification::Params params("EstateAllowedGroupAdd"); + params.payload(payload) + .substitutions(args) + .functor(accessCoreConfirm); if (isLindenEstate()) { - accessCoreConfirm(0, (void*)change_info); + LLNotifications::instance().forceResponse(params, 0); } else { - LLStringUtil::format_map_t args; - args["[ALL_ESTATES]"] = all_estates_text(); - gViewerWindow->alertXml(change_info->mDialogName, args, accessCoreConfirm, (void*)change_info); + LLNotifications::instance().add(params); } } // static void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const std::string& dialog_name) { - LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo; - change_info->mOperationFlag = operation_flag; - change_info->mDialogName = dialog_name; + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; // agent id filled in after avatar picker + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessAddCore2); + if (isLindenEstate()) { - gViewerWindow->alertXml("ChangeLindenAccess", accessAddCore2, change_info); + LLNotifications::instance().add(params); } else { // same as clicking "OK" - accessAddCore2(0, change_info); + LLNotifications::instance().forceResponse(params, 0); } } // static -void LLPanelEstateInfo::accessAddCore2(S32 option, void* data) +bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& response) { - LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option != 0) { // abort change - delete change_info; - change_info = NULL; - return; + return false; } + LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); // avatar picker yes multi-select, yes close-on-select LLFloaterAvatarPicker::show(accessAddCore3, (void*)change_info, TRUE, TRUE); + return false; } // static @@ -1756,12 +1807,12 @@ void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, co int currentCount = (list ? list->getItemCount() : 0); if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) { - LLStringUtil::format_map_t args; - args["[NUM_ADDED]"] = llformat("%d",ids.size()); - args["[MAX_AGENTS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["[LIST_TYPE]"] = "Allowed Residents"; - args["[NUM_EXCESS]"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - gViewerWindow->alertXml("MaxAgentOnRegionBatch", args); + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = "Allowed Residents"; + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAgentOnRegionBatch", args); delete change_info; return; } @@ -1772,28 +1823,34 @@ void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, co int currentCount = (list ? list->getItemCount() : 0); if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) { - LLStringUtil::format_map_t args; - args["[NUM_ADDED]"] = llformat("%d",ids.size()); - args["[MAX_AGENTS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["[LIST_TYPE]"] = "Banned Residents"; - args["[NUM_EXCESS]"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - gViewerWindow->alertXml("MaxAgentOnRegionBatch", args); + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = "Banned Residents"; + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotifications::instance().add("MaxAgentOnRegionBatch", args); delete change_info; return; } } + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + + LLNotification::Params params(change_info->mDialogName); + params.substitutions(args) + .payload(change_info->asLLSD()) + .functor(accessCoreConfirm); + if (isLindenEstate()) { // just apply to this estate - accessCoreConfirm(0, (void*)change_info); + LLNotifications::instance().forceResponse(params, 0); } else { // ask if this estate or all estates with this owner - LLStringUtil::format_map_t args; - args["[ALL_ESTATES]"] = all_estates_text(); - gViewerWindow->alertXml(change_info->mDialogName, args, accessCoreConfirm, (void*)change_info); + LLNotifications::instance().add(params); } } @@ -1809,85 +1866,87 @@ void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const std::string& if (list_vector.size() == 0) return; - LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo; - change_info->mOperationFlag = operation_flag; - change_info->mDialogName = dialog_name; + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; for (std::vector<LLScrollListItem*>::const_iterator iter = list_vector.begin(); iter != list_vector.end(); iter++) { LLScrollListItem *item = (*iter); - change_info->mAgentOrGroupIDs.push_back(item->getUUID()); + payload["allowed_ids"].append(item->getUUID()); } + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessRemoveCore2); + if (isLindenEstate()) { // warn on change linden estate - gViewerWindow->alertXml("ChangeLindenAccess", - accessRemoveCore2, - (void*)change_info); + LLNotifications::instance().add(params); } else { // just proceed, as if clicking OK - accessRemoveCore2(0, (void*)change_info); + LLNotifications::instance().forceResponse(params, 0); } } // static -void LLPanelEstateInfo::accessRemoveCore2(S32 option, void* data) +bool LLPanelEstateInfo::accessRemoveCore2(const LLSD& notification, const LLSD& response) { - LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option != 0) { // abort - delete change_info; - change_info = NULL; - return; + return false; } // If Linden estate, can only apply to "this" estate, not all estates // owned by NULL. if (isLindenEstate()) { - accessCoreConfirm(0, (void*)change_info); + accessCoreConfirm(notification, response); } else { - LLStringUtil::format_map_t args; - args["[ALL_ESTATES]"] = all_estates_text(); - gViewerWindow->alertXml(change_info->mDialogName, - args, - accessCoreConfirm, - (void*)change_info); + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + LLNotifications::instance().add(notification["payload"]["dialog_name"], + args, + notification["payload"], + accessCoreConfirm); } + return false; } // Used for both access add and remove operations, depending on the mOperationFlag // passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.) // static -void LLPanelEstateInfo::accessCoreConfirm(S32 option, void* data) +bool LLPanelEstateInfo::accessCoreConfirm(const LLSD& notification, const LLSD& response) { - LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; - const U32 originalFlags = change_info->mOperationFlag; - AgentOrGroupIDsVector& ids = change_info->mAgentOrGroupIDs; + S32 option = LLNotification::getSelectedOption(notification, response); + const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); LLViewerRegion* region = gAgent.getRegion(); - for (AgentOrGroupIDsVector::const_iterator iter = ids.begin(); - iter != ids.end(); + LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray(); + + for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray(); + iter != end_it; iter++) { U32 flags = originalFlags; - if (iter + 1 != ids.end()) + if (iter + 1 != end_it) flags |= ESTATE_ACCESS_NO_REPLY; - const LLUUID id = (*iter); - if ((change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD) + const LLUUID id = iter->asUUID(); + if (((U32)notification["payload"]["operation"].asInteger() & ESTATE_ACCESS_BANNED_AGENT_ADD) && region && (region->getOwner() == id)) { - gViewerWindow->alertXml("OwnerCanNotBeDenied"); + LLNotifications::instance().add("OwnerCanNotBeDenied"); break; } switch(option) @@ -1919,8 +1978,7 @@ void LLPanelEstateInfo::accessCoreConfirm(S32 option, void* data) break; } } - delete change_info; - change_info = NULL; + return false; } // key = "estateaccessdelta" @@ -2146,34 +2204,34 @@ BOOL LLPanelEstateInfo::sendUpdate() { llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl; + LLNotification::Params params("ChangeLindenEstate"); + params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); + if (getEstateID() <= ESTATE_LAST_LINDEN) { // trying to change reserved estate, warn - gViewerWindow->alertXml("ChangeLindenEstate", - callbackChangeLindenEstate, - this); + LLNotifications::instance().add(params); } else { // for normal estates, just make the change - callbackChangeLindenEstate(0, this); + LLNotifications::instance().forceResponse(params, 0); } return TRUE; } -// static -void LLPanelEstateInfo::callbackChangeLindenEstate(S32 option, void* data) +bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, const LLSD& response) { - LLPanelEstateInfo* self = (LLPanelEstateInfo*)data; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: // send the update - if (!self->commitEstateInfoCaps()) + if (!commitEstateInfoCaps()) { // the caps method failed, try the old way LLFloaterRegionInfo::nextInvoice(); - self->commitEstateInfoDataserver(); + commitEstateInfoDataserver(); } // we don't want to do this because we'll get it automatically from the sim // after the spaceserver processes it @@ -2188,6 +2246,7 @@ void LLPanelEstateInfo::callbackChangeLindenEstate(S32 option, void* data) // do nothing break; } + return false; } @@ -2572,18 +2631,15 @@ BOOL LLPanelEstateInfo::checkSunHourSlider(LLUICtrl* child_ctrl) void LLPanelEstateInfo::onClickMessageEstate(void* userdata) { llinfos << "LLPanelEstateInfo::onClickMessageEstate" << llendl; - gViewerWindow->alertXmlEditText("MessageEstate", LLStringUtil::format_map_t(), - NULL, NULL, - onMessageCommit, userdata); + LLNotifications::instance().add("MessageEstate", LLSD(), LLSD(), boost::bind(&LLPanelEstateInfo::onMessageCommit, (LLPanelEstateInfo*)userdata, _1, _2)); } -// static -void LLPanelEstateInfo::onMessageCommit(S32 option, const std::string& text, void* userdata) +bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& response) { - if(option != 0) return; - if(text.empty()) return; - LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata; - if(!self) return; + S32 option = LLNotification::getSelectedOption(notification, response); + std::string text = response["message"].asString(); + if(option != 0) return false; + if(text.empty()) return false; llinfos << "Message to everyone: " << text << llendl; strings_t strings; //integers_t integers; @@ -2592,7 +2648,8 @@ void LLPanelEstateInfo::onMessageCommit(S32 option, const std::string& text, voi strings.push_back(strings_t::value_type(name)); strings.push_back(strings_t::value_type(text)); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); + return false; } LLPanelEstateCovenant::LLPanelEstateCovenant() @@ -2695,9 +2752,10 @@ BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop *accept = ACCEPT_YES_COPY_SINGLE; if (item && drop) { - gViewerWindow->alertXml("EstateChangeCovenant", - LLPanelEstateCovenant::confirmChangeCovenantCallback, - item); + LLSD payload; + payload["item_id"] = item->getUUID(); + LLNotifications::instance().add("EstateChangeCovenant", LLSD(), payload, + LLPanelEstateCovenant::confirmChangeCovenantCallback); } break; default: @@ -2709,12 +2767,13 @@ BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop } // static -void LLPanelEstateCovenant::confirmChangeCovenantCallback(S32 option, void* userdata) +bool LLPanelEstateCovenant::confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response) { - LLInventoryItem* item = (LLInventoryItem*)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); + LLInventoryItem* item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); - if (!item || !self) return; + if (!item || !self) return false; switch(option) { @@ -2724,22 +2783,22 @@ void LLPanelEstateCovenant::confirmChangeCovenantCallback(S32 option, void* user default: break; } + return false; } // static void LLPanelEstateCovenant::resetCovenantID(void* userdata) { - gViewerWindow->alertXml("EstateChangeCovenant", - LLPanelEstateCovenant::confirmResetCovenantCallback, - NULL); + LLNotifications::instance().add("EstateChangeCovenant", LLSD(), LLSD(), confirmResetCovenantCallback); } // static -void LLPanelEstateCovenant::confirmResetCovenantCallback(S32 option, void* userdata) +bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notification, const LLSD& response) { LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); - if (!self) return; + if (!self) return false; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: @@ -2748,6 +2807,7 @@ void LLPanelEstateCovenant::confirmResetCovenantCallback(S32 option, void* userd default: break; } + return false; } void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) @@ -2808,7 +2868,7 @@ void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, if( !panelp->mEditor->importBuffer( buffer, file_length+1 ) ) { llwarns << "Problem importing estate covenant." << llendl; - gViewerWindow->alertXml("ProblemImportingEstateCovenant"); + LLNotifications::instance().add("ProblemImportingEstateCovenant"); } else { @@ -2829,15 +2889,15 @@ void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { - gViewerWindow->alertXml("MissingNotecardAssetID"); + LLNotifications::instance().add("MissingNotecardAssetID"); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { - gViewerWindow->alertXml("NotAllowedToViewNotecard"); + LLNotifications::instance().add("NotAllowedToViewNotecard"); } else { - gViewerWindow->alertXml("UnableToLoadNotecard"); + LLNotifications::instance().add("UnableToLoadNotecardAsset"); } llwarns << "Problem loading notecard: " << status << llendl; diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 8580189a2e..8c14e463ff 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -161,9 +161,9 @@ protected: static void onClickKick(void* userdata); static void onKickCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata); static void onClickKickAll(void* userdata); - static void onKickAllCommit(S32 option, void* userdata); + bool onKickAllCommit(const LLSD& notification, const LLSD& response); static void onClickMessage(void* userdata); - static void onMessageCommit(S32 option, const std::string& text, void* userdata); + bool onMessageCommit(const LLSD& notification, const LLSD& response); static void onClickManageTelehub(void* data); }; @@ -186,11 +186,11 @@ protected: static void onClickChooseAvatar(void*); static void callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data); static void onClickReturn(void *); - static void callbackReturn(S32 option, void*); + bool callbackReturn(const LLSD& notification, const LLSD& response); static void onClickTopColliders(void*); static void onClickTopScripts(void*); static void onClickRestart(void* data); - static void callbackRestart(S32 option, void* data); + bool callbackRestart(const LLSD& notification, const LLSD& response); static void onClickCancelRestart(void* data); private: @@ -240,7 +240,7 @@ protected: static void onClickDownloadRaw(void*); static void onClickUploadRaw(void*); static void onClickBakeTerrain(void*); - static void callbackBakeTerrain(S32 option, void* data); + bool callbackBakeTerrain(const LLSD& notification, const LLSD& response); }; ///////////////////////////////////////////////////////////////////////////// @@ -269,27 +269,27 @@ public: static void onClickKickUser(void* userdata); // Group picker callback is different, can't use core methods below - static void addAllowedGroup(S32 option, void* data); + bool addAllowedGroup(const LLSD& notification, const LLSD& response); static void addAllowedGroup2(LLUUID id, void* data); // Core methods for all above add/remove button clicks static void accessAddCore(U32 operation_flag, const std::string& dialog_name); - static void accessAddCore2(S32 option, void* data); + static bool accessAddCore2(const LLSD& notification, const LLSD& response); static void accessAddCore3(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data); static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name); - static void accessRemoveCore2(S32 option, void* data); + static bool accessRemoveCore2(const LLSD& notification, const LLSD& response); // used for both add and remove operations - static void accessCoreConfirm(S32 option, void* data); - static void kickUserConfirm(S32 option, void* userdata); + static bool accessCoreConfirm(const LLSD& notification, const LLSD& response); + bool kickUserConfirm(const LLSD& notification, const LLSD& response); // Send the actual EstateOwnerRequest "estateaccessdelta" message static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); static void onKickUserCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata); static void onClickMessageEstate(void* data); - static void onMessageCommit(S32 option, const std::string& text, void* data); + bool onMessageCommit(const LLSD& notification, const LLSD& response); LLPanelEstateInfo(); ~LLPanelEstateInfo() {} @@ -344,7 +344,7 @@ public: protected: virtual BOOL sendUpdate(); // confirmation dialog callback - static void callbackChangeLindenEstate(S32 opt, void* data); + bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response); void commitEstateInfoDataserver(); bool commitEstateInfoCaps(); @@ -377,9 +377,9 @@ public: BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); - static void confirmChangeCovenantCallback(S32 option, void* userdata); + static bool confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response); static void resetCovenantID(void* userdata); - static void confirmResetCovenantCallback(S32 option, void* userdata); + static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response); void sendChangeCovenantID(const LLUUID &asset_id); void loadInvItem(LLInventoryItem *itemp); static void onLoadComplete(LLVFS *vfs, diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index da435c9452..e87ffeb258 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -207,10 +207,10 @@ void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg) { if ( gEmailToEstateOwner ) { - gViewerWindow->alertXml("HelpReportAbuseEmailEO"); + LLNotifications::instance().add("HelpReportAbuseEmailEO"); } else - gViewerWindow->alertXml("HelpReportAbuseEmailLL"); + LLNotifications::instance().add("HelpReportAbuseEmailLL"); }; } @@ -406,7 +406,7 @@ void LLFloaterReporter::onClickSend(void *userdata) category_value == IP_CONTENT_REMOVAL || category_value == IP_PERMISSONS_EXPLOIT) { - gViewerWindow->alertXml("HelpReportAbuseContainsCopyright"); + LLNotifications::instance().add("HelpReportAbuseContainsCopyright"); self->mCopyrightWarningSeen = TRUE; return; } @@ -415,7 +415,7 @@ void LLFloaterReporter::onClickSend(void *userdata) { // IP_CONTENT_REMOVAL *always* shows the dialog - // ergo you can never send that abuse report type. - gViewerWindow->alertXml("HelpReportAbuseContainsCopyright"); + LLNotifications::instance().add("HelpReportAbuseContainsCopyright"); return; } } @@ -524,7 +524,7 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) if (report_type == BUG_REPORT) { - gViewerWindow->alertXml("HelpReportBug"); + LLNotifications::instance().add("HelpReportBug"); } else { @@ -610,11 +610,11 @@ bool LLFloaterReporter::validateReport() { if ( mReportType != BUG_REPORT ) { - gViewerWindow->alertXml("HelpReportAbuseSelectCategory"); + LLNotifications::instance().add("HelpReportAbuseSelectCategory"); } else { - gViewerWindow->alertXml("HelpReportBugSelectCategory"); + LLNotifications::instance().add("HelpReportBugSelectCategory"); } return false; } @@ -623,13 +623,13 @@ bool LLFloaterReporter::validateReport() { if ( childGetText("abuser_name_edit").empty() ) { - gViewerWindow->alertXml("HelpReportAbuseAbuserNameEmpty"); + LLNotifications::instance().add("HelpReportAbuseAbuserNameEmpty"); return false; }; if ( childGetText("abuse_location_edit").empty() ) { - gViewerWindow->alertXml("HelpReportAbuseAbuserLocationEmpty"); + LLNotifications::instance().add("HelpReportAbuseAbuserLocationEmpty"); return false; }; }; @@ -638,11 +638,11 @@ bool LLFloaterReporter::validateReport() { if ( mReportType != BUG_REPORT ) { - gViewerWindow->alertXml("HelpReportAbuseSummaryEmpty"); + LLNotifications::instance().add("HelpReportAbuseSummaryEmpty"); } else { - gViewerWindow->alertXml("HelpReportBugSummaryEmpty"); + LLNotifications::instance().add("HelpReportBugSummaryEmpty"); } return false; }; @@ -651,11 +651,11 @@ bool LLFloaterReporter::validateReport() { if ( mReportType != BUG_REPORT ) { - gViewerWindow->alertXml("HelpReportAbuseDetailsEmpty"); + LLNotifications::instance().add("HelpReportAbuseDetailsEmpty"); } else { - gViewerWindow->alertXml("HelpReportBugDetailsEmpty"); + LLNotifications::instance().add("HelpReportBugDetailsEmpty"); } return false; }; @@ -951,13 +951,12 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, if(result < 0) { - LLStringUtil::format_map_t args; - std::string reason = std::string(LLAssetStorage::getErrorString(result)); - args["[REASON]"] = reason; - gViewerWindow->alertXml("ErrorUploadingReportScreenshot", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotifications::instance().add("ErrorUploadingReportScreenshot", args); std::string err_msg("There was a problem uploading a report screenshot"); - err_msg += " due to the following reason: " + reason; + err_msg += " due to the following reason: " + args["REASON"].asString(); llwarns << err_msg << llendl; return; } diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 749ccbe7fa..1e1d1f6fd2 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -79,9 +79,9 @@ private: static void doSelectAgent(void *userdata); static void doCancel(void *userdata); static void doSellLand(void *userdata); - static void onConfirmSale(S32 option, void *userdata); + bool onConfirmSale(const LLSD& notification, const LLSD& response); static void doShowObjects(void *userdata); - static void callbackHighlightTransferable(S32 option, void* userdata); + static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response); static void callbackAvatarPick(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data); @@ -443,15 +443,16 @@ void LLFloaterSellLandUI::doShowObjects(void *userdata) send_parcel_select_objects(parcel->getLocalID(), RT_SELL); - LLNotifyBox::showXml("TransferObjectsHighlighted", - callbackHighlightTransferable, - userdata); + LLNotifications::instance().add("TransferObjectsHighlighted", + LLSD(), LLSD(), + &LLFloaterSellLandUI::callbackHighlightTransferable); } // static -void LLFloaterSellLandUI::callbackHighlightTransferable(S32 option, void* userdata) +bool LLFloaterSellLandUI::callbackHighlightTransferable(const LLSD& notification, const LLSD& data) { LLSelectMgr::getInstance()->unhighlightAll(); + return false; } // static @@ -462,83 +463,89 @@ void LLFloaterSellLandUI::doSellLand(void *userdata) LLParcel* parcel = self->mParcelSelection->getParcel(); // Do a confirmation - if (!parcel->getForSale()) + S32 sale_price = self->childGetValue("price"); + S32 area = parcel->getArea(); + std::string authorizedBuyerName = "Anyone"; + bool sell_to_anyone = true; + if ("user" == self->childGetValue("sell_to").asString()) { - S32 sale_price = self->childGetValue("price"); - S32 area = parcel->getArea(); - std::string authorizedBuyerName = "Anyone"; - bool sell_to_anyone = true; - if ("user" == self->childGetValue("sell_to").asString()) - { - authorizedBuyerName = self->childGetText("sell_to_agent"); - sell_to_anyone = false; - } + authorizedBuyerName = self->childGetText("sell_to_agent"); + sell_to_anyone = false; + } - // must sell to someone if indicating sale to anyone - if ((sale_price == 0) && sell_to_anyone) - { - gViewerWindow->alertXml("SalePriceRestriction"); - return; - } + // must sell to someone if indicating sale to anyone + if (!parcel->getForSale() + && (sale_price == 0) + && sell_to_anyone) + { + LLNotifications::instance().add("SalePriceRestriction"); + return; + } - LLStringUtil::format_map_t args; - args["[LAND_SIZE]"] = llformat("%d",area); - args["[SALE_PRICE]"] = llformat("%d",sale_price); - args["[NAME]"] = authorizedBuyerName; + LLSD args; + args["LAND_SIZE"] = llformat("%d",area); + args["SALE_PRICE"] = llformat("%d",sale_price); + args["NAME"] = authorizedBuyerName; - if (sell_to_anyone) - { - gViewerWindow->alertXml("ConfirmLandSaleToAnyoneChange", args, onConfirmSale, self); - } - else - { - gViewerWindow->alertXml("ConfirmLandSaleChange", args, onConfirmSale, self); - } + LLNotification::Params params("ConfirmLandSaleChange"); + params.substitutions(args) + .functor(boost::bind(&LLFloaterSellLandUI::onConfirmSale, self, _1, _2)); + + if (sell_to_anyone) + { + params.name("ConfirmLandSaleToAnyoneChange"); + } + + if (parcel->getForSale()) + { + // parcel already for sale, so ignore this question + LLNotifications::instance().forceResponse(params, -1); } else { - onConfirmSale(-1, self); + // ask away + LLNotifications::instance().add(params); } + } -// static -void LLFloaterSellLandUI::onConfirmSale(S32 option, void *userdata) +bool LLFloaterSellLandUI::onConfirmSale(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option != 0) { - return; + return false; } - LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata; - S32 sale_price = self->childGetValue("price"); + S32 sale_price = childGetValue("price"); // Valid extracted data if (sale_price < 0) { // TomY TODO: Throw an error - return; + return false; } - LLParcel* parcel = self->mParcelSelection->getParcel(); - if (!parcel) return; + LLParcel* parcel = mParcelSelection->getParcel(); + if (!parcel) return false; // can_agent_modify_parcel deprecated by GROUPS // if (!can_agent_modify_parcel(parcel)) // { -// self->close(); +// close(); // return; // } parcel->setParcelFlag(PF_FOR_SALE, TRUE); parcel->setSalePrice(sale_price); bool sell_with_objects = false; - if ("yes" == self->childGetValue("sell_objects").asString()) + if ("yes" == childGetValue("sell_objects").asString()) { sell_with_objects = true; } parcel->setSellWithObjects(sell_with_objects); - if ("user" == self->childGetValue("sell_to").asString()) + if ("user" == childGetValue("sell_to").asString()) { - parcel->setAuthorizedBuyerID(self->mAuthorizedBuyer); + parcel->setAuthorizedBuyerID(mAuthorizedBuyer); } else { @@ -548,5 +555,6 @@ void LLFloaterSellLandUI::onConfirmSale(S32 option, void *userdata) // Send update to server LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - self->close(); + close(); + return false; } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index dcfb1e9442..207b2ea655 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -966,7 +966,7 @@ void LLSnapshotLivePreview::saveTexture() } else { - gViewerWindow->alertXml("ErrorEncodingSnapshot"); + LLNotifications::instance().add("ErrorEncodingSnapshot"); llwarns << "Error encoding snapshot" << llendl; } diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index eea6b40cba..3b79f58db7 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -353,17 +353,19 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) } //static -void LLFloaterTopObjects::callbackReturnAll(S32 option, void* userdata) +bool LLFloaterTopObjects::callbackReturnAll(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { sInstance->doToObjects(ACTION_RETURN, true); } + return false; } void LLFloaterTopObjects::onReturnAll(void* data) { - gViewerWindow->alertXml("ReturnAllTopObjects", callbackReturnAll, NULL); + LLNotifications::instance().add("ReturnAllTopObjects", LLSD(), LLSD(), &callbackReturnAll); } @@ -374,17 +376,19 @@ void LLFloaterTopObjects::onReturnSelected(void* data) //static -void LLFloaterTopObjects::callbackDisableAll(S32 option, void* userdata) +bool LLFloaterTopObjects::callbackDisableAll(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { sInstance->doToObjects(ACTION_DISABLE, true); } + return false; } void LLFloaterTopObjects::onDisableAll(void* data) { - gViewerWindow->alertXml("DisableAllTopObjects", callbackDisableAll, NULL); + LLNotifications::instance().add("DisableAllTopObjects", LLSD(), LLSD(), callbackDisableAll); } void LLFloaterTopObjects::onDisableSelected(void* data) diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h index 5b23e737d7..a6f07a6a34 100644 --- a/indra/newview/llfloatertopobjects.h +++ b/indra/newview/llfloatertopobjects.h @@ -72,8 +72,8 @@ private: static void onDisableAll(void* data); static void onDisableSelected(void* data); - static void callbackReturnAll(S32 option, void* userdata); - static void callbackDisableAll(S32 option, void* userdata); + static bool callbackReturnAll(const LLSD& notification, const LLSD& response); + static bool callbackDisableAll(const LLSD& notification, const LLSD& response); static void onGetByOwnerName(LLUICtrl* ctrl, void* data); static void onGetByObjectName(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index ad592f909e..bd09bf9ef6 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -257,7 +257,7 @@ void LLFloaterTOS::onCancel( void* userdata ) { LLFloaterTOS* self = (LLFloaterTOS*) userdata; llinfos << "User disagrees with TOS." << llendl; - gViewerWindow->alertXml("MustAgreeToLogIn", login_alert_done); + LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS self->close(); // destroys this object diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 69916f80ea..3efd6eed61 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -262,32 +262,30 @@ void LLFloaterURLEntry::onBtnCancel( void* userdata ) //----------------------------------------------------------------------------- void LLFloaterURLEntry::onBtnClear( void* userdata ) { - gViewerWindow->alertXml( "ConfirmClearMediaUrlList", callback_clear_url_list, userdata ); + LLNotifications::instance().add( "ConfirmClearMediaUrlList", LLSD(), LLSD(), + boost::bind(&LLFloaterURLEntry::callback_clear_url_list, (LLFloaterURLEntry*)userdata, _1, _2) ); } -void LLFloaterURLEntry::callback_clear_url_list(S32 option, void* userdata) +bool LLFloaterURLEntry::callback_clear_url_list(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if ( option == 0 ) // YES { - LLFloaterURLEntry *self =(LLFloaterURLEntry *)userdata; - - if ( self ) + // clear saved list + LLCtrlListInterface* url_list = childGetListInterface("media_entry"); + if ( url_list ) { - // clear saved list - LLCtrlListInterface* url_list = self->childGetListInterface("media_entry"); - if ( url_list ) - { - url_list->operateOnAll( LLCtrlListInterface::OP_DELETE ); - } + url_list->operateOnAll( LLCtrlListInterface::OP_DELETE ); + } - // clear current contents of combo box - self->mMediaURLEdit->clear(); + // clear current contents of combo box + mMediaURLEdit->clear(); - // clear stored version of list - LLURLHistory::clear("parcel"); + // clear stored version of list + LLURLHistory::clear("parcel"); - // cleared the list so disable Clear button - self->childSetEnabled( "clear_btn", false ); - } + // cleared the list so disable Clear button + childSetEnabled( "clear_btn", false ); } + return false; } diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 53e77880f5..f85106dffe 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -63,7 +63,7 @@ private: static void onBtnOK(void*); static void onBtnCancel(void*); static void onBtnClear(void*); - static void callback_clear_url_list(S32 option, void* userdata); + bool callback_clear_url_list(const LLSD& notification, const LLSD& response); }; #endif // LL_LLFLOATERURLENTRY_H diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp index 4705b2f5ba..1a8beb7a58 100644 --- a/indra/newview/llfloaterwater.cpp +++ b/indra/newview/llfloaterwater.cpp @@ -176,15 +176,7 @@ void LLFloaterWater::onClickHelp(void* data) LLFloaterWater* self = LLFloaterWater::instance(); const std::string* xml_alert = (std::string*)data; - LLAlertDialog* dialogp = gViewerWindow->alertXml(*xml_alert); - if (dialogp) - { - LLFloater* root_floater = gFloaterView->getParentFloater(self); - if (root_floater) - { - root_floater->addDependentFloater(dialogp); - } - } + LLNotifications::instance().add(self->contextualNotification(*xml_alert)); } void LLFloaterWater::initHelpBtn(const std::string& name, const std::string& xml_alert) @@ -192,11 +184,14 @@ void LLFloaterWater::initHelpBtn(const std::string& name, const std::string& xml childSetAction(name, onClickHelp, new std::string(xml_alert)); } -void LLFloaterWater::newPromptCallback(S32 option, const std::string& text, void* userData) +bool LLFloaterWater::newPromptCallback(const LLSD& notification, const LLSD& response) { + std::string text = response["message"].asString(); + S32 option = LLNotification::getSelectedOption(notification, response); + if(text == "") { - return; + return false; } if(option == 0) { @@ -224,9 +219,10 @@ void LLFloaterWater::newPromptCallback(S32 option, const std::string& text, void } else { - gViewerWindow->alertXml("ExistsWaterPresetAlert"); + LLNotifications::instance().add("ExistsWaterPresetAlert"); } } + return false; } void LLFloaterWater::syncMenu() @@ -596,8 +592,7 @@ void LLFloaterWater::onNormalMapPicked(LLUICtrl* ctrl, void* userData) void LLFloaterWater::onNewPreset(void* userData) { - gViewerWindow->alertXmlEditText("NewWaterPreset", LLStringUtil::format_map_t(), - NULL, NULL, newPromptCallback, NULL); + LLNotifications::instance().add("NewWaterPreset", LLSD(), LLSD(), newPromptCallback); } void LLFloaterWater::onSavePreset(void* userData) @@ -619,15 +614,16 @@ void LLFloaterWater::onSavePreset(void* userData) comboBox->getSelectedItemLabel()); if(sIt != sDefaultPresets.end() && !gSavedSettings.getBOOL("WaterEditPresets")) { - gViewerWindow->alertXml("WLNoEditDefault"); + LLNotifications::instance().add("WLNoEditDefault"); return; } - gViewerWindow->alertXml("WLSavePresetAlert", saveAlertCallback, sWaterMenu); + LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), saveAlertCallback); } -void LLFloaterWater::saveAlertCallback(S32 option, void* userdata) +bool LLFloaterWater::saveAlertCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // if they choose save, do it. Otherwise, don't do anything if(option == 0) { @@ -640,7 +636,7 @@ void LLFloaterWater::saveAlertCallback(S32 option, void* userdata) // comment this back in to save to file param_mgr->savePreset(param_mgr->mCurParams.mName); } - + return false; } void LLFloaterWater::onDeletePreset(void* userData) @@ -652,13 +648,14 @@ void LLFloaterWater::onDeletePreset(void* userData) return; } - LLStringUtil::format_map_t args; - args["[SKY]"] = combo_box->getSelectedValue().asString(); - gViewerWindow->alertXml("WLDeletePresetAlert", args, deleteAlertCallback, sWaterMenu); + LLSD args; + args["SKY"] = combo_box->getSelectedValue().asString(); + LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), deleteAlertCallback); } -void LLFloaterWater::deleteAlertCallback(S32 option, void* userdata) +bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // if they choose delete, do it. Otherwise, don't do anything if(option == 0) { @@ -680,8 +677,8 @@ void LLFloaterWater::deleteAlertCallback(S32 option, void* userdata) std::set<std::string>::iterator sIt = sDefaultPresets.find(name); if(sIt != sDefaultPresets.end()) { - gViewerWindow->alertXml("WaterNoEditDefault"); - return; + LLNotifications::instance().add("WaterNoEditDefault"); + return false; } LLWaterParamManager::instance()->removeParamSet(name, true); @@ -710,6 +707,7 @@ void LLFloaterWater::deleteAlertCallback(S32 option, void* userdata) combo_box->setCurrentByIndex(new_index); } } + return false; } diff --git a/indra/newview/llfloaterwater.h b/indra/newview/llfloaterwater.h index 883b2a35f1..ad361266fe 100644 --- a/indra/newview/llfloaterwater.h +++ b/indra/newview/llfloaterwater.h @@ -63,7 +63,7 @@ public: static void onClickHelp(void* data); void initHelpBtn(const std::string& name, const std::string& xml_alert); - static void newPromptCallback(S32 option, const std::string& text, void* userData); + static bool newPromptCallback(const LLSD& notification, const LLSD& response); /// general purpose callbacks for dealing with color controllers static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); @@ -97,13 +97,13 @@ public: static void onSavePreset(void* userData); /// prompts a user when overwriting a preset - static void saveAlertCallback(S32 option, void* userdata); + static bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// when user hits the save preset button static void onDeletePreset(void* userData); /// prompts a user when overwriting a preset - static void deleteAlertCallback(S32 option, void* userdata); + static bool deleteAlertCallback(const LLSD& notification, const LLSD& response); /// what to do when you change the preset name static void onChangePresetName(LLUICtrl* ctrl, void* userData); diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index 4e27774029..8ae291f24c 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -233,16 +233,8 @@ void LLFloaterWindLight::onClickHelp(void* data) { LLFloaterWindLight* self = LLFloaterWindLight::instance(); - const std::string* xml_alert = (std::string*)data; - LLAlertDialog* dialogp = gViewerWindow->alertXml(*xml_alert); - if (dialogp) - { - LLFloater* root_floater = gFloaterView->getParentFloater(self); - if (root_floater) - { - root_floater->addDependentFloater(dialogp); - } - } + const std::string xml_alert = *(std::string*)data; + LLNotifications::instance().add(self->contextualNotification(xml_alert)); } void LLFloaterWindLight::initHelpBtn(const std::string& name, const std::string& xml_alert) @@ -250,11 +242,14 @@ void LLFloaterWindLight::initHelpBtn(const std::string& name, const std::string& childSetAction(name, onClickHelp, new std::string(xml_alert)); } -void LLFloaterWindLight::newPromptCallback(S32 option, const std::string& text, void* userData) +bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD& response) { + std::string text = response["message"].asString(); + S32 option = LLNotification::getSelectedOption(notification, response); + if(text == "") { - return; + return false; } if(option == 0) { @@ -303,9 +298,10 @@ void LLFloaterWindLight::newPromptCallback(S32 option, const std::string& text, } else { - gViewerWindow->alertXml("ExistsSkyPresetAlert"); + LLNotifications::instance().add("ExistsSkyPresetAlert"); } } + return false; } void LLFloaterWindLight::syncMenu() @@ -784,8 +780,7 @@ void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl, void* userData) void LLFloaterWindLight::onNewPreset(void* userData) { - gViewerWindow->alertXmlEditText("NewSkyPreset", LLStringUtil::format_map_t(), - NULL, NULL, newPromptCallback, NULL); + LLNotifications::instance().add("NewSkyPreset", LLSD(), LLSD(), newPromptCallback); } void LLFloaterWindLight::onSavePreset(void* userData) @@ -805,18 +800,19 @@ void LLFloaterWindLight::onSavePreset(void* userData) comboBox->getSelectedItemLabel()); if(sIt != sDefaultPresets.end() && !gSavedSettings.getBOOL("SkyEditPresets")) { - gViewerWindow->alertXml("WLNoEditDefault"); + LLNotifications::instance().add("WLNoEditDefault"); return; } LLWLParamManager::instance()->mCurParams.mName = comboBox->getSelectedItemLabel(); - gViewerWindow->alertXml("WLSavePresetAlert", saveAlertCallback, sWindLight); + LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), saveAlertCallback); } -void LLFloaterWindLight::saveAlertCallback(S32 option, void* userdata) +bool LLFloaterWindLight::saveAlertCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // if they choose save, do it. Otherwise, don't do anything if(option == 0) { @@ -827,7 +823,7 @@ void LLFloaterWindLight::saveAlertCallback(S32 option, void* userdata) // comment this back in to save to file param_mgr->savePreset(param_mgr->mCurParams.mName); } - + return false; } void LLFloaterWindLight::onDeletePreset(void* userData) @@ -840,17 +836,20 @@ void LLFloaterWindLight::onDeletePreset(void* userData) return; } - LLStringUtil::format_map_t args; - args["[SKY]"] = combo_box->getSelectedValue().asString(); - gViewerWindow->alertXml("WLDeletePresetAlert", args, deleteAlertCallback, sWindLight); + LLSD args; + args["SKY"] = combo_box->getSelectedValue().asString(); + LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), + boost::bind(&LLFloaterWindLight::deleteAlertCallback, sWindLight, _1, _2)); } -void LLFloaterWindLight::deleteAlertCallback(S32 option, void* userdata) +bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); + // if they choose delete, do it. Otherwise, don't do anything if(option == 0) { - LLComboBox* combo_box = sWindLight->getChild<LLComboBox>( + LLComboBox* combo_box = getChild<LLComboBox>( "WLPresetsCombo"); LLFloaterDayCycle* day_cycle = NULL; LLComboBox* key_combo = NULL; @@ -870,8 +869,8 @@ void LLFloaterWindLight::deleteAlertCallback(S32 option, void* userdata) std::set<std::string>::iterator sIt = sDefaultPresets.find(name); if(sIt != sDefaultPresets.end()) { - gViewerWindow->alertXml("WLNoEditDefault"); - return; + LLNotifications::instance().add("WLNoEditDefault"); + return false; } LLWLParamManager::instance()->removeParamSet(name, true); @@ -899,6 +898,7 @@ void LLFloaterWindLight::deleteAlertCallback(S32 option, void* userdata) combo_box->setCurrentByIndex(new_index); } } + return false; } diff --git a/indra/newview/llfloaterwindlight.h b/indra/newview/llfloaterwindlight.h index d9e02b1117..35f8a65cbd 100644 --- a/indra/newview/llfloaterwindlight.h +++ b/indra/newview/llfloaterwindlight.h @@ -63,7 +63,7 @@ public: static void onClickHelp(void* data); void initHelpBtn(const std::string& name, const std::string& xml_alert); - static void newPromptCallback(S32 option, const std::string& text, void* userData); + static bool newPromptCallback(const LLSD& notification, const LLSD& response); /// general purpose callbacks for dealing with color controllers static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); @@ -94,13 +94,13 @@ public: static void onSavePreset(void* userData); /// prompts a user when overwriting a preset - static void saveAlertCallback(S32 option, void* userdata); + static bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// when user hits the save preset button static void onDeletePreset(void* userData); /// prompts a user when overwriting a preset - static void deleteAlertCallback(S32 option, void* userdata); + bool deleteAlertCallback(const LLSD& notification, const LLSD& response); /// what to do when you change the preset name static void onChangePresetName(LLUICtrl* ctrl, void* userData); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 2281f1b598..1c6eb84a8a 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -1303,10 +1303,10 @@ void LLFloaterWorldMap::onCopySLURL(void* data) LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(self->mSLURL)); - LLStringUtil::format_map_t args; - args["[SLURL]"] = self->mSLURL; + LLSD args; + args["SLURL"] = self->mSLURL; - LLAlertDialog::showXml("CopySLURL", args); + LLNotifications::instance().add("CopySLURL", args); } void LLFloaterWorldMap::onCheckEvents(LLUICtrl*, void* data) diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index a25b1daebf..eba295531a 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -952,9 +952,9 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, && gGestureManager.mDeactivateSimilarNames.length() > 0) { // we're done with this set of deactivations - LLStringUtil::format_map_t args; - args["[NAMES]"] = gGestureManager.mDeactivateSimilarNames; - LLNotifyBox::showXml("DeactivatedGesturesTrigger", args); + LLSD args; + args["NAMES"] = gGestureManager.mDeactivateSimilarNames; + LLNotifications::instance().add("DeactivatedGesturesTrigger", args); } } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 631b2caa91..9a8e70242c 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1288,9 +1288,9 @@ void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data) else { // *TODO:translate - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = message; - gViewerWindow->alertXml("UnableToCreateGroup", args); + LLSD args; + args["MESSAGE"] = message; + LLNotifications::instance().add("UnableToCreateGroup", args); } } diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 770c117798..98b0786200 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -306,13 +306,13 @@ void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) if ( 403 == status ) { //403 == no ability - LLNotifyBox::showXml( + LLNotifications::instance().add( "VoiceNotAllowed", channelp->getNotifyArgs()); } else { - LLNotifyBox::showXml( + LLNotifications::instance().add( "VoiceCallGenericError", channelp->getNotifyArgs()); } @@ -348,7 +348,7 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& sess mSessionName(session_name), mIgnoreNextSessionLeave(FALSE) { - mNotifyArgs["[VOICE_CHANNEL_NAME]"] = mSessionName; + mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) { @@ -384,13 +384,13 @@ void LLVoiceChannel::setChannelInfo( { if (mURI.empty()) { - LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs); + LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); llwarns << "Received empty URI for channel " << mSessionName << llendl; deactivate(); } else if (mCredentials.empty()) { - LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs); + LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); llwarns << "Received empty credentials for channel " << mSessionName << llendl; deactivate(); } @@ -433,25 +433,26 @@ void LLVoiceChannel::handleStatusChange(EStatusType type) switch(type) { case STATUS_LOGIN_RETRY: - mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); + //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); + LLNotifications::instance().add("VoiceLoginRetry"); break; case STATUS_LOGGED_IN: - if (!mLoginNotificationHandle.isDead()) - { - LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); - if (notifyp) - { - notifyp->close(); - } - mLoginNotificationHandle.markDead(); - } + //if (!mLoginNotificationHandle.isDead()) + //{ + // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); + // if (notifyp) + // { + // notifyp->close(); + // } + // mLoginNotificationHandle.markDead(); + //} break; case STATUS_LEFT_CHANNEL: if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) { // if forceably removed from channel // update the UI and revert to default channel - LLNotifyBox::showXml("VoiceChannelDisconnected", mNotifyArgs); + LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); deactivate(); } mIgnoreNextSessionLeave = FALSE; @@ -793,9 +794,9 @@ void LLVoiceChannelGroup::handleError(EStatusType status) // notification if (!notify.empty()) { - LLNotifyBox::showXml(notify, mNotifyArgs); + LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); // echo to im window - gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, LLNotifyBox::getTemplateMessage(notify, mNotifyArgs)); + gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); } LLVoiceChannel::handleError(status); @@ -896,7 +897,7 @@ void LLVoiceChannelProximal::handleError(EStatusType status) // notification if (!notify.empty()) { - LLNotifyBox::showXml(notify, mNotifyArgs); + LLNotifications::instance().add(notify, mNotifyArgs); } LLVoiceChannel::handleError(status); @@ -934,12 +935,12 @@ void LLVoiceChannelP2P::handleStatusChange(EStatusType type) if (mState == STATE_RINGING) { // other user declined call - LLNotifyBox::showXml("P2PCallDeclined", mNotifyArgs); + LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); } else { // other user hung up - LLNotifyBox::showXml("VoiceChannelDisconnectedP2P", mNotifyArgs); + LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); } deactivate(); } @@ -957,7 +958,7 @@ void LLVoiceChannelP2P::handleError(EStatusType type) switch(type) { case ERROR_NOT_AVAILABLE: - LLNotifyBox::showXml("P2PCallNoAnswer", mNotifyArgs); + LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); break; default: break; @@ -2213,35 +2214,33 @@ void LLFloaterIMPanel::showSessionStartError( //their own XML file which would be read in by any LLIMPanel //post build function instead of repeating the same info //in the group, adhoc and normal IM xml files. - LLStringUtil::format_map_t args; - args["[REASON]"] = + LLSD args; + args["REASON"] = LLFloaterIM::sErrorStringsMap[error_string]; - args["[RECIPIENT]"] = getTitle(); + args["RECIPIENT"] = getTitle(); + + LLSD payload; + payload["session_id"] = mSessionUUID; - gViewerWindow->alertXml( + LLNotifications::instance().add( "ChatterBoxSessionStartError", args, - onConfirmForceCloseError, - new LLUUID(mSessionUUID)); + payload, + onConfirmForceCloseError); } void LLFloaterIMPanel::showSessionEventError( const std::string& event_string, const std::string& error_string) { - LLStringUtil::format_map_t args; - std::string event; - - event = LLFloaterIM::sEventStringsMap[event_string]; - args["[RECIPIENT]"] = getTitle(); - LLStringUtil::format(event, args); - - - args = LLStringUtil::format_map_t(); - args["[REASON]"] = LLFloaterIM::sErrorStringsMap[error_string]; - args["[EVENT]"] = event; + LLSD args; + args["REASON"] = + LLFloaterIM::sErrorStringsMap[error_string]; + args["EVENT"] = + LLFloaterIM::sEventStringsMap[event_string]; + args["RECIPIENT"] = getTitle(); - gViewerWindow->alertXml( + LLNotifications::instance().add( "ChatterBoxSessionEventError", args); } @@ -2249,16 +2248,19 @@ void LLFloaterIMPanel::showSessionEventError( void LLFloaterIMPanel::showSessionForceClose( const std::string& reason_string) { - LLStringUtil::format_map_t args; + LLSD args; - args["[NAME]"] = getTitle(); - args["[REASON]"] = LLFloaterIM::sForceCloseSessionMap[reason_string]; + args["NAME"] = getTitle(); + args["REASON"] = LLFloaterIM::sForceCloseSessionMap[reason_string]; - gViewerWindow->alertXml( + LLSD payload; + payload["session_id"] = mSessionUUID; + + LLNotifications::instance().add( "ForceCloseChatterBoxSession", args, - LLFloaterIMPanel::onConfirmForceCloseError, - new LLUUID(mSessionUUID)); + payload, + LLFloaterIMPanel::onConfirmForceCloseError); } @@ -2268,10 +2270,10 @@ void LLFloaterIMPanel::onKickSpeaker(void* user_data) } -void LLFloaterIMPanel::onConfirmForceCloseError(S32 option, void* data) +bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLSD& response) { //only 1 option really - LLUUID session_id = *((LLUUID*) data); + LLUUID session_id = notification["payload"]["session_id"]; if ( gIMMgr ) { @@ -2280,6 +2282,7 @@ void LLFloaterIMPanel::onConfirmForceCloseError(S32 option, void* data) if ( floaterp ) floaterp->close(FALSE); } + return false; } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index b20dcd02bd..4681c5684b 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -81,7 +81,7 @@ public: EState getState() { return mState; } void updateSessionID(const LLUUID& new_session_id); - const LLStringUtil::format_map_t& getNotifyArgs() { return mNotifyArgs; } + const LLSD& getNotifyArgs() { return mNotifyArgs; } static LLVoiceChannel* getChannelByID(const LLUUID& session_id); static LLVoiceChannel* getChannelByURI(std::string uri); @@ -100,7 +100,7 @@ protected: LLUUID mSessionID; EState mState; std::string mSessionName; - LLStringUtil::format_map_t mNotifyArgs; + LLSD mNotifyArgs; BOOL mIgnoreNextSessionLeave; LLHandle<LLPanel> mLoginNotificationHandle; @@ -266,7 +266,7 @@ public: const std::string& error_string); void showSessionForceClose(const std::string& reason); - static void onConfirmForceCloseError(S32 option, void* data); + static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); private: // called by constructors diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index c33de4c457..552854e7fa 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -97,6 +97,96 @@ std::map<std::string,std::string> LLFloaterIM::sForceCloseSessionMap; // return (LLStringUtil::compareDict( a->mName, b->mName ) < 0); //} +class LLViewerChatterBoxInvitationAcceptResponder : + public LLHTTPClient::Responder +{ +public: + LLViewerChatterBoxInvitationAcceptResponder( + const LLUUID& session_id, + LLIMMgr::EInvitationType invitation_type) + { + mSessionID = session_id; + mInvitiationType = invitation_type; + } + + void result(const LLSD& content) + { + if ( gIMMgr) + { + LLFloaterIMPanel* floaterp = + gIMMgr->findFloaterBySession(mSessionID); + + if (floaterp) + { + //we've accepted our invitation + //and received a list of agents that were + //currently in the session when the reply was sent + //to us. Now, it is possible that there were some agents + //to slip in/out between when that message was sent to us + //and now. + + //the agent list updates we've received have been + //accurate from the time we were added to the session + //but unfortunately, our base that we are receiving here + //may not be the most up to date. It was accurate at + //some point in time though. + floaterp->setSpeakers(content); + + //we now have our base of users in the session + //that was accurate at some point, but maybe not now + //so now we apply all of the udpates we've received + //in case of race conditions + floaterp->updateSpeakersList( + gIMMgr->getPendingAgentListUpdates(mSessionID)); + + if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE ) + { + floaterp->requestAutoConnect(); + LLFloaterIMPanel::onClickStartCall(floaterp); + // always open IM window when connecting to voice + LLFloaterChatterBox::showInstance(TRUE); + } + else if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE ) + { + LLFloaterChatterBox::showInstance(TRUE); + } + } + + gIMMgr->clearPendingAgentListUpdates(mSessionID); + gIMMgr->clearPendingInvitation(mSessionID); + } + } + + void error(U32 statusNum, const std::string& reason) + { + //throw something back to the viewer here? + if ( gIMMgr ) + { + gIMMgr->clearPendingAgentListUpdates(mSessionID); + gIMMgr->clearPendingInvitation(mSessionID); + + LLFloaterIMPanel* floaterp = + gIMMgr->findFloaterBySession(mSessionID); + + if ( floaterp ) + { + if ( 404 == statusNum ) + { + std::string error_string; + error_string = "does not exist"; + + floaterp->showSessionStartError( + error_string); + } + } + } + } + +private: + LLUUID mSessionID; + LLIMMgr::EInvitationType mInvitiationType; +}; + // the other_participant_id is either an agent_id, a group_id, or an inventory // folder item_id (collection of calling cards) @@ -256,38 +346,104 @@ protected: }; -class LLIMMgr::LLIMSessionInvite +bool inviteUserResponse(const LLSD& notification, const LLSD& response) { -public: - LLIMSessionInvite( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller_id, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle, - const std::string& notify_box) : - mSessionID(session_id), - mSessionName(session_name), - mCallerID(caller_id), - mCallerName(caller_name), - mType(type), - mInvType(inv_type), - mSessionHandle(session_handle), - mNotifyBox(notify_box) - {}; - - LLUUID mSessionID; - std::string mSessionName; - LLUUID mCallerID; - std::string mCallerName; - EInstantMessage mType; - EInvitationType mInvType; - std::string mSessionHandle; - std::string mNotifyBox; -}; + const LLSD& payload = notification["payload"]; + LLUUID session_id = payload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + payload["session_name"].asString(), + payload["caller_id"].asUUID(), + payload["session_handle"].asString()); + + LLFloaterIMPanel* im_floater = + gIMMgr->findFloaterBySession( + session_id); + if (im_floater) + { + im_floater->requestAutoConnect(); + LLFloaterIMPanel::onClickStartCall(im_floater); + // always open IM window when connecting to voice + LLFloaterChatterBox::showInstance(session_id); + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + gIMMgr->addSession( + payload["session_name"].asString(), + type, + session_id); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "accept invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + new LLViewerChatterBoxInvitationAcceptResponder( + session_id, + inv_type)); + } + } + break; + case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) + { + // mute the sender of this invite + if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) + { + LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + } + } + /* FALLTHROUGH */ + + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(gVoiceClient) + { + std::string s = payload["session_handle"].asString(); + gVoiceClient->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + NULL); + } + } + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + break; + } + + return false; +} // // Public Static Member Functions @@ -510,7 +666,7 @@ void LLIMMgr::addMessage( } } -void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLStringUtil::format_map_t& args) +void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) { LLUIString message; @@ -520,7 +676,7 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess LLFloaterChat* floaterp = LLFloaterChat::getInstance(); message = floaterp->getString(message_name); - message.setArgList(args); + message.setArgs(args); LLChat chat(message); chat.mSourceType = CHAT_SOURCE_SYSTEM; @@ -532,7 +688,7 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess if (floaterp) { message = floaterp->getString(message_name); - message.setArgList(args); + message.setArgs(args); gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); } @@ -687,7 +843,7 @@ void LLIMMgr::removeSession(const LLUUID& session_id) LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater); //mTabContainer->removeTabPanel(floater); - clearPendingInviation(session_id); + clearPendingInvitation(session_id); clearPendingAgentListUpdates(session_id); } } @@ -733,21 +889,21 @@ void LLIMMgr::inviteToSession( ad_hoc_invite = TRUE; } - LLIMSessionInvite* invite = new LLIMSessionInvite( - session_id, - session_name, - caller_id, - caller_name, - type, - inv_type, - session_handle, - notify_box_type); + LLSD payload; + payload["session_id"] = session_id; + payload["session_name"] = session_name; + payload["caller_id"] = caller_id; + payload["caller_name"] = caller_name; + payload["type"] = type; + payload["inv_type"] = inv_type; + payload["session_handle"] = session_handle; + payload["notify_box_type"] = notify_box_type; LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); if (channelp && channelp->callStarted()) { // you have already started a call to the other user, so just accept the invite - inviteUserResponse(0, invite); // inviteUserResponse deletes + LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 0); return; } @@ -761,7 +917,7 @@ void LLIMMgr::inviteToSession( if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) { // invite not from a friend, so decline - inviteUserResponse(1, invite); // inviteUserResponse deletes + LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1); return; } } @@ -771,230 +927,41 @@ void LLIMMgr::inviteToSession( { if (caller_name.empty()) { - gCacheName->get(caller_id, FALSE, onInviteNameLookup, invite); + gCacheName->getName(caller_id, onInviteNameLookup, new LLSD(payload)); } else { - LLStringUtil::format_map_t args; - args["[NAME]"] = caller_name; - args["[GROUP]"] = session_name; + LLSD args; + args["NAME"] = caller_name; + args["GROUP"] = session_name; - LLNotifyBox::showXml(notify_box_type, + LLNotifications::instance().add(notify_box_type, args, - inviteUserResponse, - (void*)invite); // inviteUserResponse deletes + payload, + &inviteUserResponse); } mPendingInvitations[session_id.asString()] = LLSD(); } - else - { - delete invite; - } } //static void LLIMMgr::onInviteNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* userdata) { - LLIMSessionInvite* invite = (LLIMSessionInvite*)userdata; + LLSD payload = *(LLSD*)userdata; + delete (LLSD*)userdata; - invite->mCallerName = first + " " + last; - invite->mSessionName = invite->mCallerName; + payload["caller_name"] = first + " " + last; + payload["session_name"] = payload["caller_name"].asString(); - LLStringUtil::format_map_t args; - args["[NAME]"] = invite->mCallerName; + LLSD args; + args["NAME"] = payload["caller_name"].asString(); - LLNotifyBox::showXml( - invite->mNotifyBox, + LLNotifications::instance().add( + payload["notify_box_type"].asString(), args, - inviteUserResponse, - (void*)invite); -} - -class LLViewerChatterBoxInvitationAcceptResponder : - public LLHTTPClient::Responder -{ -public: - LLViewerChatterBoxInvitationAcceptResponder( - const LLUUID& session_id, - LLIMMgr::EInvitationType invitation_type) - { - mSessionID = session_id; - mInvitiationType = invitation_type; - } - - void result(const LLSD& content) - { - if ( gIMMgr) - { - LLFloaterIMPanel* floaterp = - gIMMgr->findFloaterBySession(mSessionID); - - if (floaterp) - { - //we've accepted our invitation - //and received a list of agents that were - //currently in the session when the reply was sent - //to us. Now, it is possible that there were some agents - //to slip in/out between when that message was sent to us - //and now. - - //the agent list updates we've received have been - //accurate from the time we were added to the session - //but unfortunately, our base that we are receiving here - //may not be the most up to date. It was accurate at - //some point in time though. - floaterp->setSpeakers(content); - - //we now have our base of users in the session - //that was accurate at some point, but maybe not now - //so now we apply all of the udpates we've received - //in case of race conditions - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(mSessionID)); - - if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE ) - { - floaterp->requestAutoConnect(); - LLFloaterIMPanel::onClickStartCall(floaterp); - // always open IM window when connecting to voice - LLFloaterChatterBox::showInstance(TRUE); - } - else if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE ) - { - LLFloaterChatterBox::showInstance(TRUE); - } - } - - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInviation(mSessionID); - } - } - - void error(U32 statusNum, const std::string& reason) - { - //throw something back to the viewer here? - if ( gIMMgr ) - { - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInviation(mSessionID); - - LLFloaterIMPanel* floaterp = - gIMMgr->findFloaterBySession(mSessionID); - - if ( floaterp ) - { - if ( 404 == statusNum ) - { - std::string error_string; - error_string = "does not exist"; - - floaterp->showSessionStartError( - error_string); - } - } - } - } - -private: - LLUUID mSessionID; - LLIMMgr::EInvitationType mInvitiationType; -}; - -//static -void LLIMMgr::inviteUserResponse(S32 option, void* user_data) -{ - LLIMSessionInvite* invitep = (LLIMSessionInvite*)user_data; - - switch(option) - { - case 0: // accept - { - if (invitep->mType == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - invitep->mSessionID = gIMMgr->addP2PSession( - invitep->mSessionName, - invitep->mCallerID, - invitep->mSessionHandle); - - LLFloaterIMPanel* im_floater = - gIMMgr->findFloaterBySession( - invitep->mSessionID); - if (im_floater) - { - im_floater->requestAutoConnect(); - LLFloaterIMPanel::onClickStartCall(im_floater); - // always open IM window when connecting to voice - LLFloaterChatterBox::showInstance(invitep->mSessionID); - } - - gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID); - gIMMgr->clearPendingInviation(invitep->mSessionID); - } - else - { - gIMMgr->addSession( - invitep->mSessionName, - invitep->mType, - invitep->mSessionID); - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = invitep->mSessionID; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - invitep->mSessionID, - invitep->mInvType)); - } - } - break; - case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) - { - // mute the sender of this invite - if (!LLMuteList::getInstance()->isMuted(invitep->mCallerID)) - { - LLMute mute(invitep->mCallerID, invitep->mCallerName, LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } - /* FALLTHROUGH */ - - case 1: // decline - { - if (invitep->mType == IM_SESSION_P2P_INVITE) - { - if(gVoiceClient) - { - gVoiceClient->declineInvite(invitep->mSessionHandle); - } - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = invitep->mSessionID; - LLHTTPClient::post( - url, - data, - NULL); - } - } - - gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID); - gIMMgr->clearPendingInviation(invitep->mSessionID); - break; - } - - delete invitep; + payload, + &inviteUserResponse); } void LLIMMgr::refresh() @@ -1068,7 +1035,7 @@ BOOL LLIMMgr::hasSession(const LLUUID& session_id) return (findFloaterBySession(session_id) != NULL); } -void LLIMMgr::clearPendingInviation(const LLUUID& session_id) +void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) { if ( mPendingInvitations.has(session_id.asString()) ) { diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index da64cd3bab..175f47ebc1 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -68,7 +68,7 @@ public: const LLVector3& position = LLVector3::zero, bool link_name = false); - void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLStringUtil::format_map_t& args); + void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); // This method returns TRUE if the local viewer has a session // currently open keyed to the uuid. The uuid can be keyed by @@ -157,7 +157,7 @@ public: static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id); - void clearPendingInviation(const LLUUID& session_id); + void clearPendingInvitation(const LLUUID& session_id); LLSD getPendingAgentListUpdates(const LLUUID& session_id); void addPendingAgentListUpdates( @@ -169,8 +169,6 @@ public: const std::set<LLHandle<LLFloater> >& getIMFloaterHandles() { return mFloaters; } private: - class LLIMSessionInvite; - // create a panel and update internal representation for // consistency. Returns the pointer, caller (the class instance // since it is a private method) is not responsible for deleting @@ -197,7 +195,6 @@ private: void processIMTypingCore(const LLIMInfo* im_info, BOOL typing); - static void inviteUserResponse(S32 option, void* user_data); static void onInviteNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* userdata); private: diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index a4b80ed7c1..3852755850 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -109,8 +109,8 @@ void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); void remove_inventory_category_from_avatar(LLInventoryCategory* category); void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata); -void move_task_inventory_callback(S32 option, void* user_data); -void confirm_replace_attachment_rez(S32 option, void* user_data); +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); +bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); std::string ICON_NAME[ICON_NAME_COUNT] = { @@ -1288,7 +1288,7 @@ void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv) { dialog = "MoveInventoryFromObject"; } - gViewerWindow->alertXml(dialog, move_task_inventory_callback, move_inv); + LLNotifications::instance().add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv)); } // Move/copy all inventory items from the Contents folder of an in-world @@ -1377,7 +1377,9 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, } else { - move_task_inventory_callback(0, (void*)(move_inv)); + LLNotification::Params params("MoveInventoryFromObject"); + params.functor(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + LLNotifications::instance().forceResponse(params, 0); } } return accept; @@ -2187,12 +2189,12 @@ void LLFolderBridge::modifyOutfit(BOOL append) } // helper stuff -void move_task_inventory_callback(S32 option, void* user_data) +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv* move_inv) { - LLMoveInv* move_inv = (LLMoveInv*)user_data; LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData; LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID); - + S32 option = LLNotification::getSelectedOption(notification, response); + if(option == 0 && object) { if (cat_and_wear && cat_and_wear->mWear) @@ -2223,6 +2225,7 @@ void move_task_inventory_callback(S32 option, void* user_data) } delete move_inv; + return false; } BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, @@ -2353,7 +2356,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else { - move_task_inventory_callback(0, (void*)(move_inv)); + LLNotification::Params params("MoveInventoryFromObject"); + params.functor(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + LLNotifications::instance().forceResponse(params, 0); } } @@ -2648,23 +2653,28 @@ void open_landmark(LLViewerInventoryItem* inv_item, } } -static void open_landmark_callback(S32 option, void* data) +static bool open_landmark_callback(const LLSD& notification, const LLSD& response) { - LLUUID* asset_idp = (LLUUID*)data; + S32 option = LLNotification::getSelectedOption(notification, response); + + LLUUID asset_id = notification["payload"]["asset_id"].asUUID(); if (option == 0) { // HACK: This is to demonstrate teleport on double click for landmarks - gAgent.teleportViaLandmark( *asset_idp ); + gAgent.teleportViaLandmark( asset_id ); // we now automatically track the landmark you're teleporting to // because you'll probably arrive at a telehub instead if( gFloaterWorldMap ) { - gFloaterWorldMap->trackLandmark( *asset_idp ); + gFloaterWorldMap->trackLandmark( asset_id ); } } - delete asset_idp; + + return false; } +static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFromLandmark", open_landmark_callback); + void LLLandmarkBridge::openItem() { @@ -2674,9 +2684,9 @@ void LLLandmarkBridge::openItem() // Opening (double-clicking) a landmark immediately teleports, // but warns you the first time. // open_landmark(item, std::string(" ") + getPrefix() + item->getName(), FALSE); - LLUUID* asset_idp = new LLUUID(item->getAssetUUID()); - LLAlertDialog::showXml("TeleportFromLandmark", - open_landmark_callback, (void*)asset_idp); + LLSD payload; + payload["asset_id"] = item->getAssetUUID(); + LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); } } @@ -3321,8 +3331,9 @@ std::string LLObjectBridge::getLabelSuffix() const void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) { - LLAttachmentRezAction* rez_action = new LLAttachmentRezAction; - rez_action->mItemID = item->getUUID(); + LLSD payload; + payload["item_id"] = item->getUUID(); + S32 attach_pt = 0; if (gAgent.getAvatarObject() && attachment) { @@ -3336,46 +3347,46 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach } } } - rez_action->mAttachPt = attach_pt; + + payload["attachment_point"] = attach_pt; + if (attachment && attachment->getObject()) { - gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment_rez, (void*)rez_action); + LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); } else { - confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action); + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } } -void confirm_replace_attachment_rez(S32 option, void* user_data) +bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) { - LLAttachmentRezAction* rez_action = (LLAttachmentRezAction*)user_data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0/*YES*/) { - if (rez_action) + LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + + if (itemp) { - LLViewerInventoryItem* itemp = gInventory.getItem(rez_action->mItemID); - - if (itemp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, rez_action->mAttachPt); - pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); - msg->addStringFast(_PREHASH_Name, itemp->getName()); - msg->addStringFast(_PREHASH_Description, itemp->getDescription()); - msg->sendReliable(gAgent.getRegion()->getHost()); - } + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); + msg->addU8Fast(_PREHASH_AttachmentPt, notification["payload"]["attachment_point"].asInteger()); + pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); + msg->addStringFast(_PREHASH_Name, itemp->getName()); + msg->addStringFast(_PREHASH_Description, itemp->getDescription()); + msg->sendReliable(gAgent.getRegion()->getHost()); } } - delete rez_action; + return false; } +static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez); void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { @@ -3927,7 +3938,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) if( !wearable_count && !obj_count && !gest_count) { - gViewerWindow->alertXml("CouldNotPutOnOutfit"); + LLNotifications::instance().add("CouldNotPutOnOutfit"); delete wear_info; return; } @@ -4334,7 +4345,7 @@ void LLWearableBridge::openItem() { if( isInTrash() ) { - gViewerWindow->alertXml("CannotWearTrash"); + LLNotifications::instance().add("CannotWearTrash"); } else if(isAgentInventory()) { @@ -4363,7 +4374,7 @@ void LLWearableBridge::openItem() { // *TODO: We should fetch the item details, and then do // the operation above. - gViewerWindow->alertXml("CannotWearInfoNotComplete"); + LLNotifications::instance().add("CannotWearInfoNotComplete"); } } } @@ -4464,7 +4475,7 @@ void LLWearableBridge::wearOnAvatar() // destroy clothing items. if (!gAgent.areWearablesLoaded()) { - gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded"); + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return; } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 064ace52f2..c0cda4c6a4 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -92,7 +92,6 @@ class LLViewerInventoryItem; class LLViewerInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; -class LLAlertDialog; class LLInventoryModel { diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index 59b4d245ac..d98ee1894b 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -119,11 +119,11 @@ void LLLandmarkList::processGetAssetReply( if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) { - LLNotifyBox::showXml("LandmarkMissing"); + LLNotifications::instance().add("LandmarkMissing"); } else { - LLNotifyBox::showXml("UnableToLoadLandmark"); + LLNotifications::instance().add("UnableToLoadLandmark"); } gLandmarkList.mBadList.insert(uuid); diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 3ad26b703a..cc9be04cfc 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -66,7 +66,8 @@ #include "llfloaterchat.h" #include "llimpanel.h" #include "llimview.h" -#include "llnotify.h" +#include "lltrans.h" +#include "llnotifications.h" #include "lluistring.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -278,7 +279,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) if ((mute.mType == LLMute::AGENT) && isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0)) { - gViewerWindow->alertXml("MuteLinden"); + LLNotifications::instance().add("MuteLinden"); return FALSE; } @@ -480,35 +481,35 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& first_n { U32 temp_data = (U32) (uintptr_t) user_data; LLMuteList::EAutoReason reason = (LLMuteList::EAutoReason)temp_data; - LLUIString auto_message; - + + std::string auto_message; switch (reason) { default: case LLMuteList::AR_IM: - auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByIM"); + auto_message = LLTrans::getString("AutoUnmuteByIM"); break; case LLMuteList::AR_INVENTORY: - auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByInventory"); + auto_message = LLTrans::getString("AutoUnmuteByInventory"); break; case LLMuteList::AR_MONEY: - auto_message = LLNotifyBox::getTemplateMessage("AutoUnmuteByMoney"); + auto_message = LLTrans::getString("AutoUnmuteByMoney"); break; } - auto_message.setArg("[FIRST]", first_name); - auto_message.setArg("[LAST]", last_name); + std::string message = LLNotification::format(auto_message, + LLSD().insert("FIRST", first_name).insert("LAST", last_name)); if (reason == LLMuteList::AR_IM) { LLFloaterIMPanel *timp = gIMMgr->findFloaterBySession(agent_id); if (timp) { - timp->addHistoryLine(auto_message.getString()); + timp->addHistoryLine(message); } } - LLChat auto_chat(auto_message.getString()); + LLChat auto_chat(message); LLFloaterChat::addChat(auto_chat, FALSE, FALSE); } diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index dfc327e329..5b4e956137 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -349,7 +349,7 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto LLSD columns; S32 index = 0; - S32 total_static = 0; + //S32 total_static = 0; LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { @@ -383,7 +383,7 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto LLFontGL::HAlign h_align = LLFontGL::LEFT; h_align = LLView::selectFontHAlign(child); - if(!columndynamicwidth) total_static += llmax(0, columnwidth); + //if(!columndynamicwidth) total_static += llmax(0, columnwidth); columns[index]["name"] = columnname; columns[index]["label"] = labelname; @@ -394,7 +394,6 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto index++; } } - name_list->setTotalStaticColumnWidth(total_static); name_list->setColumnHeadings(columns); diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 9c8817da9a..3f4732692f 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -352,20 +352,24 @@ void LLPanelAvatarSecondLife::onDoubleClickGroup(void* data) // static void LLPanelAvatarSecondLife::onClickPublishHelp(void *) { - gViewerWindow->alertXml("ClickPublishHelpAvatar"); + LLNotifications::instance().add("ClickPublishHelpAvatar"); } // static void LLPanelAvatarSecondLife::onClickPartnerHelp(void *) { - gViewerWindow->alertXml("ClickPartnerHelpAvatar", onClickPartnerHelpLoadURL, (void*) NULL); + LLNotifications::instance().add("ClickPartnerHelpAvatar", LLSD(), LLSD(), onClickPartnerHelpLoadURL); } // static -void LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL(S32 option, void* userdata) +bool LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response) { - if (option == 0) - LLWeb::loadURL("http://secondlife.com/partner"); + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + LLWeb::loadURL("http://secondlife.com/partner"); + } + return false; } // static @@ -593,7 +597,7 @@ void LLPanelAvatarWeb::onCommitURL(LLUICtrl* ctrl, void* data) // static void LLPanelAvatarWeb::onClickWebProfileHelp(void *) { - gViewerWindow->alertXml("ClickWebProfileHelpAvatar"); + LLNotifications::instance().add("ClickWebProfileHelpAvatar"); } void LLPanelAvatarWeb::load(std::string url) @@ -930,26 +934,25 @@ void LLPanelAvatarClassified::onClickNew(void* data) { LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - gViewerWindow->alertXml("AddClassified",callbackNew,self); + LLNotifications::instance().add("AddClassified", LLSD(), LLSD(), boost::bind(&LLPanelAvatarClassified::callbackNew, self, _1, _2)); } -// static -void LLPanelAvatarClassified::callbackNew(S32 option, void* data) +bool LLPanelAvatarClassified::callbackNew(const LLSD& notification, const LLSD& response) { - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { LLPanelClassified* panel_classified = new LLPanelClassified(false, false); panel_classified->initNewClassified(); - LLTabContainer* tabs = self->getChild<LLTabContainer>("classified tab"); + LLTabContainer* tabs = getChild<LLTabContainer>("classified tab"); if(tabs) { tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName()); tabs->selectLastTab(); } } + return false; } @@ -966,18 +969,17 @@ void LLPanelAvatarClassified::onClickDelete(void* data) } if (!panel_classified) return; - LLStringUtil::format_map_t args; - args["[NAME]"] = panel_classified->getClassifiedName(); - gViewerWindow->alertXml("DeleteClassified", args, callbackDelete, self); + LLSD args; + args["NAME"] = panel_classified->getClassifiedName(); + LLNotifications::instance().add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelAvatarClassified::callbackDelete, self, _1, _2)); } -// static -void LLPanelAvatarClassified::callbackDelete(S32 option, void* data) +bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LLSD& response) { - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - LLTabContainer* tabs = self->getChild<LLTabContainer>("classified tab"); + S32 option = LLNotification::getSelectedOption(notification, response); + LLTabContainer* tabs = getChild<LLTabContainer>("classified tab"); LLPanelClassified* panel_classified=NULL; if(tabs) { @@ -986,7 +988,7 @@ void LLPanelAvatarClassified::callbackDelete(S32 option, void* data) LLMessageSystem* msg = gMessageSystem; - if (!panel_classified) return; + if (!panel_classified) return false; if (0 == option) { @@ -1005,6 +1007,7 @@ void LLPanelAvatarClassified::callbackDelete(S32 option, void* data) delete panel_classified; panel_classified = NULL; } + return false; } @@ -1124,24 +1127,23 @@ void LLPanelAvatarPicks::onClickDelete(void* data) if (!panel_pick) return; - LLStringUtil::format_map_t args; - args["[PICK]"] = panel_pick->getPickName(); + LLSD args; + args["PICK"] = panel_pick->getPickName(); - gViewerWindow->alertXml("DeleteAvatarPick", args, - callbackDelete, - self); + LLNotifications::instance().add("DeleteAvatarPick", args, LLSD(), + boost::bind(&LLPanelAvatarPicks::callbackDelete, self, _1, _2)); } // static -void LLPanelAvatarPicks::callbackDelete(S32 option, void* data) +bool LLPanelAvatarPicks::callbackDelete(const LLSD& notification, const LLSD& response) { - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLTabContainer* tabs = self->getChild<LLTabContainer>("picks tab"); - LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL; + S32 option = LLNotification::getSelectedOption(notification, response); + LLTabContainer* tabs = getChild<LLTabContainer>("picks tab"); + LLPanelPick* panel_pick = tabs ? (LLPanelPick*)tabs->getCurrentPanel() : NULL; LLMessageSystem* msg = gMessageSystem; - if (!panel_pick) return; + if (!panel_pick) return false; if (0 == option) { @@ -1177,6 +1179,7 @@ void LLPanelAvatarPicks::callbackDelete(S32 option, void* data) delete panel_pick; panel_pick = NULL; } + return false; } @@ -1835,7 +1838,7 @@ void LLPanelAvatar::processAvatarPropertiesReply(LLMessageSystem *msg, void**) args["[PAYMENTINFO]"] = self->mPanelSecondLife->getString(payment_text); std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; // Do not display age verification status at this time - //args["[AGEVERIFICATION]"] = self->mPanelSecondLife->getString(age_text); + //args["[[AGEVERIFICATION]]"] = self->mPanelSecondLife->getString(age_text); args["[AGEVERIFICATION]"] = " "; } else @@ -2187,85 +2190,93 @@ void LLPanelAvatar::onClickKick(void* userdata) gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect(left, top, left+400, top-300); - gViewerWindow->alertXmlEditText("KickUser", LLStringUtil::format_map_t(), - NULL, NULL, - LLPanelAvatar::finishKick, self); + LLSD payload; + payload["avatar_id"] = self->mAvatarID; + LLNotifications::instance().add("KickUser", LLSD(), payload, finishKick); } -// static -void LLPanelAvatar::finishKick(S32 option, const std::string& text, void* userdata) +//static +bool LLPanelAvatar::finishKick(const LLSD& notification, const LLSD& response) { - LLPanelAvatar* self = (LLPanelAvatar*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GodKickUser); msg->nextBlockFast(_PREHASH_UserInfo); msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, self->mAvatarID ); + msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); msg->addU32("KickFlags", KICK_FLAGS_DEFAULT ); - msg->addStringFast(_PREHASH_Reason, text ); + msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); gAgent.sendReliableMessage(); } + return false; } // static void LLPanelAvatar::onClickFreeze(void* userdata) { - gViewerWindow->alertXmlEditText("FreezeUser", LLStringUtil::format_map_t(), - NULL, NULL, - LLPanelAvatar::finishFreeze, userdata); + LLPanelAvatar* self = (LLPanelAvatar*) userdata; + LLSD payload; + payload["avatar_id"] = self->mAvatarID; + LLNotifications::instance().add("FreezeUser", LLSD(), payload, LLPanelAvatar::finishFreeze); } // static -void LLPanelAvatar::finishFreeze(S32 option, const std::string& text, void* userdata) +bool LLPanelAvatar::finishFreeze(const LLSD& notification, const LLSD& response) { - LLPanelAvatar* self = (LLPanelAvatar*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GodKickUser); msg->nextBlockFast(_PREHASH_UserInfo); msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, self->mAvatarID ); + msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); msg->addU32("KickFlags", KICK_FLAGS_FREEZE ); - msg->addStringFast(_PREHASH_Reason, text ); + msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); gAgent.sendReliableMessage(); } + return false; } // static void LLPanelAvatar::onClickUnfreeze(void* userdata) { - gViewerWindow->alertXmlEditText("UnFreezeUser", LLStringUtil::format_map_t(), - NULL, NULL, - LLPanelAvatar::finishUnfreeze, userdata); + LLPanelAvatar* self = (LLPanelAvatar*) userdata; + LLSD payload; + payload["avatar_id"] = self->mAvatarID; + LLNotifications::instance().add("UnFreezeUser", LLSD(), payload, LLPanelAvatar::finishUnfreeze); } // static -void LLPanelAvatar::finishUnfreeze(S32 option, const std::string& text, void* userdata) +bool LLPanelAvatar::finishUnfreeze(const LLSD& notification, const LLSD& response) { - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - + S32 option = LLNotification::getSelectedOption(notification, response); + std::string text = response["message"].asString(); if (option == 0) { + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GodKickUser); msg->nextBlockFast(_PREHASH_UserInfo); msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, self->mAvatarID ); + msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); msg->addU32("KickFlags", KICK_FLAGS_UNFREEZE ); msg->addStringFast(_PREHASH_Reason, text ); gAgent.sendReliableMessage(); } + return false; } // static diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 833b124389..b7f9c69687 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -117,7 +117,7 @@ public: static void onDoubleClickGroup(void* userdata); static void onClickPublishHelp(void *userdata); static void onClickPartnerHelp(void *userdata); - static void onClickPartnerHelpLoadURL(S32 option, void* userdata); + static bool onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response); static void onClickPartnerInfo(void *userdata); // Clear out the controls anticipating new network data. @@ -231,8 +231,8 @@ private: static void onClickNew(void* data); static void onClickDelete(void* data); - static void callbackDelete(S32 option, void* data); - static void callbackNew(S32 option, void* data); + bool callbackDelete(const LLSD& notification, const LLSD& response); + bool callbackNew(const LLSD& notification, const LLSD& response); }; @@ -257,7 +257,7 @@ private: static void onClickNew(void* data); static void onClickDelete(void* data); - static void callbackDelete(S32 option, void* data); + bool callbackDelete(const LLSD& notification, const LLSD& response); }; @@ -325,9 +325,9 @@ public: private: void enableOKIfReady(); - static void finishKick(S32 option, const std::string& text, void* userdata); - static void finishFreeze(S32 option, const std::string& text, void* userdata); - static void finishUnfreeze(S32 option, const std::string& text, void* userdata); + static bool finishKick(const LLSD& notification, const LLSD& response); + static bool finishFreeze(const LLSD& notification, const LLSD& response); + static bool finishUnfreeze(const LLSD& notification, const LLSD& response); static void showProfileCallback(S32 option, void *userdata); diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 64cc19e2fd..e50f2649af 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -317,12 +317,12 @@ BOOL LLPanelClassified::titleIsValid() const std::string& name = mNameEditor->getText(); if (name.empty()) { - gViewerWindow->alertXml("BlankClassifiedName"); + LLNotifications::instance().add("BlankClassifiedName"); return FALSE; } if (!isalnum(name[0])) { - gViewerWindow->alertXml("ClassifiedMustBeAlphanumeric"); + LLNotifications::instance().add("ClassifiedMustBeAlphanumeric"); return FALSE; } @@ -339,31 +339,24 @@ void LLPanelClassified::apply() } } - -// static -void LLPanelClassified::saveCallback(S32 option, void* data) +bool LLPanelClassified::saveCallback(const LLSD& notification, const LLSD& response) { - LLPanelClassified* self = (LLPanelClassified*)data; + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) { case 0: // Save - self->sendClassifiedInfoUpdate(); + sendClassifiedInfoUpdate(); // fall through to close case 1: // Don't Save { - self->mForceClose = true; + mForceClose = true; // Close containing floater - LLView* view = self; - while (view) + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) { - LLFloater* floaterp = dynamic_cast<LLFloater*>(view); - if (floaterp) - { - floaterp->close(); - break; - } - view = view->getParent(); + parent_floater->close(); } } break; @@ -373,16 +366,18 @@ void LLPanelClassified::saveCallback(S32 option, void* data) LLAppViewer::instance()->abortQuit(); break; } + return false; } + BOOL LLPanelClassified::canClose() { if (mForceClose || !checkDirty()) return TRUE; - LLStringUtil::format_map_t args; - args["[NAME]"] = mNameEditor->getText(); - LLAlertDialog::showXml("ClassifiedSave", args, saveCallback, this); + LLSD args; + args["NAME"] = mNameEditor->getText(); + LLNotifications::instance().add("ClassifiedSave", args, LLSD(), boost::bind(&LLPanelClassified::saveCallback, this, _1, _2)); return FALSE; } @@ -785,8 +780,11 @@ void LLPanelClassified::onClickUpdate(void* data) // If user has not set mature, do not allow publish if(self->mMatureCombo->getCurrentIndex() == DECLINE_TO_STATE) { - LLStringUtil::format_map_t args; - gViewerWindow->alertXml("SetClassifiedMature", &callbackConfirmMature, self); + // Tell user about it + LLNotifications::instance().add("SetClassifiedMature", + LLSD(), + LLSD(), + boost::bind(&LLPanelClassified::confirmMature, self, _1, _2)); return; } @@ -794,16 +792,11 @@ void LLPanelClassified::onClickUpdate(void* data) self->gotMature(); } -// static -void LLPanelClassified::callbackConfirmMature(S32 option, void* data) -{ - LLPanelClassified* self = (LLPanelClassified*)data; - self->confirmMature(option); -} - -// invoked from callbackConfirmMature -void LLPanelClassified::confirmMature(S32 option) +// Callback from a dialog indicating response to mature notification +bool LLPanelClassified::confirmMature(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); + // 0 == Yes // 1 == No // 2 == Cancel @@ -816,11 +809,12 @@ void LLPanelClassified::confirmMature(S32 option) mMatureCombo->setCurrentByIndex(NON_MATURE_CONTENT); break; default: - return; + return false; } // If we got here it means they set a valid value gotMature(); + return false; } // Called after we have determined whether this classified has @@ -830,7 +824,9 @@ void LLPanelClassified::gotMature() // if already paid for, just do the update if (mPaidFor) { - callbackConfirmPublish(0, this); + LLNotification::Params params("PublishClassified"); + params.functor(boost::bind(&LLPanelClassified::confirmPublish, this, _1, _2)); + LLNotifications::instance().forceResponse(params, 0); } else { @@ -850,11 +846,11 @@ void LLPanelClassified::callbackGotPriceForListing(S32 option, std::string text, S32 price_for_listing = strtol(text.c_str(), NULL, 10); if (price_for_listing < MINIMUM_PRICE_FOR_LISTING) { - LLStringUtil::format_map_t args; + LLSD args; std::string price_text = llformat("%d", MINIMUM_PRICE_FOR_LISTING); - args["[MIN_PRICE]"] = price_text; + args["MIN_PRICE"] = price_text; - gViewerWindow->alertXml("MinClassifiedPrice", args); + LLNotifications::instance().add("MinClassifiedPrice", args); return; } @@ -862,10 +858,10 @@ void LLPanelClassified::callbackGotPriceForListing(S32 option, std::string text, // update send self->mPriceForListing = price_for_listing; - LLStringUtil::format_map_t args; - args["[AMOUNT]"] = llformat("%d", price_for_listing); - gViewerWindow->alertXml("PublishClassified", args, &callbackConfirmPublish, self); - + LLSD args; + args["AMOUNT"] = llformat("%d", price_for_listing); + LLNotifications::instance().add("PublishClassified", args, LLSD(), + boost::bind(&LLPanelClassified::confirmPublish, self, _1, _2)); } void LLPanelClassified::resetDirty() @@ -889,10 +885,11 @@ void LLPanelClassified::resetDirty() } // invoked from callbackConfirmPublish -void LLPanelClassified::confirmPublish(S32 option) +bool LLPanelClassified::confirmPublish(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // Option 0 = publish - if (option != 0) return; + if (option != 0) return false; sendClassifiedInfoUpdate(); @@ -911,14 +908,9 @@ void LLPanelClassified::confirmPublish(S32 option) } resetDirty(); + return false; } -// static -void LLPanelClassified::callbackConfirmPublish(S32 option, void* data) -{ - LLPanelClassified* self = (LLPanelClassified*)data; - self->confirmPublish(option); -} // static void LLPanelClassified::onClickTeleport(void* data) diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index ee84d89f43..f808eb9913 100644 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -100,17 +100,15 @@ public: static void processClassifiedInfoReply(LLMessageSystem* msg, void**); // Confirmation dialogs flow in this order - static void callbackConfirmMature(S32 option, void* data); - void confirmMature(S32 option); + bool confirmMature(const LLSD& notification, const LLSD& response); void gotMature(); static void callbackGotPriceForListing(S32 option, std::string text, void* data); - static void callbackConfirmPublish(S32 option, void* data); - void confirmPublish(S32 option); + bool confirmPublish(const LLSD& notification, const LLSD& response); void sendClassifiedClickMessage(const std::string& type); protected: - static void saveCallback(S32 option, void* data); + bool saveCallback(const LLSD& notification, const LLSD& response); static void onClickUpdate(void* data); static void onClickTeleport(void* data); diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 2d5f789141..6233740d53 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -45,6 +45,7 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llappviewer.h" +#include "llnotifications.h" // static void* LLPanelGroupTab::createTab(void* data) @@ -115,17 +116,12 @@ void LLPanelGroupTab::handleClickHelp() std::string help_text( getHelpText() ); if ( !help_text.empty() ) { - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = help_text; - LLAlertDialog* dialogp = gViewerWindow->alertXml("GenericAlert", args); - if (dialogp) - { - LLFloater* root_floater = gFloaterView->getParentFloater(this);; - if (root_floater) - { - root_floater->addDependentFloater(dialogp); - } - } + LLSD args; + args["MESSAGE"] = help_text; + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + LLNotification::Params params(parent_floater->contextualNotification("GenericAlert")); + params.substitutions(args); + LLNotifications::instance().add(params); } } @@ -411,11 +407,11 @@ BOOL LLPanelGroup::attemptTransition() mesg = mDefaultNeedsApplyMesg; } // Create a notify box, telling the user about the unapplied tab. - LLStringUtil::format_map_t args; - args["[NEEDS_APPLY_MESSAGE]"] = mesg; - args["[WANT_APPLY_MESSAGE]"] = mWantApplyMesg; - gViewerWindow->alertXml("PanelGroupApply", args, - onNotifyCallback, (void*) this); + LLSD args; + args["NEEDS_APPLY_MESSAGE"] = mesg; + args["WANT_APPLY_MESSAGE"] = mWantApplyMesg; + LLNotifications::instance().add("PanelGroupApply", args, LLSD(), + boost::bind(&LLPanelGroup::handleNotifyCallback, this, _1, _2)); mShowingNotifyDialog = TRUE; // We need to reselect the current tab, since it isn't finished. @@ -465,18 +461,9 @@ void LLPanelGroup::transitionToTab() } } -// static -void LLPanelGroup::onNotifyCallback(S32 option, void* user_data) -{ - LLPanelGroup* self = static_cast<LLPanelGroup*>(user_data); - if (self) - { - self->handleNotifyCallback(option); - } -} - -void LLPanelGroup::handleNotifyCallback(S32 option) +bool LLPanelGroup::handleNotifyCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); mShowingNotifyDialog = FALSE; switch (option) { @@ -512,6 +499,7 @@ void LLPanelGroup::handleNotifyCallback(S32 option) LLAppViewer::instance()->abortQuit(); break; } + return false; } // static @@ -568,9 +556,9 @@ bool LLPanelGroup::apply() // Inform the user. if ( !apply_mesg.empty() ) { - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = apply_mesg; - gViewerWindow->alertXml("GenericAlert", args); + LLSD args; + args["MESSAGE"] = apply_mesg; + LLNotifications::instance().add("GenericAlert", args); } return false; @@ -638,7 +626,7 @@ void LLPanelGroup::showNotice(const std::string& subject, // We need to clean up that inventory offer. if (inventory_offer) { - inventory_offer_callback( IOR_DECLINE , inventory_offer); + inventory_offer->forceResponse(IOR_DECLINE); } return; } diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index f27ef75843..946448a224 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -87,8 +87,7 @@ public: void updateTabVisibility(); // Used by attemptTransition to query the user's response to a tab that needs to apply. - static void onNotifyCallback(S32 option, void* user_data); - void handleNotifyCallback(S32 option); + bool handleNotifyCallback(const LLSD& notification, const LLSD& response); bool apply(); void refreshData(); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 044ad280fa..f6f262f2be 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -344,18 +344,18 @@ void LLPanelGroupGeneral::onClickJoin(void *userdata) if (gdatap) { S32 cost = gdatap->mMembershipFee; - LLStringUtil::format_map_t args; - args["[COST]"] = llformat("%d", cost); - + LLSD args; + args["COST"] = llformat("%d", cost); + LLSD payload; + payload["group_id"] = self->mGroupID; + if (can_afford_transaction(cost)) { - gViewerWindow->alertXml("JoinGroupCanAfford", args, - LLPanelGroupGeneral::joinDlgCB, - self); + LLNotifications::instance().add("JoinGroupCanAfford", args, payload, LLPanelGroupGeneral::joinDlgCB); } else { - gViewerWindow->alertXml("JoinGroupCannotAfford", args); + LLNotifications::instance().add("JoinGroupCannotAfford", args, payload); } } else @@ -366,17 +366,18 @@ void LLPanelGroupGeneral::onClickJoin(void *userdata) } // static -void LLPanelGroupGeneral::joinDlgCB(S32 which, void *userdata) +bool LLPanelGroupGeneral::joinDlgCB(const LLSD& notification, const LLSD& response) { - LLPanelGroupGeneral* self = (LLPanelGroupGeneral*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); - if (which == 1 || !self) + if (option == 1) { // user clicked cancel - return; + return false; } - LLGroupMgr::getInstance()->sendGroupMemberJoin(self->mGroupID); + LLGroupMgr::getInstance()->sendGroupMemberJoin(notification["payload"]["group_id"].asUUID()); + return false; } // static @@ -444,9 +445,8 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) if(mComboMature && mComboMature->getCurrentIndex() == DECLINE_TO_STATE) { - LLStringUtil::format_map_t args; - gViewerWindow->alertXml("SetGroupMature", &callbackConfirmMatureApply, - new LLHandle<LLPanel>(getHandle())); + LLNotifications::instance().add("SetGroupMature", LLSD(), LLSD(), + boost::bind(&LLPanelGroupGeneral::confirmMatureApply, this, _1, _2)); return false; } @@ -464,10 +464,9 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) return false; } - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = mConfirmGroupCreateStr; - gViewerWindow->alertXml("GenericAlertYesCancel", args, - createGroupCallback, new LLHandle<LLPanel>(getHandle()) ); + LLSD args; + args["MESSAGE"] = mConfirmGroupCreateStr; + LLNotifications::instance().add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupGeneral::createGroupCallback, this, _1, _2)); return false; } @@ -545,22 +544,10 @@ void LLPanelGroupGeneral::cancel() notifyObservers(); } - -// static -void LLPanelGroupGeneral::callbackConfirmMatureApply(S32 option, void* data) -{ - LLHandle<LLPanel>* handlep = (LLHandle<LLPanel>*)data; - LLPanelGroupGeneral* self = dynamic_cast<LLPanelGroupGeneral*>(handlep->get()); - delete handlep; - if (self) - { - self->confirmMatureApply(option); - } -} - // invoked from callbackConfirmMature -void LLPanelGroupGeneral::confirmMatureApply(S32 option) +bool LLPanelGroupGeneral::confirmMatureApply(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // 0 == Yes // 1 == No // 2 == Cancel @@ -573,39 +560,35 @@ void LLPanelGroupGeneral::confirmMatureApply(S32 option) mComboMature->setCurrentByIndex(NON_MATURE_CONTENT); break; default: - return; + return false; } // If we got here it means they set a valid value std::string mesg = ""; apply(mesg); + return false; } // static -void LLPanelGroupGeneral::createGroupCallback(S32 option, void* userdata) +bool LLPanelGroupGeneral::createGroupCallback(const LLSD& notification, const LLSD& response) { - LLHandle<LLPanel> panel_handle = *(LLHandle<LLPanel>*)userdata; - delete (LLHandle<LLPanel>*)userdata; - - LLPanelGroupGeneral* self = dynamic_cast<LLPanelGroupGeneral*>(panel_handle.get()); - if (!self) return; - + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: { // Yay! We are making a new group! - U32 enrollment_fee = (self->mCtrlEnrollmentFee->get() ? - (U32) self->mSpinEnrollmentFee->get() : 0); + U32 enrollment_fee = (mCtrlEnrollmentFee->get() ? + (U32) mSpinEnrollmentFee->get() : 0); - LLGroupMgr::getInstance()->sendCreateGroupRequest(self->mGroupNameEditor->getText(), - self->mEditCharter->getText(), - self->mCtrlShowInGroupList->get(), - self->mInsignia->getImageAssetID(), + LLGroupMgr::getInstance()->sendCreateGroupRequest(mGroupNameEditor->getText(), + mEditCharter->getText(), + mCtrlShowInGroupList->get(), + mInsignia->getImageAssetID(), enrollment_fee, - self->mCtrlOpenEnrollment->get(), + mCtrlOpenEnrollment->get(), false, - self->mComboMature->getCurrentIndex() == MATURE_CONTENT); + mComboMature->getCurrentIndex() == MATURE_CONTENT); } break; @@ -613,6 +596,7 @@ void LLPanelGroupGeneral::createGroupCallback(S32 option, void* userdata) default: break; } + return false; } static F32 sSDTime = 0.0f; diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index 982d0678dd..c38594ef0d 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -57,8 +57,7 @@ public: virtual bool needsApply(std::string& mesg); virtual bool apply(std::string& mesg); virtual void cancel(); - static void createGroupCallback(S32 option, void* user_data); - static void callbackConfirmMatureApply(S32 option, void* data); + bool createGroupCallback(const LLSD& notification, const LLSD& response); virtual void update(LLGroupChange gc); @@ -77,11 +76,11 @@ private: static void onReceiveNotices(LLUICtrl* ctrl, void* data); static void openProfile(void* data); - static void joinDlgCB(S32 which, void *userdata); + static bool joinDlgCB(const LLSD& notification, const LLSD& response); void updateMembers(); void updateChanged(); - void confirmMatureApply(S32 option); + bool confirmMatureApply(const LLSD& notification, const LLSD& response); BOOL mPendingMemberUpdate; BOOL mChanged; diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index c4af61587c..70440dd75a 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -66,7 +66,7 @@ public: static void callbackAddUsers(const std::vector<std::string>& names, const std::vector<LLUUID>& agent_ids, void* user_data); - static void inviteOwnerCallback(S32 option, void* userdata); + bool inviteOwnerCallback(const LLSD& notification, const LLSD& response); public: LLUUID mGroupID; @@ -158,9 +158,9 @@ void LLPanelGroupInvite::impl::submitInvitations() // owner role: display confirmation and wait for callback if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite)) { - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = mOwnerWarning; - gViewerWindow->alertXml("GenericAlertYesCancel", args, inviteOwnerCallback, this); + LLSD args; + args["MESSAGE"] = mOwnerWarning; + LLNotifications::instance().add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2)); return; // we'll be called again if user confirms } } @@ -180,24 +180,23 @@ void LLPanelGroupInvite::impl::submitInvitations() (*mCloseCallback)(mCloseCallbackUserData); } -//static -void LLPanelGroupInvite::impl::inviteOwnerCallback(S32 option, void* userdata) +bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response) { - LLPanelGroupInvite::impl* self = (LLPanelGroupInvite::impl*)userdata; - if (!self) return; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: // user confirmed that they really want a new group owner - self->mConfirmedOwnerInvite = true; - self->submitInvitations(); + mConfirmedOwnerInvite = true; + submitInvitations(); break; case 1: // fall through default: break; } + return false; } @@ -396,16 +395,14 @@ void LLPanelGroupInvite::addUsers(std::vector<LLUUID>& agent_ids) if(dest && dest->isAvatar()) { std::string fullname; - LLStringUtil::format_map_t args; + LLSD args; LLNameValue* nvfirst = dest->getNVPair("FirstName"); LLNameValue* nvlast = dest->getNVPair("LastName"); if(nvfirst && nvlast) { - args["[FIRST]"] = nvfirst->getString(); - args["[LAST]"] = nvlast->getString(); - fullname = nvfirst->getString(); - fullname += " "; - fullname += nvlast->getString(); + args["FIRST"] = std::string(nvfirst->getString()); + args["LAST"] = std::string(nvlast->getString()); + fullname = std::string(nvfirst->getString()) + " " + std::string(nvlast->getString()); } if (!fullname.empty()) { diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 18fcc9d291..1b1a7e32a0 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -53,6 +53,7 @@ #include "roles_constants.h" #include "llviewerwindow.h" #include "llviewermessage.h" +#include "llnotifications.h" const S32 NOTICE_DATE_STRING_SIZE = 30; @@ -195,7 +196,8 @@ LLPanelGroupNotices::~LLPanelGroupNotices() if (mInventoryOffer) { // Cancel the inventory offer. - inventory_offer_callback( IOR_DECLINE , mInventoryOffer); + mInventoryOffer->forceResponse(IOR_DECLINE); + mInventoryOffer = NULL; } } @@ -345,7 +347,7 @@ void LLPanelGroupNotices::onClickOpenAttachment(void* data) { LLPanelGroupNotices* self = (LLPanelGroupNotices*)data; - inventory_offer_callback( IOR_ACCEPT , self->mInventoryOffer); + self->mInventoryOffer->forceResponse(IOR_ACCEPT); self->mInventoryOffer = NULL; self->mBtnOpenAttachment->setEnabled(FALSE); } @@ -357,7 +359,7 @@ void LLPanelGroupNotices::onClickSendMessage(void* data) if (self->mCreateSubject->getText().empty()) { // Must supply a subject - gViewerWindow->alertXml("MustSpecifyGroupNoticeSubject"); + LLNotifications::instance().add("MustSpecifyGroupNoticeSubject"); return; } send_group_notice( @@ -384,7 +386,7 @@ void LLPanelGroupNotices::onClickNewMessage(void* data) if (self->mInventoryOffer) { - inventory_offer_callback( IOR_DECLINE , self->mInventoryOffer); + self->mInventoryOffer->forceResponse(IOR_DECLINE); self->mInventoryOffer = NULL; } @@ -535,7 +537,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, if (mInventoryOffer) { // Cancel the inventory offer for the previously viewed notice - inventory_offer_callback( IOR_DECLINE , mInventoryOffer); + mInventoryOffer->forceResponse(IOR_DECLINE); mInventoryOffer = NULL; } diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 4b48fb3510..6fb601bf56 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -237,11 +237,11 @@ BOOL LLPanelGroupRoles::attemptTransition() mesg = mDefaultNeedsApplyMesg; } // Create a notify box, telling the user about the unapplied tab. - LLStringUtil::format_map_t args; - args["[NEEDS_APPLY_MESSAGE]"] = mesg; - args["[WANT_APPLY_MESSAGE]"] = mWantApplyMesg; - gViewerWindow->alertXml("PanelGroupApply", args, - onNotifyCallback, (void*) this); + LLSD args; + args["NEEDS_APPLY_MESSAGE"] = mesg; + args["WANT_APPLY_MESSAGE"] = mWantApplyMesg; + LLNotifications::instance().add("PanelGroupApply", args, LLSD(), + boost::bind(&LLPanelGroupRoles::handleNotifyCallback, this, _1, _2)); mHasModal = TRUE; // We need to reselect the current tab, since it isn't finished. if (mSubTabContainer) @@ -282,18 +282,9 @@ void LLPanelGroupRoles::transitionToTab() } } -// static -void LLPanelGroupRoles::onNotifyCallback(S32 option, void* user_data) -{ - LLPanelGroupRoles* self = static_cast<LLPanelGroupRoles*>(user_data); - if (self) - { - self->handleNotifyCallback(option); - } -} - -void LLPanelGroupRoles::handleNotifyCallback(S32 option) +bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); mHasModal = FALSE; switch (option) { @@ -307,9 +298,9 @@ void LLPanelGroupRoles::handleNotifyCallback(S32 option) if ( !apply_mesg.empty() ) { mHasModal = TRUE; - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = apply_mesg; - gViewerWindow->alertXml("GenericAlert", args, onModalClose, (void*) this); + LLSD args; + args["MESSAGE"] = apply_mesg; + LLNotifications::instance().add("GenericAlert", args, LLSD(), boost::bind(&LLPanelGroupRoles::onModalClose, this, _1, _2)); } // Skip switching tabs. break; @@ -337,16 +328,13 @@ void LLPanelGroupRoles::handleNotifyCallback(S32 option) // Do nothing. The user is canceling the action. break; } + return false; } -// static -void LLPanelGroupRoles::onModalClose(S32 option, void* user_data) +bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& response) { - LLPanelGroupRoles* self = static_cast<LLPanelGroupRoles*>(user_data); - if (self) - { - self->mHasModal = FALSE; - } + mHasModal = FALSE; + return false; } @@ -1375,16 +1363,16 @@ bool LLPanelGroupMembersSubTab::apply(std::string& mesg) if ( mNumOwnerAdditions > 0 ) { LLRoleData rd; - LLStringUtil::format_map_t args; + LLSD args; if ( gdatap->getRoleData(gdatap->mOwnerRole, rd) ) { mHasModal = TRUE; - args["[ROLE_NAME]"] = rd.mRoleName; - gViewerWindow->alertXml("AddGroupOwnerWarning", + args["ROLE_NAME"] = rd.mRoleName; + LLNotifications::instance().add("AddGroupOwnerWarning", args, - addOwnerCB, - this); + LLSD(), + boost::bind(&LLPanelGroupMembersSubTab::addOwnerCB, this, _1, _2)); } else { @@ -1404,20 +1392,17 @@ bool LLPanelGroupMembersSubTab::apply(std::string& mesg) return true; } -//static -void LLPanelGroupMembersSubTab::addOwnerCB(S32 option, void* data) +bool LLPanelGroupMembersSubTab::addOwnerCB(const LLSD& notification, const LLSD& response) { - LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*) data; - - if (!self) return; - - self->mHasModal = FALSE; + S32 option = LLNotification::getSelectedOption(notification, response); + mHasModal = FALSE; if (0 == option) { // User clicked "Yes" - self->applyMemberChanges(); + applyMemberChanges(); } + return false; } void LLPanelGroupMembersSubTab::applyMemberChanges() @@ -2225,22 +2210,19 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLCheckBoxCtrl* check, bool forc check->set(FALSE); LLRoleData rd; - LLStringUtil::format_map_t args; + LLSD args; if ( gdatap->getRoleData(role_id, rd) ) { - args["[ACTION_NAME]"] = rap->mDescription; - args["[ROLE_NAME]"] = rd.mRoleName; - struct ActionCBData* cb_data = new ActionCBData; - cb_data->mSelf = this; - cb_data->mCheck = check; + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; mHasModal = TRUE; std::string warning = "AssignDangerousActionWarning"; if (GP_ROLE_CHANGE_ACTIONS == power) { warning = "AssignDangerousAbilityWarning"; } - gViewerWindow->alertXml(warning, args, addActionCB, cb_data); + LLNotifications::instance().add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); } else { @@ -2262,22 +2244,21 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLCheckBoxCtrl* check, bool forc notifyObservers(); } -//static -void LLPanelGroupRolesSubTab::addActionCB(S32 option, void* data) +bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check) { - struct ActionCBData* cb_data = (struct ActionCBData*) data; + if (!check) return false; - if (!cb_data || !cb_data->mSelf || !cb_data->mCheck) return; - - cb_data->mSelf->mHasModal = FALSE; + mHasModal = FALSE; + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { // User clicked "Yes" - cb_data->mCheck->set(TRUE); + check->set(TRUE); const bool force_add = true; - cb_data->mSelf->handleActionCheck(cb_data->mCheck, force_add); + handleActionCheck(check, force_add); } + return false; } @@ -2413,9 +2394,9 @@ void LLPanelGroupRolesSubTab::handleDeleteRole() if (role_item->getUUID().isNull() || role_item->getUUID() == gdatap->mOwnerRole) { - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = mRemoveEveryoneTxt; - LLNotifyBox::showXml("GenericNotify", args); + LLSD args; + args["MESSAGE"] = mRemoveEveryoneTxt; + LLNotifications::instance().add("GenericNotify", args); return; } diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index f55d70f018..592e585f9e 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -73,9 +73,8 @@ public: void transitionToTab(); // Used by attemptTransition to query the user's response to a tab that needs to apply. - static void onNotifyCallback(S32 option, void* user_data); - void handleNotifyCallback(S32 option); - static void onModalClose(S32 option, void* user_data); + bool handleNotifyCallback(const LLSD& notification, const LLSD& response); + bool onModalClose(const LLSD& notification, const LLSD& response); // Most of these messages are just passed on to the current sub-tab. virtual std::string getHelpText() const; @@ -188,7 +187,7 @@ public: LLRoleMemberChangeType type); void applyMemberChanges(); - static void addOwnerCB(S32 option, void* data); + bool addOwnerCB(const LLSD& notification, const LLSD& response); virtual void activate(); virtual void deactivate(); @@ -250,7 +249,7 @@ public: static void onActionCheck(LLUICtrl*, void*); void handleActionCheck(LLCheckBoxCtrl*, bool force=false); - static void addActionCB(S32 option, void* data); + bool addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check); static void onPropertiesKey(LLLineEditor*, void*); diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index 11f88695c5..05381ae7d8 100644 --- a/indra/newview/llpanelland.cpp +++ b/indra/newview/llpanelland.cpp @@ -266,5 +266,5 @@ void LLPanelLandInfo::onClickAbout(void*) void LLPanelLandInfo::onShowOwnersHelp(void* user_data) { - gViewerWindow->alertXml("ShowOwnersHelp"); + LLNotifications::instance().add("ShowOwnersHelp"); } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 20228ed306..929043e97d 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -899,16 +899,17 @@ void LLPanelLogin::onClickConnect(void *) } else { - gViewerWindow->alertXml("MustHaveAccountToLogIn", - LLPanelLogin::newAccountAlertCallback); + LLNotifications::instance().add("MustHaveAccountToLogIn", LLSD(), LLSD(), + LLPanelLogin::newAccountAlertCallback); } } } // static -void LLPanelLogin::newAccountAlertCallback(S32 option, void*) +bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { llinfos << "Going to account creation URL" << llendl; @@ -918,6 +919,7 @@ void LLPanelLogin::newAccountAlertCallback(S32 option, void*) { sInstance->setFocus(TRUE); } + return false; } @@ -964,7 +966,7 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE) { - LLNotifyBox::showXml("CapsKeyOn"); + LLNotifications::instance().add("CapsKeyOn"); sCapslockDidNotification = TRUE; } } diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 9d7e386cda..1f803fa57c 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -82,7 +82,7 @@ public: private: static void onClickConnect(void*); static void onClickNewAccount(void*); - static void newAccountAlertCallback(S32 option, void*); + static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); static void onClickQuit(void*); static void onClickVersion(void*); virtual void onNavigateComplete( const EventType& eventIn ); diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 8a75385984..b46e04d462 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -876,8 +876,9 @@ void LLPanelPermissions::cbGroupID(LLUUID group_id, void* userdata) LLSelectMgr::getInstance()->sendGroup(group_id); } -void callback_deed_to_group(S32 option, void*) +bool callback_deed_to_group(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { LLUUID group_id; @@ -888,12 +889,12 @@ void callback_deed_to_group(S32 option, void*) // LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT); } } + return false; } void LLPanelPermissions::onClickDeedToGroup(void* data) { - gViewerWindow->alertXml( "DeedObjectToGroup", - callback_deed_to_group, NULL); + LLNotifications::instance().add( "DeedObjectToGroup", LLSD(), LLSD(), callback_deed_to_group); } ///---------------------------------------------------------------------------- @@ -1092,7 +1093,7 @@ void LLPanelPermissions::onCommitClickAction(LLUICtrl* ctrl, void*) LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); if (!sale_info.isForSale()) { - gViewerWindow->alertXml("CantSetBuyObject"); + LLNotifications::instance().add("CantSetBuyObject"); // Set click action back to its old value U8 click_action = 0; @@ -1110,7 +1111,7 @@ void LLPanelPermissions::onCommitClickAction(LLUICtrl* ctrl, void*) if (!can_pay) { // Warn, but do it anyway. - gViewerWindow->alertXml("ClickActionNotPayable"); + LLNotifications::instance().add("ClickActionNotPayable"); } } LLSelectMgr::getInstance()->selectionSetClickAction(click_action); diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 9bd118fa1d..2420d8d424 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -476,7 +476,7 @@ void LLPanelPick::onClickSet(void* data) // is the location and nothing else if ( gAgent.getRegion ()->getName () != self->mSimName ) { - gViewerWindow->alertXml("SetPickLocation"); + LLNotifications::instance().add("SetPickLocation"); }; self->mLocationEditor->setText(location_text); diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 4ae253360a..100fa3209d 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -416,24 +416,24 @@ void LLPanelPlace::onClickLandmark(void* data) void LLPanelPlace::onClickAuction(void* data) { LLPanelPlace* self = (LLPanelPlace*)data; + LLSD payload; + payload["auction_id"] = self->mAuctionID; - gViewerWindow->alertXml("GoToAuctionPage", - callbackAuctionWebPage, - self); + LLNotifications::instance().add("GoToAuctionPage", LLSD(), payload, callbackAuctionWebPage); } // static -void LLPanelPlace::callbackAuctionWebPage(S32 option, void* data) +bool LLPanelPlace::callbackAuctionWebPage(const LLSD& notification, const LLSD& response) { - LLPanelPlace* self = (LLPanelPlace*)data; - + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { std::string url; - url = AUCTION_URL + llformat( "%010d", self->mAuctionID); + url = AUCTION_URL + llformat("%010d", response["auction_id"].asInteger()); llinfos << "Loading auction page " << url << llendl; LLWeb::loadURL(url); } + return false; } diff --git a/indra/newview/llpanelplace.h b/indra/newview/llpanelplace.h index 7a09f5cca6..db47889546 100644 --- a/indra/newview/llpanelplace.h +++ b/indra/newview/llpanelplace.h @@ -83,7 +83,7 @@ protected: static void onClickAuction(void* data); // Go to auction web page if user clicked OK - static void callbackAuctionWebPage(S32 option, void* data); + static bool callbackAuctionWebPage(const LLSD& notification, const LLSD& response); protected: LLUUID mParcelID; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 7661f9acd6..7e465a88bc 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -284,9 +284,8 @@ BOOL LLPreviewGesture::canClose() else { // Bring up view-modal dialog: Save changes? Yes, No, Cancel - gViewerWindow->alertXml("SaveChanges", - handleSaveChangesDialog, - this ); + LLNotifications::instance().add("SaveChanges", LLSD(), LLSD(), + boost::bind(&LLPreviewGesture::handleSaveChangesDialog, this, _1, _2) ); return FALSE; } } @@ -320,22 +319,21 @@ void LLPreviewGesture::setMinimized(BOOL minimize) } -// static -void LLPreviewGesture::handleSaveChangesDialog(S32 option, void* data) +bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const LLSD& response) { - LLPreviewGesture* self = (LLPreviewGesture*)data; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: // "Yes" - gGestureManager.stopGesture(self->mPreviewGesture); - self->mCloseAfterSave = TRUE; - onClickSave(data); + gGestureManager.stopGesture(mPreviewGesture); + mCloseAfterSave = TRUE; + onClickSave(this); break; case 1: // "No" - gGestureManager.stopGesture(self->mPreviewGesture); - self->mDirty = FALSE; // Force the dirty flag because user has clicked NO on confirm save dialog... - self->close(); + gGestureManager.stopGesture(mPreviewGesture); + mDirty = FALSE; // Force the dirty flag because user has clicked NO on confirm save dialog... + close(); break; case 2: // "Cancel" @@ -344,6 +342,7 @@ void LLPreviewGesture::handleSaveChangesDialog(S32 option, void* data) LLAppViewer::instance()->abortQuit(); break; } + return false; } @@ -1114,14 +1113,14 @@ void LLPreviewGesture::saveIfNeeded() if (dp.getCurrentSize() > 1000) { - gViewerWindow->alertXml("GestureSaveFailedTooManySteps"); + LLNotifications::instance().add("GestureSaveFailedTooManySteps"); delete gesture; gesture = NULL; } else if (!ok) { - gViewerWindow->alertXml("GestureSaveFailedTryAgain"); + LLNotifications::instance().add("GestureSaveFailedTryAgain"); delete gesture; gesture = NULL; } @@ -1260,7 +1259,7 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, } else { - gViewerWindow->alertXml("GestureSaveFailedObjectNotFound"); + LLNotifications::instance().add("GestureSaveFailedObjectNotFound"); } } @@ -1274,9 +1273,9 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, else { llwarns << "Problem saving gesture: " << status << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("GestureSaveFailedReason",args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("GestureSaveFailedReason", args); } delete info; info = NULL; diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 3b07608134..bbe9486bfd 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -101,7 +101,7 @@ protected: void* user_data, S32 status, LLExtStat ext_status); - static void handleSaveChangesDialog(S32 option, void* userdata); + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); // Write UI back into gesture LLMultiGesture* createGesture(); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 61ebe6cbbc..ef61270069 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -229,9 +229,7 @@ BOOL LLPreviewNotecard::canClose() else { // Bring up view-modal dialog: Save changes? Yes, No, Cancel - gViewerWindow->alertXml("SaveChanges", - &LLPreviewNotecard::handleSaveChangesDialog, - this); + LLNotifications::instance().add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleSaveChangesDialog,this, _1, _2)); return FALSE; } @@ -403,15 +401,15 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { - LLNotifyBox::showXml("NotecardMissing"); + LLNotifications::instance().add("NotecardMissing"); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { - LLNotifyBox::showXml("NotecardNoPermissions"); + LLNotifications::instance().add("NotecardNoPermissions"); } else { - LLNotifyBox::showXml("UnableToLoadNotecard"); + LLNotifications::instance().add("UnableToLoadNotecard"); } llwarns << "Problem loading notecard: " << status << llendl; @@ -578,7 +576,7 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data } else { - gViewerWindow->alertXml("SaveNotecardFailObjectNotFound"); + LLNotifications::instance().add("SaveNotecardFailObjectNotFound"); } } // Perform item copy to inventory @@ -601,9 +599,9 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data else { llwarns << "Problem saving notecard: " << status << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("SaveNotecardFailReason",args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("SaveNotecardFailReason", args); } std::string uuid_string; @@ -614,20 +612,19 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data delete info; } -// static -void LLPreviewNotecard::handleSaveChangesDialog(S32 option, void* userdata) +bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const LLSD& response) { - LLPreviewNotecard* self = (LLPreviewNotecard*)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: // "Yes" - self->mCloseAfterSave = TRUE; - LLPreviewNotecard::onClickSave((void*)self); + mCloseAfterSave = TRUE; + LLPreviewNotecard::onClickSave((void*)this); break; case 1: // "No" - self->mForceClose = TRUE; - self->close(); + mForceClose = TRUE; + close(); break; case 2: // "Cancel" @@ -636,6 +633,7 @@ void LLPreviewNotecard::handleSaveChangesDialog(S32 option, void* userdata) LLAppViewer::instance()->abortQuit(); break; } + return false; } void LLPreviewNotecard::reshape(S32 width, S32 height, BOOL called_from_parent) diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index 1c801abf59..7175a764ec 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -101,7 +101,7 @@ protected: void* user_data, S32 status, LLExtStat ext_status); - static void handleSaveChangesDialog(S32 option, void* userdata); + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); virtual const char *getTitleName() const { return "Note"; } diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 2717c44415..42363079a4 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -608,27 +608,26 @@ BOOL LLScriptEdCore::canClose() else { // Bring up view-modal dialog: Save changes? Yes, No, Cancel - gViewerWindow->alertXml("SaveChanges", LLScriptEdCore::handleSaveChangesDialog, this); + LLNotifications::instance().add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleSaveChangesDialog, this, _1, _2)); return FALSE; } } -// static -void LLScriptEdCore::handleSaveChangesDialog( S32 option, void* userdata ) +bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLSD& response ) { - LLScriptEdCore* self = (LLScriptEdCore*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); switch( option ) { case 0: // "Yes" // close after saving - LLScriptEdCore::doSave( self, TRUE ); + LLScriptEdCore::doSave( this, TRUE ); break; case 1: // "No" - self->mForceClose = TRUE; + mForceClose = TRUE; // This will close immediately because mForceClose is true, so we won't // infinite loop with these dialogs. JC - ((LLFloater*) self->getParent())->close(); + ((LLFloater*) getParent())->close(); break; case 2: // "Cancel" @@ -637,29 +636,32 @@ void LLScriptEdCore::handleSaveChangesDialog( S32 option, void* userdata ) LLAppViewer::instance()->abortQuit(); break; } + return false; } // static -void LLScriptEdCore::onHelpWebDialog(S32 option, void* userdata) +bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& response) { - LLScriptEdCore* corep = (LLScriptEdCore*)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: - LLWeb::loadURL(corep->mHelpURL); + LLWeb::loadURL(notification["payload"]["help_url"]); break; default: break; } + return false; } // static void LLScriptEdCore::onBtnHelp(void* userdata) { - gViewerWindow->alertXml("WebLaunchLSLGuide", - onHelpWebDialog, - userdata); + LLScriptEdCore* corep = (LLScriptEdCore*)userdata; + LLSD payload; + payload["help_url"] = corep->mHelpURL; + LLNotifications::instance().add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog); } // static @@ -818,8 +820,7 @@ void LLScriptEdCore::onBtnUndoChanges( void* userdata ) LLScriptEdCore* self = (LLScriptEdCore*) userdata; if( !self->mEditor->tryToRevertToPristineState() ) { - gViewerWindow->alertXml("ScriptCannotUndo", - LLScriptEdCore::handleReloadFromServerDialog, self); + LLNotifications::instance().add("ScriptCannotUndo", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleReloadFromServerDialog, self, _1, _2)); } } @@ -965,17 +966,16 @@ void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data) } } -// static -void LLScriptEdCore::handleReloadFromServerDialog( S32 option, void* userdata ) +bool LLScriptEdCore::handleReloadFromServerDialog(const LLSD& notification, const LLSD& response ) { - LLScriptEdCore* self = (LLScriptEdCore*) userdata; + S32 option = LLNotification::getSelectedOption(notification, response); switch( option ) { case 0: // "Yes" - if( self->mLoadCallback ) + if( mLoadCallback ) { - self->mEditor->setText( self->getString("loading") ); - self->mLoadCallback( self->mUserdata ); + mEditor->setText( getString("loading") ); + mLoadCallback( mUserdata ); } break; @@ -986,6 +986,7 @@ void LLScriptEdCore::handleReloadFromServerDialog( S32 option, void* userdata ) llassert(0); break; } + return false; } void LLScriptEdCore::selectFirstError() @@ -1444,9 +1445,9 @@ void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 else { llwarns << "Problem saving script: " << status << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("SaveScriptFailReason", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("SaveScriptFailReason", args); } delete info; } @@ -1482,9 +1483,9 @@ void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_d else { llwarns << "Problem saving LSL Bytecode (Preview)" << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("SaveBytecodeFailReason", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("SaveBytecodeFailReason", args); } delete instance_uuid; } @@ -1530,15 +1531,15 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { - LLNotifyBox::showXml("ScriptMissing"); + LLNotifications::instance().add("ScriptMissing"); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { - LLNotifyBox::showXml("ScriptNoPermissions"); + LLNotifications::instance().add("ScriptNoPermissions"); } else { - LLNotifyBox::showXml("UnableToLoadScript"); + LLNotifications::instance().add("UnableToLoadScript"); } preview->mAssetStatus = PREVIEW_ASSET_ERROR; @@ -1846,15 +1847,15 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { - LLNotifyBox::showXml("ScriptMissing"); + LLNotifications::instance().add("ScriptMissing"); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { - LLNotifyBox::showXml("ScriptNoPermissions"); + LLNotifications::instance().add("ScriptNoPermissions"); } else { - LLNotifyBox::showXml("UnableToLoadScript"); + LLNotifications::instance().add("UnableToLoadScript"); } instance->mAssetStatus = PREVIEW_ASSET_ERROR; } @@ -1941,7 +1942,7 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) else { runningCheckbox->set(!running); - gViewerWindow->alertXml("CouldNotStartStopScript"); + LLNotifications::instance().add("CouldNotStartStopScript"); } } @@ -1964,7 +1965,7 @@ void LLLiveLSLEditor::onReset(void *userdata) } else { - gViewerWindow->alertXml("CouldNotStartStopScript"); + LLNotifications::instance().add("CouldNotStartStopScript"); } } @@ -2058,7 +2059,7 @@ void LLLiveLSLEditor::saveIfNeeded() LLViewerObject* object = gObjectList.findObject(mObjectID); if(!object) { - gViewerWindow->alertXml("SaveScriptFailObjectNotFound"); + LLNotifications::instance().add("SaveScriptFailObjectNotFound"); return; } @@ -2066,7 +2067,7 @@ void LLLiveLSLEditor::saveIfNeeded() { // $NOTE: While the error message may not be exactly correct, // it's pretty close. - gViewerWindow->alertXml("SaveScriptFailObjectNotFound"); + LLNotifications::instance().add("SaveScriptFailObjectNotFound"); return; } @@ -2268,9 +2269,9 @@ void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_da if (status) { llwarns << "Unable to save text for a script." << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("CompileQueueSaveText", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("CompileQueueSaveText", args); } else { @@ -2329,9 +2330,9 @@ void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* use llinfos << "Problem saving LSL Bytecode (Live Editor)" << llendl; llwarns << "Unable to save a compiled script." << llendl; - LLStringUtil::format_map_t args; - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); - gViewerWindow->alertXml("CompileQueueSaveBytecode", args); + LLSD args; + args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); + LLNotifications::instance().add("CompileQueueSaveBytecode", args); } std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString()); diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index c0af06f480..c84d5e6d8f 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -80,10 +80,10 @@ public: BOOL canClose(); - static void handleSaveChangesDialog(S32 option, void* userdata); - static void handleReloadFromServerDialog(S32 option, void* userdata); + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); + bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response); - static void onHelpWebDialog(S32 option, void* userdata); + static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); static void onBtnHelp(void* userdata); static void onBtnDynamicHelp(void* userdata); static void onCheckLock(LLUICtrl*, void*); diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 79b8313352..fefa6d40d7 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -349,15 +349,15 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, LLPointer<LLImageTGA> image_tga = new LLImageTGA; if( !image_tga->encode( src ) ) { - LLStringUtil::format_map_t args; - args["[FILE]"] = self->mSaveFileName; - gViewerWindow->alertXml("CannotEncodeFile", args); + LLSD args; + args["FILE"] = self->mSaveFileName; + LLNotifications::instance().add("CannotEncodeFile", args); } else if( !image_tga->save( self->mSaveFileName ) ) { - LLStringUtil::format_map_t args; - args["[FILE]"] = self->mSaveFileName; - gViewerWindow->alertXml("CannotWriteFile", args); + LLSD args; + args["FILE"] = self->mSaveFileName; + LLNotifications::instance().add("CannotWriteFile", args); } else { @@ -370,7 +370,7 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, if( self && !success ) { - gViewerWindow->alertXml("CannotDownloadFile"); + LLNotifications::instance().add("CannotDownloadFile"); } } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 81decdf40a..ae4be6173b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2695,7 +2695,8 @@ void LLSelectMgr::selectDelete() return; } - LLObjectSelectionHandle* selection_handlep = new LLObjectSelectionHandle(getSelection()); + LLNotification::Params params("ConfirmObjectDeleteLock"); + params.functor(boost::bind(&LLSelectMgr::confirmDelete, _1, _2, getSelection())); if(locked_but_deleteable_object || no_copy_but_deleteable_object || @@ -2711,72 +2712,55 @@ void LLSelectMgr::selectDelete() if(locked_but_deleteable_object && !no_copy_but_deleteable_object && all_owned_by_you) { //Locked only - gViewerWindow->alertXml( "ConfirmObjectDeleteLock", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteLock"); } else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you) { //No Copy only - gViewerWindow->alertXml( "ConfirmObjectDeleteNoCopy", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteNoCopy"); } else if(!locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you) { //not owned only - gViewerWindow->alertXml( "ConfirmObjectDeleteNoOwn", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteNoOwn"); } else if(locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you) { //locked and no copy - gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoCopy", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteLockNoCopy"); } else if(locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you) { //locked and not owned - gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoOwn", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteLockNoOwn"); } else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && !all_owned_by_you) { //no copy and not owned - gViewerWindow->alertXml( "ConfirmObjectDeleteNoCopyNoOwn", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteNoCopyNoOwn"); } else { //locked, no copy and not owned - gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoCopyNoOwn", - &LLSelectMgr::confirmDelete, - selection_handlep); + params.name("ConfirmObjectDeleteLockNoCopyNoOwn"); } - - + LLNotifications::instance().add(params); } else { - confirmDelete(0, (void*)selection_handlep); + LLNotifications::instance().forceResponse(params, 0); } } // static -void LLSelectMgr::confirmDelete(S32 option, void* data) +bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle) { - LLObjectSelectionHandle handle = *(LLObjectSelectionHandle*)data; - delete (LLObjectSelectionHandle*)data; - + S32 option = LLNotification::getSelectedOption(notification, response); if (!handle->getObjectCount()) { llwarns << "Nothing to delete!" << llendl; - return; + return false; } switch(option) @@ -2815,6 +2799,7 @@ void LLSelectMgr::confirmDelete(S32 option, void* data) default: break; } + return false; } diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index f210fdb9d3..27bcb5a582 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -683,7 +683,7 @@ private: static void packHingeHead(void *user_data); static void packPermissionsHead(void* user_data); static void packGodlikeHead(void* user_data); - static void confirmDelete(S32 option, void* data); + static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle); private: LLPointer<LLViewerImage> mSilhouetteImagep; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9a6454be33..1dc1ddd451 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -235,18 +235,17 @@ std::string load_password_from_disk(); void save_password_to_disk(const char* hashed_password); bool is_hex_string(U8* str, S32 len); void show_first_run_dialog(); -void first_run_dialog_callback(S32 option, void* userdata); +bool first_run_dialog_callback(const LLSD& notification, const LLSD& response); void set_startup_status(const F32 frac, const std::string& string, const std::string& msg); -void login_alert_status(S32 option, void* user_data); +bool login_alert_status(const LLSD& notification, const LLSD& response); void update_app(BOOL mandatory, const std::string& message); -void update_dialog_callback(S32 option, void *userdata); +bool update_dialog_callback(const LLSD& notification, const LLSD& response); void login_packet_failed(void**, S32 result); void use_circuit_callback(void**, S32 result); void register_viewer_callbacks(LLMessageSystem* msg); void init_stat_view(); void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32); -void dialog_choose_gender_first_start(); -void callback_choose_gender(S32 option, void* userdata); +bool callback_choose_gender(const LLSD& notification, const LLSD& response); void init_start_screen(S32 location_id); void release_start_screen(); void reset_login(); @@ -387,16 +386,16 @@ bool idle_startup() if (LLFeatureManager::getInstance()->isSafe()) { - gViewerWindow->alertXml("DisplaySetToSafe"); + LLNotifications::instance().add("DisplaySetToSafe"); } else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && (gSavedSettings.getS32("LastFeatureVersion") != 0)) { - gViewerWindow->alertXml("DisplaySetToRecommended"); + LLNotifications::instance().add("DisplaySetToRecommended"); } else if (!gViewerWindow->getInitAlert().empty()) { - gViewerWindow->alertXml(gViewerWindow->getInitAlert()); + LLNotifications::instance().add(gViewerWindow->getInitAlert()); } gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); @@ -419,10 +418,11 @@ bool idle_startup() } if (!xml_ok) { - // *TODO:translate (maybe - very unlikely error message) - // Note: alerts.xml may be invalid - if this gets translated it will need to be in the code - std::string bad_xui_msg = "An error occured while updating Second Life. Please download the latest version from www.secondlife.com."; - LLAppViewer::instance()->earlyExit(bad_xui_msg); + // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. + // If that's so, then we'll get a fatal error on attempting to load it, + // which will display a nontranslatable error message that says so. + // Otherwise, we'll display a reasonable error message that IS translatable. + LLAppViewer::instance()->earlyExit("BadInstallation"); } // // Statistics stuff @@ -440,9 +440,9 @@ bool idle_startup() if (ll_init_ares() == NULL || !gAres->isInitialized()) { - LL_WARNS("AppInit") << "Could not start address resolution system" << LL_ENDL; - std::string msg = LLTrans::getString("LoginFailedNoNetwork"); - LLAppViewer::instance()->earlyExit(msg); + std::string diagnostic = "Could not start address resolution system"; + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().insert("DIAGNOSTIC", diagnostic)); } // @@ -500,9 +500,9 @@ bool idle_startup() circuit_heartbeat_interval, circuit_timeout)) { - std::string msg = LLTrans::getString("LoginFailedNoNetwork"); - msg.append(llformat(" Error: %d", gMessageSystem->getErrorCode())); - LLAppViewer::instance()->earlyExit(msg); + std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().insert("DIAGNOSTIC", diagnostic)); } #if LL_WINDOWS @@ -525,7 +525,7 @@ bool idle_startup() } else { - LLAppViewer::instance()->earlyExit("Message Template " + message_template_path + " not found."); + LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().insert("PATH", message_template_path)); } if(gMessageSystem && gMessageSystem->isOK()) @@ -1551,9 +1551,9 @@ bool idle_startup() exit(0); } // Bounce back to the login screen. - LLStringUtil::format_map_t args; - args["[ERROR_MESSAGE]"] = emsg.str(); - gViewerWindow->alertXml("ErrorMessage", args, login_alert_done); + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LLNotifications::instance().add("ErrorMessage", args, LLSD(), login_alert_done); reset_login(); gSavedSettings.setBOOL("AutoLogin", FALSE); show_connect_box = true; @@ -1571,9 +1571,9 @@ bool idle_startup() exit(0); } // Bounce back to the login screen. - LLStringUtil::format_map_t args; - args["[ERROR_MESSAGE]"] = emsg.str(); - gViewerWindow->alertXml("ErrorMessage", args, login_alert_done); + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LLNotifications::instance().add("ErrorMessage", args, LLSD(), login_alert_done); reset_login(); gSavedSettings.setBOOL("AutoLogin", FALSE); show_connect_box = true; @@ -2300,23 +2300,23 @@ bool idle_startup() // location is not your expected location. So, if this is // your first login, then you do not have an expectation, // thus, do not show this alert. - LLStringUtil::format_map_t args; + LLSD args; if (url_ok) { - args["[TYPE]"] = "desired"; - args["[HELP]"] = ""; + args["TYPE"] = "desired"; + args["HELP"] = ""; } else if (gSavedSettings.getBOOL("LoginLastLocation")) { - args["[TYPE]"] = "last"; - args["[HELP]"] = ""; + args["TYPE"] = "last"; + args["HELP"] = ""; } else { - args["[TYPE]"] = "home"; - args["[HELP]"] = "You may want to set a new home location."; + args["TYPE"] = "home"; + args["HELP"] = "You may want to set a new home location."; } - gViewerWindow->alertXml("AvatarMoved", args); + LLNotifications::instance().add("AvatarMoved", args); } else { @@ -2411,16 +2411,15 @@ bool idle_startup() // initial outfit, but if the load hasn't started // already then something is wrong so fall back // to generic outfits. JC - gViewerWindow->alertXml("WelcomeChooseSex", - callback_choose_gender, NULL); + LLNotifications::instance().add("WelcomeChooseSex", LLSD(), LLSD(), + callback_choose_gender); LLStartUp::setStartupState( STATE_CLEANUP ); return TRUE; } if (wearables_time > MAX_WEARABLES_TIME) { - // It's taken too long to load, show the world - gViewerWindow->alertXml("ClothingLoading"); + LLNotifications::instance().add("ClothingLoading"); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG); LLStartUp::setStartupState( STATE_CLEANUP ); return TRUE; @@ -2440,7 +2439,7 @@ bool idle_startup() else { // OK to just get the wearables - if ( gAgent.getWearablesLoaded() ) + if ( gAgent.areWearablesLoaded() ) { // We have our clothing, proceed. //llinfos << "wearables loaded" << llendl; @@ -2722,11 +2721,12 @@ bool is_hex_string(U8* str, S32 len) void show_first_run_dialog() { - gViewerWindow->alertXml("FirstRun", first_run_dialog_callback, NULL); + LLNotifications::instance().add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); } -void first_run_dialog_callback(S32 option, void* userdata) +bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; @@ -2734,6 +2734,7 @@ void first_run_dialog_callback(S32 option, void* userdata) } LLPanelLogin::giveFocus(); + return false; } @@ -2746,8 +2747,9 @@ void set_startup_status(const F32 frac, const std::string& string, const std::st gViewerWindow->setProgressMessage(msg); } -void login_alert_status(S32 option, void* user_data) +bool login_alert_status(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); // Buttons switch( option ) { @@ -2766,6 +2768,7 @@ void login_alert_status(S32 option, void* user_data) } LLPanelLogin::giveFocus(); + return false; } void update_app(BOOL mandatory, const std::string& auth_msg) @@ -2781,67 +2784,66 @@ void update_app(BOOL mandatory, const std::string& auth_msg) { msg = "(" + auth_msg + ") \n"; } - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = msg; - - // represent a bool as a null/non-null pointer - void *mandatoryp = mandatory ? &mandatory : NULL; + LLSD args; + args["MESSAGE"] = msg; + + LLSD payload; + payload["mandatory"] = mandatory; + +/* + We're constructing one of the following 6 strings here: + "DownloadWindowsMandatory" + "DownloadWindowsReleaseForDownload" + "DownloadWindows" + "DownloadMacMandatory" + "DownloadMacReleaseForDownload" + "DownloadMac" + + I've called them out explicitly in this comment so that they can be grepped for. + + Also, we assume that if we're not Windows we're Mac. If we ever intend to support + Linux with autoupdate, this should be an explicit #elif LL_DARWIN, but + we'd rather deliver the wrong message than no message, so until Linux is supported + we'll leave it alone. + */ + std::string notification_name = "Download"; + #if LL_WINDOWS - if (mandatory) - { - gViewerWindow->alertXml("DownloadWindowsMandatory", args, - update_dialog_callback, - mandatoryp); - } - else - { -#if LL_RELEASE_FOR_DOWNLOAD - gViewerWindow->alertXml("DownloadWindowsReleaseForDownload", args, - update_dialog_callback, - mandatoryp); + notification_name += "Windows"; #else - gViewerWindow->alertXml("DownloadWindows", args, - update_dialog_callback, - mandatoryp); + notification_name += "Mac"; #endif - } -#else + if (mandatory) { - gViewerWindow->alertXml("DownloadMacMandatory", args, - update_dialog_callback, - mandatoryp); + notification_name += "Mandatory"; } else { #if LL_RELEASE_FOR_DOWNLOAD - gViewerWindow->alertXml("DownloadMacReleaseForDownload", args, - update_dialog_callback, - mandatoryp); -#else - gViewerWindow->alertXml("DownloadMac", args, - update_dialog_callback, - mandatoryp); + notification_name += "ReleaseForDownload"; #endif } -#endif - + + LLNotifications::instance().add(notification_name, args, payload, update_dialog_callback); + } - -void update_dialog_callback(S32 option, void *userdata) +bool update_dialog_callback(const LLSD& notification, const LLSD& response) { - bool mandatory = userdata != NULL; + S32 option = LLNotification::getSelectedOption(notification, response); + std::string update_exe_path; + bool mandatory = notification["payload"]["mandatory"].asBoolean(); #if !LL_RELEASE_FOR_DOWNLOAD if (option == 2) { LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); - return; + return false; } #endif - + if (option == 1) { // ...user doesn't want to do it @@ -2855,7 +2857,7 @@ void update_dialog_callback(S32 option, void *userdata) { LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); } - return; + return false; } LLSD query_map = LLSD::emptyMap(); @@ -2890,7 +2892,7 @@ void update_dialog_callback(S32 option, void *userdata) // We're hosed, bail LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL; LLAppViewer::instance()->forceQuit(); - return; + return false; } LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe"; @@ -2911,7 +2913,7 @@ void update_dialog_callback(S32 option, void *userdata) LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL; LLAppViewer::instance()->forceQuit(); - return; + return false; } // if a sim name was passed in via command line parameter (typically through a SLURL) @@ -2955,6 +2957,7 @@ void update_dialog_callback(S32 option, void *userdata) LLStringUtil::null, OSMB_OK); #endif LLAppViewer::instance()->forceQuit(); + return false; } void use_circuit_callback(void**, S32 result) @@ -2968,8 +2971,7 @@ void use_circuit_callback(void**, S32 result) { // Make sure user knows something bad happened. JC LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - gViewerWindow->alertXml("LoginPacketNeverReceived", - login_alert_status, NULL); + LLNotifications::instance().add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); reset_login(); } else @@ -3753,8 +3755,9 @@ const S32 OPT_CLOSED_WINDOW = -1; const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; -void callback_choose_gender(S32 option, void* userdata) -{ +bool callback_choose_gender(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case OPT_MALE: @@ -3767,6 +3770,7 @@ void callback_choose_gender(S32 option, void* userdata) LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" ); break; } + return false; } void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, @@ -3809,8 +3813,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, // This is really misnamed -- it means we have started loading // an outfit/shape that will give the avatar a gender eventually. JC gAgent.setGenderChosen(TRUE); + } - // Loads a bitmap to display during load // location_id = 0 => last position @@ -3990,9 +3994,10 @@ bool LLStartUp::dispatchURL() return false; } -void login_alert_done(S32 option, void* user_data) +bool login_alert_done(const LLSD& notification, const LLSD& response) { LLPanelLogin::giveFocus(); + return false; } diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 1639ed55b6..f89642aa2a 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -38,7 +38,7 @@ bool idle_startup(); std::string load_password_from_disk(); void release_start_screen(); -void login_alert_done(S32 option, void* user_data); +bool login_alert_done(const LLSD& notification, const LLSD& response); // constants, variables, & enumerations extern std::string SCREEN_HOME_FILENAME; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 278f7ea9d1..8b274a045b 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -767,7 +767,7 @@ static void onClickBuyCurrency(void* data) static void onClickHealth(void* ) { - LLNotifyBox::showXml("NotSafe"); + LLNotifications::instance().add("NotSafe"); } static void onClickScriptDebug(void*) @@ -777,22 +777,22 @@ static void onClickScriptDebug(void*) static void onClickFly(void* ) { - LLNotifyBox::showXml("NoFly"); + LLNotifications::instance().add("NoFly"); } static void onClickPush(void* ) { - LLNotifyBox::showXml("PushRestricted"); + LLNotifications::instance().add("PushRestricted"); } static void onClickVoice(void* ) { - LLNotifyBox::showXml("NoVoice"); + LLNotifications::instance().add("NoVoice"); } static void onClickBuild(void*) { - LLNotifyBox::showXml("NoBuild"); + LLNotifications::instance().add("NoBuild"); } static void onClickScripts(void*) @@ -800,15 +800,15 @@ static void onClickScripts(void*) LLViewerRegion* region = gAgent.getRegion(); if(region && region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS) { - LLNotifyBox::showXml("ScriptsStopped"); + LLNotifications::instance().add("ScriptsStopped"); } else if(region && region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) { - LLNotifyBox::showXml("ScriptsNotRunning"); + LLNotifications::instance().add("ScriptsNotRunning"); } else { - LLNotifyBox::showXml("NoOutsideScripts"); + LLNotifications::instance().add("NoOutsideScripts"); } } diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index d7db0f85d9..b9235a489a 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -307,7 +307,10 @@ void LLToolBar::refresh() } gSavedSettings.setBOOL("BuildBtnState", build_mode); - updateCommunicateList(); + if (isInVisibleChain()) + { + updateCommunicateList(); + } } void LLToolBar::updateCommunicateList() @@ -444,7 +447,7 @@ void LLToolBar::onClickChat(void* user_data) // static void LLToolBar::onClickAppearance(void*) { - if (gAgent.getWearablesLoaded()) + if (gAgent.areWearablesLoaded()) { gAgent.changeCameraToCustomizeAvatar(); } diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp index 6bdd4e7767..92233c0d9f 100644 --- a/indra/newview/lltoolbrush.cpp +++ b/indra/newview/lltoolbrush.cpp @@ -648,9 +648,9 @@ void LLToolBrushLand::alertNoTerraform(LLViewerRegion* regionp) { if (!regionp) return; - LLStringUtil::format_map_t args; - args["[REGION]"] = regionp->getName(); - gViewerWindow->alertXml("RegionNoTerraforming", args); + LLSD args; + args["REGION"] = regionp->getName(); + LLNotifications::instance().add("RegionNoTerraforming", args); } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 25b58e1409..7459a23bef 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1052,9 +1052,9 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj, if (hit_obj->isInventoryDirty()) { hit_obj->fetchInventoryFromServer(); - LLStringUtil::format_map_t args; - args["[ERROR_MESSAGE]"] = "Unable to add texture.\nPlease wait a few seconds and try again."; - gViewerWindow->alertXml("ErrorMessage", args); + LLSD args; + args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again."; + LLNotifications::instance().add("ErrorMessage", args); return FALSE; } if (hit_obj->getInventoryItemByAsset(item->getAssetUUID())) @@ -1505,45 +1505,42 @@ void LLToolDragAndDrop::giveInventory(const LLUUID& to_agent, else { // ask if the agent is sure. - LLGiveInventoryInfo* info = new LLGiveInventoryInfo(to_agent, - item->getUUID(), - im_session_id); - - gViewerWindow->alertXml("CannotCopyWarning", - &LLToolDragAndDrop::handleCopyProtectedItem, - (void*)info); + LLSD payload; + payload["agent_id"] = to_agent; + payload["item_id"] = item->getUUID(); + LLNotifications::instance().add("CannotCopyWarning", LLSD(), payload, + &LLToolDragAndDrop::handleCopyProtectedItem); } } - // static -void LLToolDragAndDrop::handleCopyProtectedItem(S32 option, void* data) +bool LLToolDragAndDrop::handleCopyProtectedItem(const LLSD& notification, const LLSD& response) { - LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data; + S32 option = LLNotification::getSelectedOption(notification, response); LLInventoryItem* item = NULL; switch(option) { case 0: // "Yes" - item = gInventory.getItem(info->mInventoryObjectID); + item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); if(item) { - LLToolDragAndDrop::commitGiveInventoryItem(info->mToAgentID, - item, - info->mIMSessionID); + LLToolDragAndDrop::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), + item); // delete it for now - it will be deleted on the server // quickly enough. - gInventory.deleteObject(info->mInventoryObjectID); + gInventory.deleteObject(notification["payload"]["item_id"].asUUID()); gInventory.notifyObservers(); } else { - gViewerWindow->alertXml("CannotGiveItem"); + LLNotifications::instance().add("CannotGiveItem"); } break; default: // no, cancel, whatever, who cares, not yes. - gViewerWindow->alertXml("TransactionCancelled"); + LLNotifications::instance().add("TransactionCancelled"); break; } + return false; } // static @@ -1592,7 +1589,7 @@ void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& 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) { - LLStringUtil::format_map_t args; + LLSD args; gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } @@ -1632,18 +1629,18 @@ void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, } if(!complete) { - LLNotifyBox::showXml("IncompleteInventory"); + LLNotifications::instance().add("IncompleteInventory"); return; } count = items.count() + cats.count(); if(count > MAX_ITEMS) { - gViewerWindow->alertXml("TooManyItems"); + LLNotifications::instance().add("TooManyItems"); return; } else if(count == 0) { - gViewerWindow->alertXml("NoItems"); + LLNotifications::instance().add("NoItems"); return; } else @@ -1656,29 +1653,29 @@ void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, { LLGiveInventoryInfo* info = NULL; info = new LLGiveInventoryInfo(to_agent, cat->getUUID()); - LLStringUtil::format_map_t args; - args["[COUNT]"] = llformat("%d",giveable.countNoCopy()); - gViewerWindow->alertXml("CannotCopyCountItems", args, - &LLToolDragAndDrop::handleCopyProtectedCategory, - (void*)info); - + LLSD args; + args["COUNT"] = llformat("%d",giveable.countNoCopy()); + LLSD payload; + payload["agent_id"] = to_agent; + payload["folder_id"] = cat->getUUID(); + LLNotifications::instance().add("CannotCopyCountItems", args, payload, &LLToolDragAndDrop::handleCopyProtectedCategory); } } } // static -void LLToolDragAndDrop::handleCopyProtectedCategory(S32 option, void* data) +bool LLToolDragAndDrop::handleCopyProtectedCategory(const LLSD& notification, const LLSD& response) { - LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data; + S32 option = LLNotification::getSelectedOption(notification, response); LLInventoryCategory* cat = NULL; switch(option) { case 0: // "Yes" - cat = gInventory.getCategory(info->mInventoryObjectID); + cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID()); if(cat) { - LLToolDragAndDrop::commitGiveInventoryCategory(info->mToAgentID, + LLToolDragAndDrop::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), cat); LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -1697,14 +1694,15 @@ void LLToolDragAndDrop::handleCopyProtectedCategory(S32 option, void* data) } else { - gViewerWindow->alertXml("CannotGiveCategory"); + LLNotifications::instance().add("CannotGiveCategory"); } break; default: // no, cancel, whatever, who cares, not yes. - gViewerWindow->alertXml("TransactionCancelled"); + LLNotifications::instance().add("TransactionCancelled"); break; } + return false; } // static @@ -1731,12 +1729,12 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, S32 count = items.count() + cats.count(); if(count > MAX_ITEMS) { - gViewerWindow->alertXml("TooManyItems"); + LLNotifications::instance().add("TooManyItems"); return; } else if(count == 0) { - gViewerWindow->alertXml("NoItems"); + LLNotifications::instance().add("NoItems"); return; } else @@ -2299,7 +2297,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( // destroy clothing items. if (!gAgent.areWearablesLoaded()) { - gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded"); + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return ACCEPT_NO; } @@ -2394,7 +2392,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( // destroy clothing items. if (!gAgent.areWearablesLoaded()) { - gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded"); + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return ACCEPT_NO; } } diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 627ef86c38..462e57b390 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -209,13 +209,13 @@ protected: // give inventory item functionality - static void handleCopyProtectedItem(S32 option, void* data); + static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response); static void commitGiveInventoryItem(const LLUUID& to_agent, LLInventoryItem* item, const LLUUID &im_session_id = LLUUID::null); // give inventory category functionality - static void handleCopyProtectedCategory(S32 option, void* data); + static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response); static void commitGiveInventoryCategory(const LLUUID& to_agent, LLInventoryCategory* cat); public: diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 477146a473..3f6227ee56 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -43,7 +43,6 @@ #include "llpanellogin.h" #include "llstartup.h" // gStartupState #include "llurlsimstring.h" -#include "llviewerwindow.h" // alertXml() #include "llweb.h" #include "llworldmap.h" @@ -147,8 +146,8 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, /* // Inform the user we can't handle this std::map<std::string, std::string> args; - args["[SLURL]"] = url; - gViewerWindow->alertXml("BadURL", args); + args["SLURL"] = url; + r; */ return false; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index c28ed7c435..e52b3a9b83 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -403,7 +403,7 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const // communicate that change with the server. if(LLAssetType::AT_NONE != mPreferredType) { - LLNotifyBox::showXml("CannotModifyProtectedCategories"); + LLNotifications::instance().add("CannotModifyProtectedCategories"); return; } @@ -427,7 +427,7 @@ void LLViewerInventoryCategory::removeFromServer( void ) // communicate that change with the server. if(LLAssetType::AT_NONE != mPreferredType) { - LLNotifyBox::showXml("CannotRemoveProtectedCategories"); + LLNotifications::instance().add("CannotRemoveProtectedCategories"); return; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c8ad7fad97..5131b77a7c 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1,3 +1,4 @@ + /** * @file llviewermenu.cpp * @brief Builds menus out of items. @@ -309,7 +310,7 @@ BOOL is_selection_buy_not_take(); S32 selection_price(); BOOL enable_take(); void handle_take(); -void confirm_take(S32 option, void* data); +bool confirm_take(const LLSD& notification, const LLSD& response); BOOL enable_buy(void*); void handle_buy(void *); void handle_buy_object(LLSaleInfo sale_info); @@ -999,6 +1000,7 @@ void init_debug_world_menu(LLMenuGL* menu) void handle_export_menus_to_xml(void*) { + LLFilePicker& picker = LLFilePicker::instance(); if(!picker.getSaveFile(LLFilePicker::FFSAVE_XML)) { @@ -2122,9 +2124,10 @@ class LLGoToObject : public view_listener_t //--------------------------------------------------------------------------- // Parcel freeze, eject, etc. //--------------------------------------------------------------------------- -void callback_freeze(S32 option, void* data) +bool callback_freeze(const LLSD& notification, const LLSD& response) { - LLUUID* avatar_id = (LLUUID*) data; + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option || 1 == option) { @@ -2136,7 +2139,7 @@ void callback_freeze(S32 option, void* data) } LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(*avatar_id); + LLViewerObject* avatar = gObjectList.findObject(avatar_id); if (avatar) { @@ -2145,16 +2148,15 @@ void callback_freeze(S32 option, void* data) msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->nextBlock("Data"); - msg->addUUID("TargetID", *avatar_id ); + msg->addUUID("TargetID", avatar_id ); msg->addU32("Flags", flags ); msg->sendReliable( avatar->getRegion()->getHost() ); } } - - delete avatar_id; - avatar_id = NULL; + return false; } + class LLAvatarFreeze : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) @@ -2162,23 +2164,25 @@ class LLAvatarFreeze : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if( avatar ) { - LLUUID* avatar_id = new LLUUID( avatar->getID() ); std::string fullname = avatar->getFullname(); + LLSD payload; + payload["avatar_id"] = avatar->getID(); if (!fullname.empty()) { - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = fullname; - gViewerWindow->alertXml("FreezeAvatarFullname", + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotifications::instance().add("FreezeAvatarFullname", args, - callback_freeze, - (void*)avatar_id); + payload, + callback_freeze); } else { - gViewerWindow->alertXml("FreezeAvatar", - callback_freeze, - (void*)avatar_id); + LLNotifications::instance().add("FreezeAvatar", + LLSD(), + payload, + callback_freeze); } } return true; @@ -2224,26 +2228,16 @@ class LLAvatarDebug : public view_listener_t } }; -struct MenuCallbackData +bool callback_eject(const LLSD& notification, const LLSD& response) { - bool ban_enabled; - LLUUID avatar_id; -}; - -void callback_eject(S32 option, void* data) -{ - MenuCallbackData *callback_data = (MenuCallbackData*)data; - if (!callback_data) - { - return; - } + S32 option = LLNotification::getSelectedOption(notification, response); if (2 == option) { - // Cancle button. - return; + // Cancel button. + return false; } - LLUUID avatar_id = callback_data->avatar_id; - bool ban_enabled = callback_data->ban_enabled; + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); if (0 == option) { @@ -2285,10 +2279,7 @@ void callback_eject(S32 option, void* data) msg->sendReliable( avatar->getRegion()->getHost() ); } } - - - delete callback_data; - callback_data = NULL; + return false; } class LLAvatarEject : public view_listener_t @@ -2298,8 +2289,8 @@ class LLAvatarEject : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if( avatar ) { - MenuCallbackData *data = new MenuCallbackData; - (*data).avatar_id = avatar->getID(); + LLSD payload; + payload["avatar_id"] = avatar->getID(); std::string fullname = avatar->getFullname(); const LLVector3d& pos = avatar->getPositionGlobal(); @@ -2307,40 +2298,42 @@ class LLAvatarEject : public view_listener_t if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) { - (*data).ban_enabled = true; + payload["ban_enabled"] = true; if (!fullname.empty()) { - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = fullname; - gViewerWindow->alertXml("EjectAvatarFullname", - args, - callback_eject, - (void*)data); + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotifications::instance().add("EjectAvatarFullname", + args, + payload, + callback_eject); } else { - gViewerWindow->alertXml("EjectAvatar", - callback_eject, - (void*)data); + LLNotifications::instance().add("EjectAvatarFullname", + LLSD(), + payload, + callback_eject); } } else { - (*data).ban_enabled = false; + payload["ban_enabled"] = false; if (!fullname.empty()) { - LLStringUtil::format_map_t args; - args["[AVATAR_NAME]"] = fullname; - gViewerWindow->alertXml("EjectAvatarFullnameNoBan", - args, - callback_eject, - (void*)data); + LLSD args; + args["AVATAR_NAME"] = fullname; + LLNotifications::instance().add("EjectAvatarFullnameNoBan", + args, + payload, + callback_eject); } else { - gViewerWindow->alertXml("EjectAvatarNoBan", - callback_eject, - (void*)data); + LLNotifications::instance().add("EjectAvatarNoBan", + LLSD(), + payload, + callback_eject); } } } @@ -2387,13 +2380,16 @@ class LLAvatarGiveCard : public view_listener_t if(dest && dest->isAvatar()) { bool found_name = false; - LLStringUtil::format_map_t args; + LLSD args; + LLSD old_args; LLNameValue* nvfirst = dest->getNVPair("FirstName"); LLNameValue* nvlast = dest->getNVPair("LastName"); if(nvfirst && nvlast) { - args["[FIRST]"] = nvfirst->getString(); - args["[LAST]"] = nvlast->getString(); + args["FIRST"] = nvfirst->getString(); + args["LAST"] = nvlast->getString(); + old_args["FIRST"] = nvfirst->getString(); + old_args["LAST"] = nvlast->getString(); found_name = true; } LLViewerRegion* region = dest->getRegion(); @@ -2415,11 +2411,11 @@ class LLAvatarGiveCard : public view_listener_t transaction_id.generate(); msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); msg->sendReliable(dest_host); - LLNotifyBox::showXml("OfferedCard", args); + LLNotifications::instance().add("OfferedCard", args); } else { - gViewerWindow->alertXml("CantOfferCallingCard", args); + LLNotifications::instance().add("CantOfferCallingCard", old_args); } } return true; @@ -2436,8 +2432,9 @@ void login_done(S32 which, void *user) } -void callback_leave_group(S32 option, void *userdata) +bool callback_leave_group(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { LLMessageSystem *msg = gMessageSystem; @@ -2450,15 +2447,16 @@ void callback_leave_group(S32 option, void *userdata) msg->addUUIDFast(_PREHASH_GroupID, gAgent.mGroupID ); gAgent.sendReliableMessage(); } + return false; } void handle_leave_group(void *) { if (gAgent.getGroupID() != LLUUID::null) { - LLStringUtil::format_map_t args; - args["[GROUP]"] = gAgent.mGroupName; - gViewerWindow->alertXml("GroupLeaveConfirmMember", args, callback_leave_group); + LLSD args; + args["GROUP"] = gAgent.mGroupName; + LLNotifications::instance().add("GroupLeaveConfirmMember", args, LLSD(), callback_leave_group); } } @@ -2521,7 +2519,7 @@ void handle_buy_object(LLSaleInfo sale_info) { if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) { - LLNotifyBox::showXml("UnableToBuyWhileDownloading"); + LLNotifications::instance().add("UnableToBuyWhileDownloading"); return; } @@ -2530,7 +2528,7 @@ void handle_buy_object(LLSaleInfo sale_info) BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); if (!owners_identical) { - LLNotifyBox::showXml("CannotBuyObjectsFromDifferentOwners"); + LLNotifications::instance().add("CannotBuyObjectsFromDifferentOwners"); return; } @@ -2540,7 +2538,7 @@ void handle_buy_object(LLSaleInfo sale_info) valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) { - LLNotifyBox::showXml("ObjectNotForSale"); + LLNotifications::instance().add("ObjectNotForSale"); return; } @@ -2686,22 +2684,22 @@ void set_god_level(U8 god_level) // inventory in items may change in god mode gObjectList.dirtyAllObjectInventory(); - if(gViewerWindow) - { - gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, + if(gViewerWindow) + { + gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, LLViewerLogin::getInstance()->isInProductionGrid()); - } - - LLStringUtil::format_map_t args; + } + + LLSD args; if(god_level > GOD_NOT) { - args["[LEVEL]"] = llformat("%d",(S32)god_level); - LLNotifyBox::showXml("EnteringGodMode", args); + args["LEVEL"] = llformat("%d",(S32)god_level); + LLNotifications::instance().add("EnteringGodMode", args); } else { - args["[LEVEL]"] = llformat("%d",(S32)old_god_level); - LLNotifyBox::showXml("LeavingGodMode", args); + args["LEVEL"] = llformat("%d",(S32)old_god_level); + LLNotifications::instance().add("LeavingGodMode", args); } @@ -2826,13 +2824,13 @@ void request_friendship(const LLUUID& dest_id) if(dest && dest->isAvatar()) { std::string fullname; - LLStringUtil::format_map_t args; + LLSD args; LLNameValue* nvfirst = dest->getNVPair("FirstName"); LLNameValue* nvlast = dest->getNVPair("LastName"); if(nvfirst && nvlast) { - args["[FIRST]"] = nvfirst->getString(); - args["[LAST]"] = nvlast->getString(); + args["FIRST"] = nvfirst->getString(); + args["LAST"] = nvlast->getString(); fullname = nvfirst->getString(); fullname += " "; fullname += nvlast->getString(); @@ -2843,7 +2841,7 @@ void request_friendship(const LLUUID& dest_id) } else { - gViewerWindow->alertXml("CantOfferFriendship"); + LLNotifications::instance().add("CantOfferFriendship"); } } } @@ -2853,12 +2851,8 @@ class LLEditEnableCustomizeAvatar : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); - - bool enabled = ((avatar && avatar->isFullyLoaded()) && - (gAgent.getWearablesLoaded())); - - gMenuHolder->findControl(userdata["control"].asString())->setValue(enabled); + bool new_value = gAgent.areWearablesLoaded(); + gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; @@ -3184,7 +3178,7 @@ void disabled_duplicate(void*) { if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) { - LLNotifyBox::showXml("CopyFailed"); + LLNotifications::instance().add("CopyFailed"); } } @@ -3317,7 +3311,7 @@ void handle_claim_public_land(void*) { if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) { - LLNotifyBox::showXml("ClaimPublicLand"); + LLNotifications::instance().add("ClaimPublicLand"); return; } @@ -3550,7 +3544,7 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) } else if(!error.empty()) { - gViewerWindow->alertXml(error); + LLNotifications::instance().add(error); } } @@ -3577,16 +3571,13 @@ class LLObjectReturn : public view_listener_t mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - gViewerWindow->alertXml("ReturnToOwner", - onReturnToOwner, - (void*)this); + LLNotifications::instance().add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); return true; } - static void onReturnToOwner(S32 option, void* data) + bool onReturnToOwner(const LLSD& notification, const LLSD& response) { - LLObjectReturn* object_return = (LLObjectReturn*)data; - + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { // Ignore category ID for this derez destination. @@ -3594,7 +3585,8 @@ class LLObjectReturn : public view_listener_t } // drop reference to current selection - object_return->mObjectSelection = NULL; + mObjectSelection = NULL; + return false; } protected: @@ -3731,48 +3723,46 @@ void handle_take() { category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT); } - LLUUID* cat_id = new LLUUID(category_id); + LLSD payload; + payload["folder_id"] = category_id; + + LLNotification::Params params("ConfirmObjectTakeLock"); + params.payload(payload) + .functor(confirm_take); + if(locked_but_takeable_object || !you_own_everything) { if(locked_but_takeable_object && you_own_everything) { - gViewerWindow->alertXml("ConfirmObjectTakeLock", - confirm_take, - (void*)cat_id); + params.name("ConfirmObjectTakeLock"); } else if(!locked_but_takeable_object && !you_own_everything) { - gViewerWindow->alertXml("ConfirmObjectTakeNoOwn", - confirm_take, - (void*)cat_id); + params.name("ConfirmObjectTakeNoOwn"); } else { - gViewerWindow->alertXml("ConfirmObjectTakeLockNoOwn", - confirm_take, - (void*)cat_id); + params.name("ConfirmObjectTakeLockNoOwn"); } - - + + LLNotifications::instance().add(params); } - else { - confirm_take(0, (void*)cat_id); + LLNotifications::instance().forceResponse(params, 0); } } -void confirm_take(S32 option, void* data) +bool confirm_take(const LLSD& notification, const LLSD& response) { - LLUUID* cat_id = (LLUUID*)data; - if(!cat_id) return; + S32 option = LLNotification::getSelectedOption(notification, response); if(enable_take() && (option == 0)) { - derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, *cat_id); + derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); } - delete cat_id; + return false; } // You can take an item when it is public and transferrable, or when @@ -3934,13 +3924,15 @@ S32 selection_price() return total_price; } -void callback_show_buy_currency(S32 option, void*) +bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { llinfos << "Loading page " << BUY_CURRENCY_URL << llendl; LLWeb::loadURL(BUY_CURRENCY_URL); } + return false; } @@ -3955,14 +3947,13 @@ void show_buy_currency(const char* extra) } mesg << "Go to " << BUY_CURRENCY_URL << "\nfor information on purchasing currency?"; - LLStringUtil::format_map_t args; + LLSD args; if (extra != NULL) { - args["[EXTRA]"] = extra; + args["EXTRA"] = extra; } - args["[URL]"] = BUY_CURRENCY_URL; - gViewerWindow->alertXml("PromptGoToCurrencyPage", args, - callback_show_buy_currency); + args["URL"] = BUY_CURRENCY_URL; + LLNotifications::instance().add("PromptGoToCurrencyPage", args, LLSD(), callback_show_buy_currency); } void handle_buy_currency(void*) @@ -4142,29 +4133,29 @@ class LLToolsLink : public view_listener_t { if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) { - LLNotifyBox::showXml("UnableToLinkWhileDownloading"); + LLNotifications::instance().add("UnableToLinkWhileDownloading"); return true; } S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); if (object_count > MAX_CHILDREN_PER_TASK + 1) { - LLStringUtil::format_map_t args; - args["[COUNT]"] = llformat("%d", object_count); + LLSD args; + args["COUNT"] = llformat("%d", object_count); int max = MAX_CHILDREN_PER_TASK+1; - args["[MAX]"] = llformat("%d", max); - gViewerWindow->alertXml("UnableToLinkObjects", args); + args["MAX"] = llformat("%d", max); + LLNotifications::instance().add("UnableToLinkObjects", args); return true; } if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2) { - gViewerWindow->alertXml("CannotLinkIncompleteSet"); + LLNotifications::instance().add("CannotLinkIncompleteSet"); return true; } if(!LLSelectMgr::getInstance()->selectGetRootsModify()) { - gViewerWindow->alertXml("CannotLinkModify"); + LLNotifications::instance().add("CannotLinkModify"); return true; } LLUUID owner_id; @@ -4174,7 +4165,7 @@ class LLToolsLink : public view_listener_t // we don't actually care if you're the owner, but novices are // the most likely to be stumped by this one, so offer the // easiest and most likely solution. - gViewerWindow->alertXml("CannotLinkDifferentOwners"); + LLNotifications::instance().add("CannotLinkDifferentOwners"); return true; } LLSelectMgr::getInstance()->sendLink(); @@ -4738,7 +4729,7 @@ class LLWorldSetBusy : public view_listener_t else { gAgent.setBusy(); - gViewerWindow->alertXml("BusyModeSet"); + LLNotifications::instance().add("BusyModeSet"); } return true; } @@ -4764,7 +4755,7 @@ class LLWorldCreateLandmark : public view_listener_t if (!agent_parcel->getAllowLandmark() && !LLViewerParcelMgr::isParcelOwnedByAgent(agent_parcel, GP_LAND_ALLOW_LANDMARK)) { - gViewerWindow->alertXml("CannotCreateLandmarkNotOwner"); + LLNotifications::instance().add("CannotCreateLandmarkNotOwner"); return true; } @@ -4871,16 +4862,14 @@ class LLAvatarAddFriend : public view_listener_t } }; -void complete_give_money(S32 option, void* user_data) +bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { gAgent.clearBusy(); } - LLObjectSelectionHandle handle(*(LLObjectSelectionHandle*)user_data); - delete (LLObjectSelectionHandle*)user_data; - LLViewerObject* objectp = handle->getPrimaryObject(); // Show avatar's name if paying attachment @@ -4906,19 +4895,22 @@ void complete_give_money(S32 option, void* user_data) LLFloaterPay::payViaObject(&give_money, objectp->getID()); } } + return false; } bool handle_give_money_dialog() { - LLObjectSelectionHandle* handlep = new LLObjectSelectionHandle(LLSelectMgr::getInstance()->getSelection()); + LLNotification::Params params("BusyModePay"); + params.functor(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + if (gAgent.getBusy()) { // warn users of being in busy mode during a transaction - gViewerWindow->alertXml("BusyModePay", complete_give_money, handlep); + LLNotifications::instance().add(params); } else { - complete_give_money(1, handlep); + LLNotifications::instance().forceResponse(params, 1); } return true; } @@ -5069,7 +5061,7 @@ class LLShowFloater : public view_listener_t } else if (floater_name == "appearance") { - if (gAgent.getWearablesLoaded()) + if (gAgent.areWearablesLoaded()) { gAgent.changeCameraToCustomizeAvatar(); } @@ -5272,14 +5264,14 @@ class LLFloaterVisible : public view_listener_t } }; -void callback_show_url(S32 option, void* data) +bool callback_show_url(const LLSD& notification, const LLSD& response) { - std::string* urlp = (std::string*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { - LLWeb::loadURL(*urlp); + LLWeb::loadURL(notification["payload"]["url"].asString()); } - delete urlp; + return false; } class LLPromptShowURL : public view_listener_t @@ -5292,15 +5284,16 @@ class LLPromptShowURL : public view_listener_t { std::string alert = param.substr(0, offset); std::string url = param.substr(offset+1); - std::string* url_copy = new std::string(url); if(gSavedSettings.getBOOL("UseExternalBrowser")) { - gViewerWindow->alertXml(alert, callback_show_url, url_copy); + LLSD payload; + payload["url"] = url; + LLNotifications::instance().add(alert, LLSD(), payload, callback_show_url); } else { - callback_show_url(0, url_copy); + LLWeb::loadURL(url); } } else @@ -5311,6 +5304,39 @@ class LLPromptShowURL : public view_listener_t } }; +bool callback_show_file(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (0 == option) + { + LLWeb::loadURL(notification["payload"]["url"]); + } + return false; +} + +class LLPromptShowFile : public view_listener_t +{ + bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) + { + std::string param = userdata.asString(); + std::string::size_type offset = param.find(","); + if (offset != param.npos) + { + std::string alert = param.substr(0, offset); + std::string file = param.substr(offset+1); + + LLSD payload; + payload["url"] = file; + LLNotifications::instance().add(alert, LLSD(), payload, callback_show_file); + } + else + { + llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl; + } + return true; + } +}; + class LLShowAgentProfile : public view_listener_t { bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) @@ -5940,11 +5966,11 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& noscriptmsg, cons { if ( !func.scripted ) { - gViewerWindow->alertXml(noscriptmsg); + LLNotifications::instance().add(noscriptmsg); } else if ( !func.modifiable ) { - gViewerWindow->alertXml(nomodmsg); + LLNotifications::instance().add(nomodmsg); } else { @@ -6933,7 +6959,7 @@ void handle_save_to_xml(void*) LLFloater* frontmost = gFloaterView->getFrontmost(); if (!frontmost) { - gViewerWindow->alertXml("NoFrontmostFloater"); + LLNotifications::instance().add("NoFrontmostFloater"); return; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 33c21b4061..5f42aff526 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -178,9 +178,9 @@ const std::string upload_pick(void* data) std::string short_name = gDirUtilp->getBaseFileName(filename); // No extension - LLStringUtil::format_map_t args; - args["[FILE]"] = short_name; - gViewerWindow->alertXml("NoFileExtension", args); + LLSD args; + args["FILE"] = short_name; + LLNotifications::instance().add("NoFileExtension", args); return std::string(); } else @@ -220,11 +220,11 @@ const std::string upload_pick(void* data) { //should only get here if the extension exists //but is invalid - LLStringUtil::format_map_t args; - args["[EXTENSION]"] = ext; - args["[VALIDS]"] = valid_extensions; - gViewerWindow->alertXml("InvalidFileExtension", args); - return std::string(); + LLSD args; + args["EXTENSION"] = ext; + args["VALIDS"] = valid_extensions; + LLNotifications::instance().add("InvalidFileExtension", args); + return NULL; } }//end else (non-null extension) @@ -239,9 +239,9 @@ const std::string upload_pick(void* data) if (check_for_invalid_wav_formats(filename,error_msg)) { llinfos << error_msg << ": " << filename << llendl; - LLStringUtil::format_map_t args; - args["[FILE]"] = filename; - gViewerWindow->alertXml( error_msg, args ); + LLSD args; + args["FILE"] = filename; + LLNotifications::instance().add( error_msg, args ); return std::string(); } }//end if a wave/sound file @@ -337,10 +337,10 @@ class LLFileUploadBulk : public view_listener_t } }; -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLStringUtil::format_map_t args) +void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { llwarns << error_message << llendl; - gViewerWindow->alertXml(label, args); + LLNotifications::instance().add(label, args); if(LLFile::remove(filename) == -1) { lldebugs << "unable to remove temp file" << llendl; @@ -531,10 +531,9 @@ void upload_new_resource(const std::string& src_filename, std::string name, LLTransactionID tid; LLAssetID uuid; - LLStringUtil::format_map_t args; + LLSD args; std::string exten = gDirUtilp->getExtension(src_filename); - LLAssetType::EType asset_type = LLAssetType::AT_NONE; std::string error_message; @@ -548,7 +547,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, error_message = llformat( "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", short_name.c_str()); - args["[FILE]"] = short_name; + args["FILE"] = short_name; upload_error(error_message, "NofileExtension", filename, args); return; } @@ -560,9 +559,9 @@ void upload_new_resource(const std::string& src_filename, std::string name, IMG_CODEC_BMP )) { error_message = llformat( "Problem with file %s:\n\n%s\n", - src_filename.c_str(), LLImage::getLastError().c_str()); - args["[FILE]"] = src_filename; - args["[ERROR]"] = LLImage::getLastError(); + src_filename.c_str(), LLImage::getLastError().c_str()); + args["FILE"] = src_filename; + args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } @@ -576,8 +575,8 @@ void upload_new_resource(const std::string& src_filename, std::string name, { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImage::getLastError().c_str()); - args["[FILE]"] = src_filename; - args["[ERROR]"] = LLImage::getLastError(); + args["FILE"] = src_filename; + args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } @@ -591,8 +590,8 @@ void upload_new_resource(const std::string& src_filename, std::string name, { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImage::getLastError().c_str()); - args["[FILE]"] = src_filename; - args["[ERROR]"] = LLImage::getLastError(); + args["FILE"] = src_filename; + args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } @@ -606,8 +605,8 @@ void upload_new_resource(const std::string& src_filename, std::string name, { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImage::getLastError().c_str()); - args["[FILE]"] = src_filename; - args["[ERROR]"] = LLImage::getLastError(); + args["FILE"] = src_filename; + args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } @@ -627,13 +626,13 @@ void upload_new_resource(const std::string& src_filename, std::string name, { case LLVORBISENC_DEST_OPEN_ERR: error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); - args["[FILE]"] = filename; + args["FILE"] = filename; upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); break; default: error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); - args["[FILE]"] = src_filename; + args["FILE"] = src_filename; upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); break; } @@ -675,7 +674,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { fclose(in); error_message = llformat("corrupt resource file: %s", src_filename.c_str()); - args["[FILE]"] = src_filename; + args["FILE"] = src_filename; upload_error(error_message, "CorruptResourceFile", filename, args); return; } @@ -703,7 +702,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { fclose(in); error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); - args["[FILE]"] = src_filename; + args["FILE"] = src_filename; upload_error(error_message, "UnknownResourceFileVersion", filename, args); return; } @@ -745,7 +744,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { fclose(in); error_message = llformat( "Unable to create output file: %s", filename.c_str()); - args["[FILE]"] = filename; + args["FILE"] = filename; upload_error(error_message, "UnableToCreateOutputFile", filename, args); return; } @@ -815,9 +814,9 @@ void upload_new_resource(const std::string& src_filename, std::string name, else { llwarns << error_message << llendl; - LLStringUtil::format_map_t args; - args["[ERROR_MESSAGE]"] = error_message; - gViewerWindow->alertXml("ErrorMessage", args); + LLSD args; + args["ERROR_MESSAGE"] = error_message; + LLNotifications::instance().add("ErrorMessage", args); if(LLFile::remove(filename) == -1) { lldebugs << "unable to remove temp file" << llendl; @@ -900,10 +899,10 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt } else // if(result >= 0) { - LLStringUtil::format_map_t args; - args["[FILE]"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["[REASON]"] = std::string(LLAssetStorage::getErrorString(result)); - gViewerWindow->alertXml("CannotUploadReason", args); + LLSD args; + args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); + args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); + LLNotifications::instance().add("CannotUploadReason", args); } LLUploadDialog::modalUploadFinished(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e38ef27cf1..daab3a7847 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -96,6 +96,7 @@ #include "llmenugl.h" #include "llmutelist.h" #include "llnetmap.h" +#include "llnotifications.h" #include "llnotify.h" #include "llpanelgrouplandmoney.h" #include "llselectmgr.h" @@ -157,7 +158,6 @@ extern BOOL gDebugClicks; // function prototypes void open_offer(const std::vector<LLUUID>& items, const std::string& from_name); -void friendship_offer_callback(S32 option, void* user_data); bool check_offer_throttle(const std::string& from_name, bool check_only); void callbackCacheEstateOwnerName(const LLUUID& id, const std::string& first, const std::string& last, @@ -184,14 +184,66 @@ const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = "ControlYourCamera" }; -struct LLFriendshipOffer +const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = { - LLUUID mFromID; - LLUUID mTransactionID; - BOOL mOnline; - LLHost mHost; + TRUE, // ScriptTakeMoney, + FALSE, // ActOnControlInputs + FALSE, // RemapControlInputs + FALSE, // AnimateYourAvatar + FALSE, // AttachToYourAvatar + FALSE, // ReleaseOwnership, + FALSE, // LinkAndDelink, + FALSE, // AddAndRemoveJoints + FALSE, // ChangePermissions + FALSE, // TrackYourCamera, + FALSE // ControlYourCamera }; +bool friendship_offer_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLUUID fid; + LLMessageSystem* msg = gMessageSystem; + const LLSD& payload = notification["payload"]; + switch(option) + { + case 0: + // accept + LLAvatarTracker::formFriendship(payload["from_id"]); + + fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + + // This will also trigger an onlinenotification if the user is online + msg->newMessageFast(_PREHASH_AcceptFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(payload["sender"].asString())); + break; + case 1: + // decline + msg->newMessageFast(_PREHASH_DeclineFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->sendReliable(LLHost(payload["sender"].asString())); + break; + default: + // close button probably, possibly timed out + break; + } + + return false; +} +static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); +static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); + //const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have " // "requested not to be disturbed. Your message will still be shown in their IM " // "panel for later viewing."; @@ -563,34 +615,31 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) gAgent.sendMessage(); } -struct LLJoinGroupData -{ - LLUUID mGroupID; - LLUUID mTransactionID; - std::string mName; - std::string mMessage; - S32 mFee; -}; - -void join_group_callback(S32 option, void* user_data) +bool join_group_response(const LLSD& notification, const LLSD& response) { - LLJoinGroupData* data = (LLJoinGroupData*)user_data; + S32 option = LLNotification::getSelectedOption(notification, response); BOOL delete_context_data = TRUE; bool accept_invite = false; - if (option == 2 && data && !data->mGroupID.isNull()) + LLUUID group_id = notification["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID(); + std::string name = notification["payload"]["name"].asString(); + std::string message = notification["payload"]["message"].asString(); + S32 fee = notification["payload"]["fee"].asInteger(); + + if (option == 2 && !group_id.isNull()) { - LLFloaterGroupInfo::showFromUUID(data->mGroupID); - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = data->mMessage; - LLNotifyBox::showXml("JoinGroup", args, &join_group_callback, data); - return; + LLFloaterGroupInfo::showFromUUID(group_id); + LLSD args; + args["MESSAGE"] = message; + LLNotifications::instance().add("JoinGroup", args, notification["payload"]); + return false; } - if(option == 0 && data && !data->mGroupID.isNull()) + if(option == 0 && !group_id.isNull()) { // check for promotion or demotion. S32 max_groups = MAX_AGENT_GROUPS; - if(gAgent.isInGroup(data->mGroupID)) ++max_groups; + if(gAgent.isInGroup(group_id)) ++max_groups; if(gAgent.mGroups.count() < max_groups) { @@ -599,10 +648,10 @@ void join_group_callback(S32 option, void* user_data) else { delete_context_data = FALSE; - LLStringUtil::format_map_t args; - args["[NAME]"] = data->mName; - args["[INVITE]"] = data->mMessage; - LLAlertDialog::showXml("JoinedTooManyGroupsMember", args, join_group_callback, (void*)data); + LLSD args; + args["NAME"] = name; + args["INVITE"] = message; + LLNotifications::instance().add("JoinedTooManyGroupsMember", args, notification["payload"]); } } @@ -610,45 +659,44 @@ void join_group_callback(S32 option, void* user_data) { // If there is a fee to join this group, make // sure the user is sure they want to join. - if (data->mFee > 0) + if (fee > 0) { delete_context_data = FALSE; - LLStringUtil::format_map_t args; - args["[COST]"] = llformat("%d", data->mFee); - // Set the fee to 0, so that we don't keep + LLSD args; + args["COST"] = llformat("%d", fee); + // Set the fee for next time to 0, so that we don't keep // asking about a fee. - data->mFee = 0; - gViewerWindow->alertXml("JoinGroupCanAfford", + LLSD next_payload = notification["payload"]; + next_payload["fee"] = 0; + LLNotifications::instance().add("JoinGroupCanAfford", args, - join_group_callback, - (void*)data); + next_payload); } else { - send_improved_im(data->mGroupID, + send_improved_im(group_id, std::string("name"), std::string("message"), IM_ONLINE, IM_GROUP_INVITATION_ACCEPT, - data->mTransactionID); + transaction_id); } } - else if (data) + else { - send_improved_im(data->mGroupID, + send_improved_im(group_id, std::string("name"), std::string("message"), IM_ONLINE, IM_GROUP_INVITATION_DECLINE, - data->mTransactionID); + transaction_id); } - if(delete_context_data) - { - delete data; - data = NULL; - } + return false; } +static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); +static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response); +static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response); //----------------------------------------------------------------------------- @@ -930,9 +978,15 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, { public: OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - BOOL matches(LLNotifyBox::notify_callback_t callback, void* cb_data) const + BOOL matches(const LLNotificationPtr notification) const { - return callback == inventory_offer_callback && ((LLOfferInfo*)cb_data)->mFromID == blocked_id; + if(notification->getName() == "ObjectGiveItem" + || notification->getName() == "ObjectGiveItemUnknownUser" + || notification->getName() == "UserGiveItem") + { + return (notification->getPayload()["from_id"].asUUID() == blocked_id); + } + return FALSE; } private: const LLUUID& blocked_id; @@ -940,12 +994,43 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, gNotifyBoxView->purgeMessagesMatching(OfferMatcher(blocked_id)); } -void inventory_offer_callback(S32 button, void* user_data) +LLOfferInfo::LLOfferInfo(const LLSD& sd) +{ + mIM = (EInstantMessage)sd["im_type"].asInteger(); + mFromID = sd["from_id"].asUUID(); + mFromGroup = sd["from_group"].asBoolean(); + mFromObject = sd["from_object"].asBoolean(); + mTransactionID = sd["transaction_id"].asUUID(); + mFolderID = sd["folder_id"].asUUID(); + mObjectID = sd["object_id"].asUUID(); + mType = LLAssetType::lookup(sd["type"].asString().c_str()); + mFromName = sd["from_name"].asString(); + mDesc = sd["description"].asString(); + mHost = LLHost(sd["sender"].asString()); +} + +LLSD LLOfferInfo::asLLSD() +{ + LLSD sd; + sd["im_type"] = mIM; + sd["from_id"] = mFromID; + sd["from_group"] = mFromGroup; + sd["from_object"] = mFromObject; + sd["transaction_id"] = mTransactionID; + sd["folder_id"] = mFolderID; + sd["object_id"] = mObjectID; + sd["type"] = LLAssetType::lookup(mType); + sd["from_name"] = mFromName; + sd["description"] = mDesc; + sd["sender"] = mHost.getIPandPort(); + return sd; +} + +bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response) { LLChat chat; std::string log_message; - LLOfferInfo* info = (LLOfferInfo*)user_data; - if(!info) return; + S32 button = LLNotification::getSelectedOption(notification, response); // For muting, we need to add the mute, then decline the offer. // This must be done here because: @@ -954,7 +1039,7 @@ void inventory_offer_callback(S32 button, void* user_data) // * we can't build two messages at once. JC if (2 == button) { - gCacheName->get(info->mFromID, info->mFromGroup, inventory_offer_mute_callback, user_data); + gCacheName->get(mFromID, mFromGroup, inventory_offer_mute_callback, this); } LLMessageSystem* msg = gMessageSystem; @@ -964,9 +1049,9 @@ void inventory_offer_callback(S32 button, void* user_data) msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MessageBlock); msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, info->mFromID); + msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, info->mTransactionID); + msg->addUUIDFast(_PREHASH_ID, mTransactionID); msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary std::string name; gAgent.buildFullname(name); @@ -977,50 +1062,50 @@ void inventory_offer_callback(S32 button, void* user_data) msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); LLInventoryObserver* opener = NULL; LLViewerInventoryCategory* catp = NULL; - catp = (LLViewerInventoryCategory*)gInventory.getCategory(info->mObjectID); + catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); LLViewerInventoryItem* itemp = NULL; if(!catp) { - itemp = (LLViewerInventoryItem*)gInventory.getItem(info->mObjectID); + itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); } // *TODO:translate std::string from_string; // Used in the pop-up. std::string chatHistory_string; // Used in chat history. - if (info->mFromObject == TRUE) + if (mFromObject == TRUE) { - if (info->mFromGroup) + if (mFromGroup) { std::string group_name; - if (gCacheName->getGroupName(info->mFromID, group_name)) + if (gCacheName->getGroupName(mFromID, group_name)) { - from_string = std::string("An object named '") + info->mFromName + "' owned by the group '" + group_name + "'"; - chatHistory_string = info->mFromName + " owned by the group '" + group_name + "'"; + from_string = std::string("An object named '") + mFromName + "' owned by the group '" + group_name + "'"; + chatHistory_string = mFromName + " owned by the group '" + group_name + "'"; } else { - from_string = std::string("An object named '") + info->mFromName + "' owned by an unknown group"; - chatHistory_string = info->mFromName + " owned by an unknown group"; + from_string = std::string("An object named '") + mFromName + "' owned by an unknown group"; + chatHistory_string = mFromName + " owned by an unknown group"; } } else { std::string first_name, last_name; - if (gCacheName->getName(info->mFromID, first_name, last_name)) + if (gCacheName->getName(mFromID, first_name, last_name)) { - from_string = std::string("An object named '") + info->mFromName + "' owned by " + first_name + " " + last_name; - chatHistory_string = info->mFromName + " owned by " + first_name + " " + last_name; + from_string = std::string("An object named '") + mFromName + "' owned by " + first_name + " " + last_name; + chatHistory_string = mFromName + " owned by " + first_name + " " + last_name; } else { - from_string = std::string("An object named '") + info->mFromName + "' owned by an unknown user"; - chatHistory_string = info->mFromName + " owned by an unknown user"; + from_string = std::string("An object named '") + mFromName + "' owned by an unknown user"; + chatHistory_string = mFromName + " owned by an unknown user"; } } } else { - from_string = chatHistory_string = info->mFromName; + from_string = chatHistory_string = mFromName; } bool busy=FALSE; @@ -1033,24 +1118,24 @@ void inventory_offer_callback(S32 button, void* user_data) // group_notice_inventory is 1 greater than the offer integer value. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(info->mFolderID.mData), - sizeof(info->mFolderID.mData)); + msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), + sizeof(mFolderID.mData)); // send the message - msg->sendReliable(info->mHost); + msg->sendReliable(mHost); //don't spam them if they are getting flooded - if (check_offer_throttle(info->mFromName, true)) + if (check_offer_throttle(mFromName, true)) { - log_message = chatHistory_string + " gave you " + info->mDesc + "."; + log_message = chatHistory_string + " gave you " + mDesc + "."; chat.mText = log_message; LLFloaterChat::addChatHistory(chat); } // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << info->mTransactionID + LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID << LL_ENDL; - switch (info->mIM) + switch (mIM) { case IM_INVENTORY_OFFERED: { @@ -1058,7 +1143,7 @@ void inventory_offer_callback(S32 button, void* user_data) // end has already copied the items into your inventory, // so we can fetch it out of our inventory. LLInventoryFetchObserver::item_ref_t items; - items.push_back(info->mObjectID); + items.push_back(mObjectID); LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string); open_agent_offer->fetchItems(items); if(catp || (itemp && itemp->isComplete())) @@ -1084,7 +1169,7 @@ void inventory_offer_callback(S32 button, void* user_data) default: LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; break; - } // end switch (info->mIM) + } // end switch (mIM) break; case IOR_BUSY: @@ -1100,14 +1185,14 @@ void inventory_offer_callback(S32 button, void* user_data) // or IM_GROUP_NOTICE_INVENTORY_DECLINED default: // close button probably (or any of the fall-throughs from above) - msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 2)); + msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2)); msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); // send the message - msg->sendReliable(info->mHost); + msg->sendReliable(mHost); - log_message = "You decline " + info->mDesc + " from " + info->mFromName + "."; + log_message = "You decline " + mDesc + " from " + mFromName + "."; chat.mText = log_message; - if( LLMuteList::getInstance()->isMuted(info->mFromID ) && ! LLMuteList::getInstance()->isLinden(info->mFromName) ) // muting for SL-42269 + if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 { chat.mMuted = TRUE; } @@ -1116,13 +1201,13 @@ void inventory_offer_callback(S32 button, void* user_data) // If it's from an agent, we have to fetch the item to throw // it away. If it's from a task or group, just denying the // request will suffice to discard the item. - if(IM_INVENTORY_OFFERED == info->mIM) + if(IM_INVENTORY_OFFERED == mIM) { LLInventoryFetchComboObserver::folder_ref_t folders; LLInventoryFetchComboObserver::item_ref_t items; - items.push_back(info->mObjectID); + items.push_back(mObjectID); LLDiscardAgentOffer* discard_agent_offer; - discard_agent_offer = new LLDiscardAgentOffer(info->mFolderID, info->mObjectID); + discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); discard_agent_offer->fetch(folders, items); if(catp || (itemp && itemp->isComplete())) { @@ -1134,9 +1219,9 @@ void inventory_offer_callback(S32 button, void* user_data) } } - if (busy && (!info->mFromGroup && !info->mFromObject)) + if (busy && (!mFromGroup && !mFromObject)) { - busy_message(msg,info->mFromID); + busy_message(msg,mFromID); } break; } @@ -1146,12 +1231,12 @@ void inventory_offer_callback(S32 button, void* user_data) gInventory.addObserver(opener); } - delete info; - info = NULL; - // Allow these to stack up, but once you deal with one, reset the // position. gFloaterView->resetStartingFloaterPosition(); + + delete this; + return false; } @@ -1161,14 +1246,14 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) //accepting it. SEE SL-39554 if (gAgent.getBusy()) { - inventory_offer_callback(IOR_BUSY, info); + info->forceResponse(IOR_BUSY); return; } //If muted, don't even go through the messaging stuff. Just curtail the offer here. if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName)) { - inventory_offer_callback(IOR_MUTE, info); + info->forceResponse(IOR_MUTE); return; } @@ -1180,7 +1265,7 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) { // For certain types, just accept the items into the inventory, // and possibly open them on receipt depending upon "ShowNewInventory". - inventory_offer_callback(IOR_ACCEPT, info); + info->forceResponse(IOR_ACCEPT); return; } @@ -1192,23 +1277,25 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) LLStringUtil::truncate(msg, indx); } - LLStringUtil::format_map_t args; + LLSD args; args["[OBJECTNAME]"] = msg; + LLSD payload; + // must protect against a NULL return from lookupHumanReadable() std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); if (!typestr.empty()) { - args["[OBJECTTYPE]"] = typestr; + args["OBJECTTYPE"] = typestr; } else { LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; - args["[OBJECTTYPE]"] = ""; + args["OBJECTTYPE"] = ""; // This seems safest, rather than propagating bogosity LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; - inventory_offer_callback(IOR_DECLINE, info); + info->forceResponse(IOR_DECLINE); return; } @@ -1220,8 +1307,8 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) std::string group_name; if (gCacheName->getGroupName(info->mFromID, group_name)) { - args["[FIRST]"] = group_name; - args["[LAST]"] = ""; + args["FIRST"] = group_name; + args["LAST"] = ""; name_found = TRUE; } } @@ -1230,95 +1317,100 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) std::string first_name, last_name; if (gCacheName->getName(info->mFromID, first_name, last_name)) { - args["[FIRST]"] = first_name; - args["[LAST]"] = last_name; + args["FIRST"] = first_name; + args["LAST"] = last_name; name_found = TRUE; } } + + payload["from_id"] = info->mFromID; + args["OBJECTFROMNAME"] = info->mFromName; + args["NAME"] = info->mFromName; + + LLNotification::Params p("ObjectGiveItem"); + p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); + if (from_task) { - args["[OBJECTFROMNAME]"] = info->mFromName; - LLNotifyBox::showXml(name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser", - args, &inventory_offer_callback, (void*)info); + p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser"; } else { - // *TODO:translate -> [FIRST] [LAST] - args["[NAME]"] = info->mFromName; - LLNotifyBox::showXml("UserGiveItem", args, - &inventory_offer_callback, (void*)info); + p.name = "UserGiveItem"; } + + LLNotifications::instance().add(p); } -void group_vote_callback(S32 option, void *userdata) +bool group_vote_callback(const LLSD& notification, const LLSD& response) { - LLUUID *group_id = (LLUUID *)userdata; - if (!group_id) return; - + LLUUID group_id = notification["payload"]["group_id"].asUUID(); + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { case 0: // Vote Now // Open up the voting tab - LLFloaterGroupInfo::showFromUUID(*group_id, "voting_tab"); + LLFloaterGroupInfo::showFromUUID(group_id, "voting_tab"); break; default: // Vote Later or // close button break; } - delete group_id; - group_id = NULL; + return false; } +static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); -struct LLLureInfo +bool lure_callback(const LLSD& notification, const LLSD& response) { - LLLureInfo(const LLUUID& from, const LLUUID& lure_id, BOOL godlike) : - mFromID(from), - mLureID(lure_id), - mGodlike(godlike) - {} - - LLUUID mFromID; - LLUUID mLureID; - BOOL mGodlike; -}; + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotification::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); -void lure_callback(S32 option, void* user_data) -{ - LLLureInfo* info = (LLLureInfo*)user_data; - if(!info) return; switch(option) { case 0: { // accept - gAgent.teleportViaLure(info->mLureID, info->mGodlike); + gAgent.teleportViaLure(lure_id, godlike); } break; case 1: default: // decline - send_simple_im(info->mFromID, + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, - info->mLureID); + lure_id); break; } - delete info; - info = NULL; + return false; } +static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); -void goto_url_callback(S32 option, void* user_data) +bool goto_url_callback(const LLSD& notification, const LLSD& response) { - char* url = (char*)user_data; + std::string url = notification["payload"]["url"].asString(); + S32 option = LLNotification::getSelectedOption(notification, response); if(1 == option) { LLWeb::loadURL(url); } - delete[] url; + return false; } +static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); void process_improved_im(LLMessageSystem *msg, void **user_data) { @@ -1332,7 +1424,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) U8 offline; U8 d = 0; LLUUID session_id; - U32 t; + U32 timestamp; std::string name; std::string message; U32 parent_estate_id = 0; @@ -1350,7 +1442,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline); msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, t); + msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); //msg->getData("MessageBlock", "Count", &count); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); @@ -1360,7 +1452,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); EInstantMessage dialog = (EInstantMessage)d; - time_t timestamp = (time_t)t; BOOL is_busy = gAgent.getBusy(); BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); @@ -1389,18 +1480,18 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) message_offset = 3; } - LLStringUtil::format_map_t args; + LLSD args; switch(dialog) { case IM_CONSOLE_AND_CHAT_HISTORY: // These are used for system messages, hence don't need the name, // as it is always "Second Life". // *TODO:translate - args["[MESSAGE]"] = message; + args["MESSAGE"] = message; // Note: don't put the message in the IM history, even though was sent // via the IM mechanism. - LLNotifyBox::showXml("SystemMessageTip",args); + LLNotifications::instance().add("SystemMessageTip",args); break; case IM_NOTHING_SPECIAL: @@ -1470,9 +1561,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else if (to_id.isNull()) { // Message to everyone from GOD - args["[NAME]"] = name; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("GodMessage", args); + args["NAME"] = name; + args["MESSAGE"] = message; + LLNotifications::instance().add("GodMessage", args); // Treat like a system message and put in chat history. // Claim to be from a local agent so it doesn't go into @@ -1541,8 +1632,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { // This is a block, modeless dialog. //*TODO:translate - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("SystemMessage", args); + args["MESSAGE"] = message; + LLNotifications::instance().add("SystemMessage", args); } break; case IM_GROUP_NOTICE: @@ -1579,9 +1670,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // If there is inventory, give the user the inventory offer. LLOfferInfo* info = NULL; + if (has_inventory) { info = new LLOfferInfo; + info->mIM = IM_GROUP_NOTICE; info->mFromID = from_id; info->mFromGroup = from_group; @@ -1610,13 +1703,26 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) std::string subj(*iter++); std::string mes(*iter++); - if (IM_GROUP_NOTICE == dialog) + // Send the notification down the new path. + // For requested notices, we don't want to send the popups. + if (dialog != IM_GROUP_NOTICE_REQUESTED) { - subj += "\n"; - mes = "\n\n" + mes; - LLGroupNotifyBox::show(subj,mes,name,group_id,t,has_inventory,item_name,info); + LLSD payload; + payload["subject"] = subj; + payload["message"] = mes; + payload["sender_name"] = name; + payload["group_id"] = group_id; + payload["inventory_name"] = item_name; + payload["inventory_offer"] = info ? info->asLLSD() : LLSD(); + + LLSD args; + args["SUBJECT"] = subj; + args["MESSAGE"] = mes; + LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(timestamp)); } - else if (IM_GROUP_NOTICE_REQUESTED == dialog) + + // Also send down the old path for now. + if (IM_GROUP_NOTICE_REQUESTED == dialog) { LLFloaterGroupInfo::showNotice(subj,mes,group_id,has_inventory,item_name,info); } @@ -1628,7 +1734,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if ((is_busy || is_muted)) { LLMessageSystem *msg = gMessageSystem; - join_group_callback(1, NULL); busy_message(msg,from_id); } else @@ -1651,18 +1756,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; S32 membership_fee = ntohl(invite_bucket->membership_fee); - LLJoinGroupData* userdata = new LLJoinGroupData; - userdata->mTransactionID = session_id; - userdata->mGroupID = from_id; - userdata->mName.assign(name); - userdata->mMessage.assign(message); - userdata->mFee = membership_fee; - - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("JoinGroup", args, - &join_group_callback, - (void*)userdata); + LLSD payload; + payload["transaction_id"] = session_id; + payload["group_id"] = from_id; + payload["name"] = name; + payload["message"] = message; + payload["fee"] = membership_fee; + + LLSD args; + args["MESSAGE"] = message; + LLNotifications::instance().add("JoinGroup", args, payload, join_group_response); } } break; @@ -1722,7 +1825,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if ( is_muted ) { // Same as closing window - inventory_offer_callback(-1, info); + info->forceResponse(IOR_DECLINE); } else { @@ -1733,23 +1836,25 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_INVENTORY_ACCEPTED: { - args["[NAME]"] = name; - LLNotifyBox::showXml("InventoryAccepted", args); + args["NAME"] = name; + LLNotifications::instance().add("InventoryAccepted", args); break; } case IM_INVENTORY_DECLINED: { - args["[NAME]"] = name; - LLNotifyBox::showXml("InventoryDeclined", args); + args["NAME"] = name; + LLNotifications::instance().add("InventoryDeclined", args); break; } case IM_GROUP_VOTE: { - LLUUID *userdata = new LLUUID(session_id); - args["[NAME]"] = name; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("GroupVote", args, - &group_vote_callback, userdata); + LLSD args; + args["NAME"] = name; + args["MESSAGE"] = message; + + LLSD payload; + payload["group_id"] = session_id; + LLNotifications::instance().add("GroupVote", args, payload); } break; @@ -1856,9 +1961,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } { // Construct a viewer alert for this message. - args["[NAME]"] = name; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("ObjectMessage", args); + args["NAME"] = name; + args["MESSAGE"] = message; + LLNotifications::instance().add("ObjectMessage", args); } break; case IM_BUSY_AUTO_RESPONSE: @@ -1887,27 +1992,34 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } else { + LLSD args; // *TODO:translate -> [FIRST] [LAST] (maybe) - LLLureInfo* info = new LLLureInfo(from_id, session_id, FALSE); - args["[NAME]"] = name; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("OfferTeleport", args, - lure_callback, (void*)info); + args["NAME"] = name; + args["MESSAGE"] = message; + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = FALSE; + LLNotifications::instance().add("TeleportOffered", args, payload); } } break; case IM_GODLIKE_LURE_USER: { - LLLureInfo* info = new LLLureInfo(from_id, session_id, TRUE); + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = TRUE; // do not show a message box, because you're about to be // teleported. - lure_callback(0, (void *)info); + LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); } break; case IM_GOTO_URL: { + LLSD args; // n.b. this is for URLs sent by the system, not for // URLs sent by scripts (i.e. llLoadURL) if (binary_bucket_size <= 0) @@ -1918,38 +2030,33 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) return; } - char* url = new char[binary_bucket_size]; - if (url == NULL) - { - LL_ERRS("Messaging") << "Memory Allocation failed" << LL_ENDL; - return; - } - - strncpy(url, (char*)binary_bucket, binary_bucket_size-1); /* Flawfinder: ignore */ - url[binary_bucket_size-1] = '\0'; - args["[MESSAGE]"] = message; - args["[URL]"] = url; - LLNotifyBox::showXml("GotoURL", args, - goto_url_callback, (void*)url); + std::string url; + + url.assign((char*)binary_bucket, binary_bucket_size-1); + args["MESSAGE"] = message; + args["URL"] = url; + LLSD payload; + payload["url"] = url; + LLNotifications::instance().add("GotoURL", args, payload ); } break; case IM_FRIENDSHIP_OFFERED: { - LLFriendshipOffer* offer = new LLFriendshipOffer; - offer->mFromID = from_id; - offer->mTransactionID = session_id; - offer->mOnline = (offline == IM_ONLINE); - offer->mHost = msg->getSender(); + LLSD payload; + payload["from_id"] = from_id; + payload["session_id"] = session_id;; + payload["online"] = (offline == IM_ONLINE); + payload["sender"] = msg->getSender().getIPandPort(); if (is_busy) { busy_message(msg, from_id); - friendship_offer_callback(1, (void*)offer); + LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); } else if (is_muted) { - friendship_offer_callback(1, (void*)offer); + LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); } else { @@ -1957,14 +2064,12 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if(message.empty()) { //support for frienship offers from clients before July 2008 - LLNotifyBox::showXml("OfferFriendshipNoMessage", args, - &friendship_offer_callback, (void*)offer); + LLNotifications::instance().add("OfferFriendshipNoMessage", args, payload); } else { args["[MESSAGE]"] = message; - LLNotifyBox::showXml("OfferFriendship", args, - &friendship_offer_callback, (void*)offer); + LLNotifications::instance().add("OfferFriendship", args, payload); } } } @@ -1981,14 +2086,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) strings.push_back(from_id.asString()); send_generic_message("requestonlinenotification", strings); - args["[NAME]"] = name; - LLNotifyBox::showXml("FriendshipAccepted", args); + args["NAME"] = name; + LLNotifications::instance().add("FriendshipAccepted", args); } break; case IM_FRIENDSHIP_DECLINED: - args["[NAME]"] = name; - LLNotifyBox::showXml("FriendshipDeclined", args); + args["NAME"] = name; + LLNotifications::instance().add("FriendshipDeclined", args); break; default: @@ -2025,61 +2130,9 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) } } -void friendship_offer_callback(S32 option, void* user_data) +bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { - LLFriendshipOffer* offer = (LLFriendshipOffer*)user_data; - if(!offer) return; - LLUUID fid; - LLMessageSystem* msg = gMessageSystem; - switch(option) - { - case 0: - // accept - LLAvatarTracker::formFriendship(offer->mFromID); - - fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); - - // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(offer->mHost); - break; - case 1: - // decline - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID); - msg->sendReliable(offer->mHost); - break; - default: - // close button probably, possibly timed out - break; - } - - delete offer; - offer = NULL; -} - -struct LLCallingCardOfferData -{ - LLUUID mTransactionID; - LLUUID mSourceID; - LLHost mHost; -}; - -void callingcard_offer_callback(S32 option, void* user_data) -{ - LLCallingCardOfferData* offerdata = (LLCallingCardOfferData*)user_data; - if(!offerdata) return; + S32 option = LLNotification::getSelectedOption(notification, response); LLUUID fid; LLUUID from_id; LLMessageSystem* msg = gMessageSystem; @@ -2092,11 +2145,11 @@ void callingcard_offer_callback(S32 option, void* user_data) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); msg->nextBlockFast(_PREHASH_FolderData); msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(offerdata->mHost); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); break; case 1: // decline @@ -2105,18 +2158,18 @@ void callingcard_offer_callback(S32 option, void* user_data) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID); - msg->sendReliable(offerdata->mHost); - busy_message(msg, offerdata->mSourceID); + msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); + busy_message(msg, notification["payload"]["source_id"].asUUID()); break; default: // close button probably, possibly timed out break; } - delete offerdata; - offerdata = NULL; + return false; } +static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) { @@ -2128,13 +2181,13 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) LLUUID tid; msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); - LLCallingCardOfferData* offerdata = new LLCallingCardOfferData; - offerdata->mTransactionID = tid; - offerdata->mSourceID = source_id; - offerdata->mHost = msg->getSender(); + LLSD payload; + payload["transaction_id"] = tid; + payload["source_id"] = source_id; + payload["sender"] = msg->getSender().getIPandPort(); LLViewerObject* source = gObjectList.findObject(source_id); - LLStringUtil::format_map_t args; + LLSD args; std::string source_name; if(source && source->isAvatar()) { @@ -2142,8 +2195,8 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) LLNameValue* nvlast = source->getNVPair("LastName"); if (nvfirst && nvlast) { - args["[FIRST]"] = nvfirst->getString(); - args["[LAST]"] = nvlast->getString(); + args["FIRST"] = nvfirst->getString(); + args["LAST"] = nvlast->getString(); source_name = std::string(nvfirst->getString()) + " " + nvlast->getString(); } } @@ -2154,33 +2207,27 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) { // automatically decline offer - callingcard_offer_callback(1, (void*)offerdata); - offerdata = NULL; // pointer was freed by callback + LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); } else { - LLNotifyBox::showXml("OfferCallingCard", args, - &callingcard_offer_callback, (void*)offerdata); - offerdata = NULL; // pointer ownership transferred + LLNotifications::instance().add("OfferCallingCard", args, payload); } } else { LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; } - - delete offerdata; // !=NULL if we didn't give ownership away - offerdata = NULL; } void process_accept_callingcard(LLMessageSystem* msg, void**) { - LLNotifyBox::showXml("CallingCardAccepted"); + LLNotifications::instance().add("CallingCardAccepted"); } void process_decline_callingcard(LLMessageSystem* msg, void**) { - LLNotifyBox::showXml("CallingCardDeclined"); + LLNotifications::instance().add("CallingCardDeclined"); } @@ -2496,18 +2543,18 @@ public: LLInventoryModel::EXCLUDE_TRASH, is_card); } - LLStringUtil::format_map_t args; + LLSD args; if ( land_items.count() > 0 ) { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory S32 random_land = ll_rand( land_items.count() - 1 ); - args["[NAME]"] = land_items[random_land]->getName(); - LLNotifyBox::showXml("TeleportToLandmark",args); + args["NAME"] = land_items[random_land]->getName(); + LLNotifications::instance().add("TeleportToLandmark",args); } if ( card_items.count() > 0 ) { // Show notification that they can now contact people. Use a random calling card from the inventory S32 random_card = ll_rand( card_items.count() - 1 ); - args["[NAME]"] = card_items[random_card]->getName(); - LLNotifyBox::showXml("TeleportToPerson",args); + args["NAME"] = card_items[random_card]->getName(); + LLNotifications::instance().add("TeleportToPerson",args); } gInventory.removeObserver(this); @@ -2688,11 +2735,6 @@ void process_avatar_init_complete(LLMessageSystem* msg, void**) } */ -static void display_release_notes(S32, void* data) -{ - gAgent.getRegion()->showReleaseNotes(); -} - void process_agent_movement_complete(LLMessageSystem* msg, void**) { gAgentMovementCompleted = true; @@ -2864,8 +2906,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (!gLastVersionChannel.empty()) { - LLNotifyBox::showXml( - "ServerVersionChanged", display_release_notes, NULL); + LLSD payload; + payload["message"] = version_channel; + LLNotifications::instance().add("ServerVersionChanged", LLSD(), payload); } gLastVersionChannel = version_channel; @@ -4059,9 +4102,9 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // Make the user confirm the transaction, since they might // have missed something during an event. // *TODO:translate - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = desc; - LLNotifyBox::showXml("SystemMessage", args); + LLSD args; + args["MESSAGE"] = desc; + LLNotifications::instance().add("SystemMessage", args); // Once the 'recent' container gets large enough, chop some // off the beginning. @@ -4121,54 +4164,54 @@ void process_alert_core(const std::string& message, BOOL modal) // Allow the server to spawn a named alert so that server alerts can be // translated out of English. std::string alert_name(message.substr(ALERT_PREFIX.length())); - LLAlertDialog::showXml(alert_name); + LLNotifications::instance().add(alert_name); } else if (message.find(NOTIFY_PREFIX) == 0) { // Allow the server to spawn a named notification so that server notifications can be // translated out of English. std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotifyBox::showXml(notify_name); + LLNotifications::instance().add(notify_name); } else if (message[0] == '/') { // System message is important, show in upper-right box not tip std::string text(message.substr(1)); - LLStringUtil::format_map_t args; + LLSD args; if (text.substr(0,17) == "RESTART_X_MINUTES") { S32 mins = 0; LLStringUtil::convertToS32(text.substr(18), mins); - args["[MINUTES]"] = llformat("%d",mins); - LLNotifyBox::showXml("RegionRestartMinutes", args); + args["MINUTES"] = llformat("%d",mins); + LLNotifications::instance().add("RegionRestartMinutes", args); } else if (text.substr(0,17) == "RESTART_X_SECONDS") { S32 secs = 0; LLStringUtil::convertToS32(text.substr(18), secs); - args["[SECONDS]"] = llformat("%d",secs); - LLNotifyBox::showXml("RegionRestartSeconds", args); + args["SECONDS"] = llformat("%d",secs); + LLNotifications::instance().add("RegionRestartSeconds", args); } else { // *TODO:translate - args["[MESSAGE]"] = text; - LLNotifyBox::showXml("SystemMessage", args); + args["MESSAGE"] = text; + LLNotifications::instance().add("SystemMessage", args); } } else if (modal) { // *TODO:translate - LLStringUtil::format_map_t args; - args["[ERROR_MESSAGE]"] = message; - gViewerWindow->alertXml("ErrorMessage", args); + LLSD args; + args["ERROR_MESSAGE"] = message; + LLNotifications::instance().add("ErrorMessage", args); } else { // *TODO:translate - LLStringUtil::format_map_t args; - args["[MESSAGE]"] = message; - LLNotifyBox::showXml("SystemMessageTip", args); + LLSD args; + args["MESSAGE"] = message; + LLNotifications::instance().add("SystemMessageTip", args); } } @@ -4300,23 +4343,7 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost)); } -class LLScriptQuestionCBData -{ -public: - LLScriptQuestionCBData(const LLUUID &taskid, const LLUUID &itemid, const LLHost &sender, S32 questions, const std::string& object_name, const std::string& owner_name) - : mTaskID(taskid), mItemID(itemid), mSender(sender), mQuestions(questions), mObjectName(object_name), mOwnerName(owner_name) - { - } - - LLUUID mTaskID; - LLUUID mItemID; - LLHost mSender; - S32 mQuestions; - std::string mObjectName; - std::string mOwnerName; -}; - -void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_questions, BOOL granted) +void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) { // only continue if at least some permissions were requested if (orig_questions) @@ -4327,16 +4354,16 @@ void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_q // located in [REGIONNAME] at [REGIONPOS], // has been <granted|denied> permission to: [PERMISSIONS]." - LLUIString notice(LLNotifyBox::getTemplateMessage(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); + LLUIString notice(LLFloaterChat::getInstance()->getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); // always include the object name and owner name - notice.setArg("[OBJECTNAME]", cbdata->mObjectName); - notice.setArg("[OWNERNAME]", cbdata->mOwnerName); + notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); + notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); // try to lookup viewerobject that corresponds to the object that // requested permissions (here, taskid->requesting object id) BOOL foundpos = FALSE; - LLViewerObject* viewobj = gObjectList.findObject(cbdata->mTaskID); + LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); if (viewobj) { // found the viewerobject, get it's position in its region @@ -4369,7 +4396,7 @@ void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_q std::string perms; for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) { - if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && LLNotifyBox::getTemplateIsCaution(SCRIPT_QUESTIONS[i])) + if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && SCRIPT_QUESTION_IS_CAUTION[i]) { count++; caution = TRUE; @@ -4381,7 +4408,7 @@ void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_q perms.append(", "); } - perms.append(LLNotifyBox::getTemplateMessage(SCRIPT_QUESTIONS[i])); + perms.append(LLFloaterChat::getInstance()->getString(SCRIPT_QUESTIONS[i])); } } @@ -4397,43 +4424,12 @@ void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_q } } -void script_question_decline_cb(S32 option, void* user_data) -{ - LLMessageSystem *msg = gMessageSystem; - LLScriptQuestionCBData *cbdata = (LLScriptQuestionCBData *)user_data; - - // remember the permissions requested so they can be checked - // when it comes time to log a chat message - S32 orig = cbdata->mQuestions; - - // this callback will always decline all permissions requested - // (any question flags set in the ScriptAnswerYes message - // will be interpreted as having been granted, so clearing all - // the bits will deny every permission) - cbdata->mQuestions = 0; - - // respond with the permissions denial - msg->newMessageFast(_PREHASH_ScriptAnswerYes); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_TaskID, cbdata->mTaskID); - msg->addUUIDFast(_PREHASH_ItemID, cbdata->mItemID); - msg->addS32Fast(_PREHASH_Questions, cbdata->mQuestions); - msg->sendReliable(cbdata->mSender); - - // log a chat message, if appropriate - notify_cautioned_script_question(cbdata, orig, FALSE); - - delete cbdata; -} - -void script_question_cb(S32 option, void* user_data) +bool script_question_cb(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); LLMessageSystem *msg = gMessageSystem; - LLScriptQuestionCBData *cbdata = (LLScriptQuestionCBData *)user_data; - S32 orig = cbdata->mQuestions; + S32 orig = notification["payload"]["questions"].asInteger(); + S32 new_questions = orig; // check whether permissions were granted or denied BOOL allowed = TRUE; @@ -4441,48 +4437,68 @@ void script_question_cb(S32 option, void* user_data) // if any other button was clicked, the permissions were denied if (option != 0) { - cbdata->mQuestions = 0; + new_questions = 0; allowed = FALSE; } + LLUUID task_id = notification["payload"]["task_id"].asUUID(); + LLUUID item_id = notification["payload"]["item_id"].asUUID(); + // reply with the permissions granted or denied msg->newMessageFast(_PREHASH_ScriptAnswerYes); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_TaskID, cbdata->mTaskID); - msg->addUUIDFast(_PREHASH_ItemID, cbdata->mItemID); - msg->addS32Fast(_PREHASH_Questions, cbdata->mQuestions); - msg->sendReliable(cbdata->mSender); + msg->addUUIDFast(_PREHASH_TaskID, task_id); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->addS32Fast(_PREHASH_Questions, new_questions); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); // only log a chat message if caution prompts are enabled if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { // log a chat message, if appropriate - notify_cautioned_script_question(cbdata, orig, allowed); + notify_cautioned_script_question(notification, response, orig, allowed); } - if ( option == 2 ) // mute + if ( response["Mute"] ) // mute { - LLMuteList::getInstance()->add(LLMute(cbdata->mItemID, cbdata->mObjectName, LLMute::OBJECT)); + LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT)); // purge the message queue of any previously queued requests from the same source. DEV-4879 class OfferMatcher : public LLNotifyBoxView::Matcher { public: OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - BOOL matches(LLNotifyBox::notify_callback_t callback, void* cb_data) const + BOOL matches(const LLNotificationPtr notification) const { - return callback == script_question_cb && ((LLScriptQuestionCBData*)cb_data)->mItemID == blocked_id; + if (notification->getName() == "ScriptQuestionCaution" + || notification->getName() == "ScriptQuestion") + { + return (notification->getPayload()["item_id"].asUUID() == blocked_id); + } + return FALSE; } private: const LLUUID& blocked_id; }; - gNotifyBoxView->purgeMessagesMatching(OfferMatcher(cbdata->mItemID)); + // should do this via the channel + gNotifyBoxView->purgeMessagesMatching(OfferMatcher(item_id)); + } + + if (response["Details"]) + { + // respawn notification... + LLNotifications::instance().add(notification["name"], notification["substitutions"], notification["payload"]); + + // ...with description on top + LLNotifications::instance().add("DebitPermissionDetails"); } - delete cbdata; + return false; } +static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); +static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb); void process_script_question(LLMessageSystem *msg, void **user_data) { @@ -4532,9 +4548,9 @@ void process_script_question(LLMessageSystem *msg, void **user_data) { BOOL caution = FALSE; S32 count = 0; - LLStringUtil::format_map_t args; - args["[OBJECTNAME]"] = object_name; - args["[NAME]"] = owner_name; + LLSD args; + args["OBJECTNAME"] = object_name; + args["NAME"] = owner_name; // check the received permission flags against each permission for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) @@ -4542,34 +4558,32 @@ void process_script_question(LLMessageSystem *msg, void **user_data) if (questions & LSCRIPTRunTimePermissionBits[i]) { count++; - script_question += " " + LLNotifyBox::getTemplateMessage(SCRIPT_QUESTIONS[i]) + "\n"; + script_question += " " + LLFloaterChat::getInstance()->getString(SCRIPT_QUESTIONS[i]) + "\n"; // check whether permission question should cause special caution dialog - caution |= LLNotifyBox::getTemplateIsCaution(SCRIPT_QUESTIONS[i]); + caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); } } - args["[QUESTIONS]"] = script_question; + args["QUESTIONS"] = script_question; - LLScriptQuestionCBData *cbdata = new LLScriptQuestionCBData(taskid, itemid, sender, questions, object_name, owner_name); + LLSD payload; + payload["task_id"] = taskid; + payload["item_id"] = itemid; + payload["sender"] = sender.getIPandPort(); + payload["questions"] = questions; + payload["object_name"] = object_name; + payload["owner_name"] = owner_name; // check whether cautions are even enabled or not if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { - if (caution) - { - // display the caution permissions prompt - LLNotifyBox::showXml("ScriptQuestionCaution", args, TRUE, script_question_cb, cbdata); - } - else - { - // display the permissions request normally - LLNotifyBox::showXml("ScriptQuestion", args, FALSE, script_question_cb, cbdata); - } + // display the caution permissions prompt + LLNotifications::instance().add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); } else { // fall back to default behavior if cautions are entirely disabled - LLNotifyBox::showXml("ScriptQuestion", args, FALSE, script_question_cb, cbdata); + LLNotifications::instance().add("ScriptQuestion", args, payload); } } @@ -4706,18 +4720,18 @@ void process_teleport_failed(LLMessageSystem *msg, void**) std::string reason; msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason); - LLStringUtil::format_map_t args; + LLSD args; std::string big_reason = LLAgent::sTeleportErrorMessages[reason]; if ( big_reason.size() > 0 ) { // Substitute verbose reason from the local map - args["[REASON]"] = big_reason; + args["REASON"] = big_reason; } else { // Nothing found in the map - use what the server returned - args["[REASON]"] = reason; + args["REASON"] = reason; } - gViewerWindow->alertXml("CouldNotTeleportReason", args); + LLNotifications::instance().add("CouldNotTeleportReason", args); if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { @@ -4839,9 +4853,10 @@ void send_group_notice(const LLUUID& group_id, bin_bucket_size); } -void handle_lure_callback(S32 option, const std::string& text, void* userdata) +bool handle_lure_callback(const LLSD& notification, const LLSD& response) { - LLDynamicArray<LLUUID>* invitees = (LLDynamicArray<LLUUID>*)userdata; + std::string text = response["message"].asString(); + S32 option = LLNotification::getSelectedOption(notification, response); if(0 == option) { @@ -4853,21 +4868,17 @@ void handle_lure_callback(S32 option, const std::string& text, void* userdata) msg->nextBlockFast(_PREHASH_Info); msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in. msg->addStringFast(_PREHASH_Message, text); - for(LLDynamicArray<LLUUID>::iterator itr = invitees->begin(); itr != invitees->end(); ++itr) + for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); + it != notification["payload"]["ids"].endArray(); + ++it) { msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, *itr); + msg->addUUIDFast(_PREHASH_TargetID, it->asUUID()); } gAgent.sendReliableMessage(); } - delete invitees; - invitees = NULL; -} - -void handle_lure_callback_godlike(S32 option, void* userdata) -{ - handle_lure_callback(option, LLStringUtil::null, userdata); + return false; } void handle_lure(const LLUUID& invitee) @@ -4880,21 +4891,23 @@ void handle_lure(const LLUUID& invitee) // Prompt for a message to the invited user. void handle_lure(LLDynamicArray<LLUUID>& ids) { - LLDynamicArray<LLUUID>* userdata = new LLDynamicArray<LLUUID>(ids); + LLSD edit_args; + edit_args["REGION"] = gAgent.getRegion()->getName(); - LLStringUtil::format_map_t edit_args; - edit_args["[REGION]"] = gAgent.getRegion()->getName(); + LLSD payload; + for (LLDynamicArray<LLUUID>::iterator it = ids.begin(); + it != ids.end(); + ++it) + { + payload["ids"].append(*it); + } if (gAgent.isGodlike()) { - gViewerWindow->alertXmlEditText("OfferTeleportFromGod", edit_args, - &handle_lure_callback_godlike, userdata, - NULL, NULL, edit_args); + LLNotifications::instance().add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); } else { - gViewerWindow->alertXmlEditText("OfferTeleport", edit_args, - NULL, NULL, - handle_lure_callback, userdata, edit_args); + LLNotifications::instance().add("OfferTeleport", edit_args, payload, handle_lure_callback); } } @@ -4986,21 +4999,13 @@ const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24; const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512; const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; -struct ScriptDialogInfo +bool callback_script_dialog(const LLSD& notification, const LLSD& response) { - LLHost mSender; - LLUUID mObjectID; - S32 mChatChannel; - std::vector<std::string> mButtons; -}; - -void callback_script_dialog(S32 option, void* data) -{ - ScriptDialogInfo* info = (ScriptDialogInfo*)data; - if (!info) return; - + LLNotificationForm form(notification["form"]); + std::string button = LLNotification::getSelectedOptionName(response); + S32 button_idx = LLNotification::getSelectedOption(notification, response); // Didn't click "Ignore" - if (0 != option) + if (button_idx != -1) { LLMessageSystem* msg = gMessageSystem; msg->newMessage("ScriptDialogReply"); @@ -5008,112 +5013,108 @@ void callback_script_dialog(S32 option, void* data) msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->nextBlock("Data"); - msg->addUUID("ObjectID", info->mObjectID); - msg->addS32("ChatChannel", info->mChatChannel); - msg->addS32("ButtonIndex", option); - msg->addString("ButtonLabel", info->mButtons[option-1]); - msg->sendReliable(info->mSender); + msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); + msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); + msg->addS32("ButtonIndex", button_idx); + msg->addString("ButtonLabel", button); + msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); } - delete info; + return false; } +static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); +static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); void process_script_dialog(LLMessageSystem* msg, void**) { S32 i; - ScriptDialogInfo* info = new ScriptDialogInfo; + LLSD payload; - std::string message; // Account for size of "Script Dialog:\n" + std::string message; std::string first_name; std::string last_name; std::string title; - info->mSender = msg->getSender(); - msg->getUUID("Data", "ObjectID", info->mObjectID); + LLUUID object_id; + S32 chat_channel; + msg->getUUID("Data", "ObjectID", object_id); msg->getString("Data", "FirstName", first_name); msg->getString("Data", "LastName", last_name); msg->getString("Data", "ObjectName", title); msg->getString("Data", "Message", message); - msg->getS32("Data", "ChatChannel", info->mChatChannel); + msg->getS32("Data", "ChatChannel", chat_channel); // unused for now LLUUID image_id; msg->getUUID("Data", "ImageID", image_id); + payload["sender"] = msg->getSender().getIPandPort(); + payload["object_id"] = object_id; + payload["chat_channel"] = chat_channel; + + // build up custom form S32 button_count = msg->getNumberOfBlocks("Buttons"); if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) { button_count = SCRIPT_DIALOG_MAX_BUTTONS; } + LLNotificationForm form; for (i = 0; i < button_count; i++) { std::string tdesc; msg->getString("Buttons", "ButtonLabel", tdesc, i); - info->mButtons.push_back(tdesc); + form.addElement("button", std::string(tdesc)); } - LLStringUtil::format_map_t args; - args["[TITLE]"] = title; - args["[MESSAGE]"] = message; + LLSD args; + args["TITLE"] = title; + args["MESSAGE"] = message; + LLNotificationPtr notification; if (!first_name.empty()) { - args["[FIRST]"] = first_name; - args["[LAST]"] = last_name; - LLNotifyBox::showXml("ScriptDialog", args, - callback_script_dialog, info, - info->mButtons, - TRUE); + args["FIRST"] = first_name; + args["LAST"] = last_name; + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); } else { - args["[GROUPNAME]"] = last_name; - LLNotifyBox::showXml("ScriptDialogGroup", args, - callback_script_dialog, info, - info->mButtons, - TRUE); + args["GROUPNAME"] = last_name; + notification = LLNotifications::instance().add( + LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); } } //--------------------------------------------------------------------------- -struct LoadUrlInfo -{ - LLUUID mObjectID; - LLUUID mOwnerID; - BOOL mOwnerIsGroup; - std::string mObjectName; - std::string mMessage; - std::string mUrl; -}; -std::vector<LoadUrlInfo*> gLoadUrlList; +std::vector<LLSD> gLoadUrlList; -void callback_load_url(S32 option, void* data) +bool callback_load_url(const LLSD& notification, const LLSD& response) { - LoadUrlInfo* infop = (LoadUrlInfo*)data; - if (!infop) return; + S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { - LLWeb::loadURLExternal(infop->mUrl); + LLWeb::loadURL(notification["payload"]["url"].asString()); } - delete infop; - infop = NULL; + return false; } +static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); // We've got the name of the person who owns the object hurling the url. // Display confirmation dialog. void callback_load_url_name(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data) { - std::vector<LoadUrlInfo*>::iterator it; + std::vector<LLSD>::iterator it; for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) { - LoadUrlInfo* infop = *it; - if (infop->mOwnerID == id) + LLSD load_url_info = *it; + if (load_url_info["owner_id"].asUUID() == id) { it = gLoadUrlList.erase(it); @@ -5130,16 +5131,15 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st // For legacy name-only mutes. if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) { - delete infop; - infop = NULL; continue; } - LLStringUtil::format_map_t args; - args["[URL]"] = infop->mUrl; - args["[MESSAGE]"] = infop->mMessage; - args["[OBJECTNAME]"] = infop->mObjectName; - args["[NAME]"] = owner_name; - LLNotifyBox::showXml("LoadWebPage", args, callback_load_url, infop); + LLSD args; + args["URL"] = load_url_info["url"].asString(); + args["MESSAGE"] = load_url_info["message"].asString();; + args["OBJECTNAME"] = load_url_info["object_name"].asString(); + args["NAME"] = owner_name; + + LLNotifications::instance().add("LoadWebPage", args, load_url_info); } else { @@ -5150,40 +5150,51 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st void process_load_url(LLMessageSystem* msg, void**) { - LoadUrlInfo* infop = new LoadUrlInfo; - - msg->getString("Data", "ObjectName", infop->mObjectName); - msg->getUUID( "Data", "ObjectID", infop->mObjectID); - msg->getUUID( "Data", "OwnerID", infop->mOwnerID); - msg->getBOOL( "Data", "OwnerIsGroup", infop->mOwnerIsGroup); - msg->getString("Data", "Message", infop->mMessage); - msg->getString("Data", "URL", infop->mUrl); + LLUUID object_id; + LLUUID owner_id; + BOOL owner_is_group; + char object_name[256]; /* Flawfinder: ignore */ + char message[256]; /* Flawfinder: ignore */ + char url[256]; /* Flawfinder: ignore */ + + msg->getString("Data", "ObjectName", 256, object_name); + msg->getUUID( "Data", "ObjectID", object_id); + msg->getUUID( "Data", "OwnerID", owner_id); + msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); + msg->getString("Data", "Message", 256, message); + msg->getString("Data", "URL", 256, url); + + LLSD payload; + payload["object_id"] = object_id; + payload["owner_id"] = owner_id; + payload["owner_is_group"] = owner_is_group; + payload["object_name"] = object_name; + payload["message"] = message; + payload["url"] = url; // URL is safety checked in load_url above // Check if object or owner is muted - if (LLMuteList::getInstance()->isMuted(infop->mObjectID, infop->mObjectName) || - LLMuteList::getInstance()->isMuted(infop->mOwnerID)) + if (LLMuteList::getInstance()->isMuted(object_id, object_name) || + LLMuteList::getInstance()->isMuted(owner_id)) { LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL; - delete infop; - infop = NULL; return; } // Add to list of pending name lookups - gLoadUrlList.push_back(infop); + gLoadUrlList.push_back(payload); - gCacheName->get(infop->mOwnerID, infop->mOwnerIsGroup, callback_load_url_name); + gCacheName->get(owner_id, owner_is_group, callback_load_url_name); } void callback_download_complete(void** data, S32 result, LLExtStat ext_status) { std::string* filepath = (std::string*)data; - LLStringUtil::format_map_t args; - args["[DOWNLOAD_PATH]"] = *filepath; - gViewerWindow->alertXml("FinishedRawDownload", args); + LLSD args; + args["DOWNLOAD_PATH"] = *filepath; + LLNotifications::instance().add("FinishedRawDownload", args); delete filepath; } @@ -5415,3 +5426,10 @@ void invalid_message_callback(LLMessageSystem* msg, // Please do not add more message handlers here. This file is huge. // Put them in a file related to the functionality you are implementing. JC + +void LLOfferInfo::forceResponse(InventoryOfferResponse response) +{ + LLNotification::Params params("UserGiveItem"); + params.functor(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); + LLNotifications::instance().forceResponse(params, response); +} diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index a2ed04d0a7..bbda752e89 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -192,11 +192,15 @@ void process_decline_callingcard(LLMessageSystem* msg, void**); void invalid_message_callback(LLMessageSystem*, void*, EMessageException); void process_initiate_download(LLMessageSystem* msg, void**); -void inventory_offer_callback(S32 option, void* user_data); void start_new_inventory_observer(); struct LLOfferInfo { + LLOfferInfo() {}; + LLOfferInfo(const LLSD& sd); + + void forceResponse(InventoryOfferResponse response); + EInstantMessage mIM; LLUUID mFromID; BOOL mFromGroup; @@ -208,6 +212,10 @@ struct LLOfferInfo std::string mFromName; std::string mDesc; LLHost mHost; + + LLSD asLLSD(); + bool inventory_offer_callback(const LLSD& notification, const LLSD& response); + }; void process_feature_disabled_message(LLMessageSystem* msg, void**); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index fe588534e5..05c589c398 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -50,7 +50,7 @@ S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; // Local functions -void callback_play_media(S32 option, void* data); +bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); // Move this to its own file. // helper class that tries to download a URL from a web site and calls a method @@ -167,8 +167,8 @@ void LLViewerParcelMedia::update(LLParcel* parcel) // First use warning if( gSavedSettings.getWarning("FirstStreamingVideo") ) { - gViewerWindow->alertXml("ParcelCanPlayMedia", - callback_play_media, (void*)parcel); + LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), + boost::bind(callback_play_media, _1, _2, parcel)); } @@ -192,7 +192,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) { gSavedSettings.setWarning("QuickTimeInstalled", FALSE); - LLNotifyBox::showXml("NoQuickTime" ); + LLNotifications::instance().add("NoQuickTime" ); }; } } @@ -382,9 +382,9 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * } } -void callback_play_media(S32 option, void* data) +bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel) { - LLParcel* parcel = (LLParcel*)data; + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); @@ -395,6 +395,6 @@ void callback_play_media(S32 option, void* data) gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); } gSavedSettings.setWarning("FirstStreamingVideo", FALSE); - + return false; } diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 6e37ec2095..099204e740 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -90,7 +90,7 @@ void callback_prepare_video(S32 option, void* data); void prepare_video(const LLParcel *parcelp); void start_video(const LLParcel *parcelp); void stop_video(); -void callback_god_force_owner(S32 option, void* user_data); +bool callback_god_force_owner(const LLSD&, const LLSD&); struct LLGodForceOwnerData { @@ -515,7 +515,7 @@ LLParcelSelectionHandle LLViewerParcelMgr::selectLand(const LLVector3d &corner1, if (region != region_other) { - LLNotifyBox::showXml("CantSelectLandFromMultipleRegions"); + LLNotifications::instance().add("CantSelectLandFromMultipleRegions"); mSelected = FALSE; notifyObservers(); return NULL; @@ -904,7 +904,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) { if (!mSelected) { - gViewerWindow->alertXml("CannotSetLandOwnerNothingSelected"); + LLNotifications::instance().add("CannotSetLandOwnerNothingSelected"); return; } @@ -919,7 +919,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) if (!region) { // TODO: Add a force owner version of this alert. - gViewerWindow->alertXml("CannotContentifyNoRegion"); + LLNotifications::instance().add("CannotContentifyNoRegion"); return; } @@ -927,29 +927,33 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check ); if (region != region2) { - gViewerWindow->alertXml("CannotSetLandOwnerMultipleRegions"); + LLNotifications::instance().add("CannotSetLandOwnerMultipleRegions"); return; } llinfos << "Region " << region->getOriginGlobal() << llendl; - LLGodForceOwnerData* data = new LLGodForceOwnerData(owner_id, mCurrentParcel->getLocalID(), region->getHost()); + LLSD payload; + payload["owner_id"] = owner_id; + payload["parcel_local_id"] = mCurrentParcel->getLocalID(); + payload["region_host"] = region->getHost().getIPandPort(); + LLNotification::Params params("ForceOwnerAuctionWarning"); + params.payload(payload).functor(callback_god_force_owner); + if(mCurrentParcel->getAuctionID()) { - gViewerWindow->alertXml("ForceOwnerAuctionWarning", - callback_god_force_owner, - (void*)data); + LLNotifications::instance().add(params); } else { - callback_god_force_owner(0, (void*)data); + LLNotifications::instance().forceResponse(params, 0); } } -void callback_god_force_owner(S32 option, void* user_data) +bool callback_god_force_owner(const LLSD& notification, const LLSD& response) { - LLGodForceOwnerData* data = (LLGodForceOwnerData*)user_data; - if(data && (0 == option)) + S32 option = LLNotification::getSelectedOption(notification, response); + if(0 == option) { LLMessageSystem* msg = gMessageSystem; msg->newMessage("ParcelGodForceOwner"); @@ -957,24 +961,24 @@ void callback_god_force_owner(S32 option, void* user_data) msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->nextBlock("Data"); - msg->addUUID("OwnerID", data->mOwnerID); - msg->addS32( "LocalID", data->mLocalID); - msg->sendReliable(data->mHost); + msg->addUUID("OwnerID", notification["payload"]["owner_id"].asUUID()); + msg->addS32( "LocalID", notification["payload"]["parcel_local_id"].asInteger()); + msg->sendReliable(LLHost(notification["payload"]["region_host"].asString())); } - delete data; + return false; } void LLViewerParcelMgr::sendParcelGodForceToContent() { if (!mSelected) { - gViewerWindow->alertXml("CannotContentifyNothingSelected"); + LLNotifications::instance().add("CannotContentifyNothingSelected"); return; } LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) { - gViewerWindow->alertXml("CannotContentifyNoRegion"); + LLNotifications::instance().add("CannotContentifyNoRegion"); return; } @@ -992,14 +996,14 @@ void LLViewerParcelMgr::sendParcelRelease() { if (!mSelected) { - gViewerWindow->alertXml("CannotReleaseLandNothingSelected"); + LLNotifications::instance().add("CannotReleaseLandNothingSelected"); return; } LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) { - gViewerWindow->alertXml("CannotReleaseLandNoRegion"); + LLNotifications::instance().add("CannotReleaseLandNoRegion"); return; } @@ -1054,14 +1058,14 @@ LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy( { if (!mSelected || !mCurrentParcel) { - gViewerWindow->alertXml("CannotBuyLandNothingSelected"); + LLNotifications::instance().add("CannotBuyLandNothingSelected"); return NULL; } LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) { - gViewerWindow->alertXml("CannotBuyLandNoRegion"); + LLNotifications::instance().add("CannotBuyLandNoRegion"); return NULL; } @@ -1079,7 +1083,7 @@ LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy( if (region != region2) { - gViewerWindow->alertXml("CantBuyLandAcrossMultipleRegions"); + LLNotifications::instance().add("CantBuyLandAcrossMultipleRegions"); return NULL; } } @@ -1160,18 +1164,18 @@ void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id) { if (!mSelected || !mCurrentParcel) { - gViewerWindow->alertXml("CannotDeedLandNothingSelected"); + LLNotifications::instance().add("CannotDeedLandNothingSelected"); return; } if(group_id.isNull()) { - gViewerWindow->alertXml("CannotDeedLandNoGroup"); + LLNotifications::instance().add("CannotDeedLandNoGroup"); return; } LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) { - gViewerWindow->alertXml("CannotDeedLandNoRegion"); + LLNotifications::instance().add("CannotDeedLandNoRegion"); return; } @@ -1908,26 +1912,27 @@ void LLViewerParcelMgr::deedLandToGroup() { std::string group_name; gCacheName->getGroupName(mCurrentParcel->getGroupID(), group_name); - LLStringUtil::format_map_t args; - args["[AREA]"] = llformat("%d", mCurrentParcel->getArea()); - args["[GROUP_NAME]"] = group_name; + LLSD args; + args["AREA"] = llformat("%d", mCurrentParcel->getArea()); + args["GROUP_NAME"] = group_name; if(mCurrentParcel->getContributeWithDeed()) { std::string first_name, last_name; gCacheName->getName(mCurrentParcel->getOwnerID(), first_name, last_name); - args["[FIRST_NAME]"] = first_name; - args["[LAST_NAME]"] = last_name; - gViewerWindow->alertXml("DeedLandToGroupWithContribution",args, deedAlertCB, NULL); + args["FIRST_NAME"] = first_name; + args["LAST_NAME"] = last_name; + LLNotifications::instance().add("DeedLandToGroupWithContribution",args, LLSD(), deedAlertCB); } else { - gViewerWindow->alertXml("DeedLandToGroup",args, deedAlertCB, NULL); + LLNotifications::instance().add("DeedLandToGroup",args, LLSD(), deedAlertCB); } } // static -void LLViewerParcelMgr::deedAlertCB(S32 option, void*) +bool LLViewerParcelMgr::deedAlertCB(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { LLParcel* parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); @@ -1938,6 +1943,7 @@ void LLViewerParcelMgr::deedAlertCB(S32 option, void*) } LLViewerParcelMgr::getInstance()->sendParcelDeed(group_id); } + return false; } @@ -1945,26 +1951,26 @@ void LLViewerParcelMgr::startReleaseLand() { if (!mSelected) { - gViewerWindow->alertXml("CannotReleaseLandNothingSelected"); + LLNotifications::instance().add("CannotReleaseLandNothingSelected"); return; } if (mRequestResult == PARCEL_RESULT_NO_DATA) { - gViewerWindow->alertXml("CannotReleaseLandWatingForServer"); + LLNotifications::instance().add("CannotReleaseLandWatingForServer"); return; } if (mRequestResult == PARCEL_RESULT_MULTIPLE) { - gViewerWindow->alertXml("CannotReleaseLandSelected"); + LLNotifications::instance().add("CannotReleaseLandSelected"); return; } if (!isParcelOwnedByAgent(mCurrentParcel, GP_LAND_RELEASE) && !(gAgent.canManageEstate())) { - gViewerWindow->alertXml("CannotReleaseLandDontOwn"); + LLNotifications::instance().add("CannotReleaseLandDontOwn"); return; } @@ -1972,31 +1978,30 @@ void LLViewerParcelMgr::startReleaseLand() LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); if (!region) { - gViewerWindow->alertXml("CannotReleaseLandRegionNotFound"); + LLNotifications::instance().add("CannotReleaseLandRegionNotFound"); return; } /* if ((region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) && !gAgent.isGodlike()) { - LLStringUtil::format_map_t args; - args["[REGION]"] = region->getName(); - gViewerWindow->alertXml("CannotReleaseLandNoTransfer", args); + LLSD args; + args["REGION"] = region->getName(); + LLNotifications::instance().add("CannotReleaseLandNoTransfer", args); return; } */ if (!mCurrentParcelSelection->mWholeParcelSelected) { - gViewerWindow->alertXml("CannotReleaseLandPartialSelection"); + LLNotifications::instance().add("CannotReleaseLandPartialSelection"); return; } // Compute claim price - LLStringUtil::format_map_t args; - args["[AREA]"] = llformat("%d",mCurrentParcel->getArea()); - gViewerWindow->alertXml("ReleaseLandWarning", args, - releaseAlertCB, this); + LLSD args; + args["AREA"] = llformat("%d",mCurrentParcel->getArea()); + LLNotifications::instance().add("ReleaseLandWarning", args, LLSD(), releaseAlertCB); } bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const @@ -2052,38 +2057,42 @@ void LLViewerParcelMgr::startDivideLand() { if (!mSelected) { - gViewerWindow->alertXml("CannotDivideLandNothingSelected"); + LLNotifications::instance().add("CannotDivideLandNothingSelected"); return; } if (mCurrentParcelSelection->mWholeParcelSelected) { - gViewerWindow->alertXml("CannotDivideLandPartialSelection"); + LLNotifications::instance().add("CannotDivideLandPartialSelection"); return; } - gViewerWindow->alertXml("LandDivideWarning", - callbackDivideLand, - this); + LLSD payload; + payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth); + payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth); + + LLNotifications::instance().add("LandDivideWarning", LLSD(), payload, callbackDivideLand); } // static -void LLViewerParcelMgr::callbackDivideLand(S32 option, void* data) +bool LLViewerParcelMgr::callbackDivideLand(const LLSD& notification, const LLSD& response) { - LLViewerParcelMgr* self = (LLViewerParcelMgr*)data; + S32 option = LLNotification::getSelectedOption(notification, response); + LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]); + LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]); + LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0; - LLVector3d parcel_center = (self->mWestSouth + self->mEastNorth) / 2.0; LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); if (!region) { - gViewerWindow->alertXml("CannotDivideLandNoRegion"); - return; + LLNotifications::instance().add("CannotDivideLandNoRegion"); + return false; } if (0 == option) { - LLVector3 west_south = region->getPosRegionFromGlobal(self->mWestSouth); - LLVector3 east_north = region->getPosRegionFromGlobal(self->mEastNorth); + LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d); + LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d); LLMessageSystem* msg = gMessageSystem; msg->newMessage("ParcelDivide"); @@ -2097,6 +2106,7 @@ void LLViewerParcelMgr::callbackDivideLand(S32 option, void* data) msg->addF32("North", east_north.mV[VY]); msg->sendReliable(region->getHost()); } + return false; } @@ -2104,44 +2114,48 @@ void LLViewerParcelMgr::startJoinLand() { if (!mSelected) { - gViewerWindow->alertXml("CannotJoinLandNothingSelected"); + LLNotifications::instance().add("CannotJoinLandNothingSelected"); return; } if (mCurrentParcelSelection->mWholeParcelSelected) { - gViewerWindow->alertXml("CannotJoinLandEntireParcelSelected"); + LLNotifications::instance().add("CannotJoinLandEntireParcelSelected"); return; } if (!mCurrentParcelSelection->mSelectedMultipleOwners) { - gViewerWindow->alertXml("CannotJoinLandSelection"); + LLNotifications::instance().add("CannotJoinLandSelection"); return; } - gViewerWindow->alertXml("JoinLandWarning", - callbackJoinLand, - this); + LLSD payload; + payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth); + payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth); + + LLNotifications::instance().add("JoinLandWarning", LLSD(), payload, callbackJoinLand); } // static -void LLViewerParcelMgr::callbackJoinLand(S32 option, void* data) +bool LLViewerParcelMgr::callbackJoinLand(const LLSD& notification, const LLSD& response) { - LLViewerParcelMgr* self = (LLViewerParcelMgr*)data; + S32 option = LLNotification::getSelectedOption(notification, response); + LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]); + LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]); + LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0; - LLVector3d parcel_center = (self->mWestSouth + self->mEastNorth) / 2.0; LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); if (!region) { - gViewerWindow->alertXml("CannotJoinLandNoRegion"); - return; + LLNotifications::instance().add("CannotJoinLandNoRegion"); + return false; } if (0 == option) { - LLVector3 west_south = region->getPosRegionFromGlobal(self->mWestSouth); - LLVector3 east_north = region->getPosRegionFromGlobal(self->mEastNorth); + LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d); + LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d); LLMessageSystem* msg = gMessageSystem; msg->newMessage("ParcelJoin"); @@ -2155,6 +2169,7 @@ void LLViewerParcelMgr::callbackJoinLand(S32 option, void* data) msg->addF32("North", east_north.mV[VY]); msg->sendReliable(region->getHost()); } + return false; } @@ -2162,19 +2177,19 @@ void LLViewerParcelMgr::startDeedLandToGroup() { if (!mSelected || !mCurrentParcel) { - gViewerWindow->alertXml("CannotDeedLandNothingSelected"); + LLNotifications::instance().add("CannotDeedLandNothingSelected"); return; } if (mRequestResult == PARCEL_RESULT_NO_DATA) { - gViewerWindow->alertXml("CannotDeedLandWaitingForServer"); + LLNotifications::instance().add("CannotDeedLandWaitingForServer"); return; } if (mRequestResult == PARCEL_RESULT_MULTIPLE) { - gViewerWindow->alertXml("CannotDeedLandMultipleSelected"); + LLNotifications::instance().add("CannotDeedLandMultipleSelected"); return; } @@ -2182,7 +2197,7 @@ void LLViewerParcelMgr::startDeedLandToGroup() LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); if (!region) { - gViewerWindow->alertXml("CannotDeedLandNoRegion"); + LLNotifications::instance().add("CannotDeedLandNoRegion"); return; } @@ -2192,9 +2207,9 @@ void LLViewerParcelMgr::startDeedLandToGroup() if((region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) && (mCurrentParcel->getOwnerID() != region->getOwner())) { - LLStringUtil::format_map_t args; - args["[REGION]"] = region->getName(); - gViewerWindow->alertXml("CannotDeedLandNoTransfer", args); + LLSD args; + args["REGION"] = region->getName(); + LLNotifications::instance().add("CannotDeedLandNoTransfer", args); return; } } @@ -2222,13 +2237,15 @@ void LLViewerParcelMgr::reclaimParcel() } // static -void LLViewerParcelMgr::releaseAlertCB(S32 option, void *) +bool LLViewerParcelMgr::releaseAlertCB(const LLSD& notification, const LLSD& response) { + S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { // Send the release message, not a force LLViewerParcelMgr::getInstance()->sendParcelRelease(); } + return false; } void LLViewerParcelMgr::buyPass() diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 4326e07e46..920423cdfa 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -110,7 +110,7 @@ public: void selectCollisionParcel(); // Select the parcel at a specific point - LLSafeHandle<LLParcelSelection> selectParcelAt(const LLVector3d& pos_global); + LLParcelSelectionHandle selectParcelAt(const LLVector3d& pos_global); // Take the current rectangle select, and select the parcel contained // within it. @@ -259,7 +259,7 @@ public: static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); private: - static void releaseAlertCB(S32 option, void *data); + static bool releaseAlertCB(const LLSD& notification, const LLSD& response); // If the user is claiming land and the current selection // borders a piece of land the user already owns, ask if he @@ -272,12 +272,10 @@ private: // move land from current owner to it's group. void deedLandToGroup(); - static void claimAlertCB(S32 option, void* data); - static void buyAlertCB(S32 option, void* data); - static void deedAlertCB(S32 option, void*); + static bool deedAlertCB(const LLSD& notification, const LLSD& response); - static void callbackDivideLand(S32 option, void* data); - static void callbackJoinLand(S32 option, void* data); + static bool callbackDivideLand(const LLSD& notification, const LLSD& response); + static bool callbackJoinLand(const LLSD& notification, const LLSD& response); //void finishClaim(BOOL user_to_user_sale, U32 join); LLViewerImage* getBlockedImage() const; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index c2c3e7e320..50486137c1 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1420,58 +1420,50 @@ void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item ) void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item ) { - //if (saved) - //{ - // An LLInventoryItem needs to be in an inventory to be opened. - // This will give the item to the viewer's agent. - // The callback will attempt to open it if its not already opened. copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback)); - - //} - //else - //{ - // LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); - // gViewerWindow->alertXml("ConfirmNotecardSave", - // LLViewerTextEditor::onNotecardDialog, (void*)info); - //} } void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item ) { - LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); - gViewerWindow->alertXml( "ConfirmNotecardSave", - LLViewerTextEditor::onNotecardDialog, (void*)info); + LLSD payload; + payload["item_id"] = item->getUUID(); + payload["notecard_id"] = mNotecardInventoryID; + LLNotifications::instance().add( "ConfirmNotecardSave", LLSD(), payload, LLViewerTextEditor::onNotecardDialog); } + // static -void LLViewerTextEditor::onNotecardDialog( S32 option, void* userdata ) +bool LLViewerTextEditor::onNotecardDialog(const LLSD& notification, const LLSD& response ) { - LLNotecardCopyInfo *info = (LLNotecardCopyInfo *)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); if( option == 0 ) { // itemptr is deleted by LLPreview::save - LLPointer<LLInventoryItem>* itemptr = new LLPointer<LLInventoryItem>(info->mItem); - LLPreview::save( info->mTextEd->mNotecardInventoryID, itemptr); + LLPointer<LLInventoryItem>* itemptr = new LLPointer<LLInventoryItem>(gInventory.getItem(notification["payload"]["item_id"].asUUID())); + LLPreview::save( notification["payload"]["notecard_id"].asUUID() , itemptr); } + return false; } void LLViewerTextEditor::showCopyToInvDialog( LLInventoryItem* item ) { - LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item); - gViewerWindow->alertXml( "ConfirmItemCopy", - LLViewerTextEditor::onCopyToInvDialog, (void*)info); + LLSD payload; + payload["item_id"] = item->getUUID(); + payload["notecard_id"] = mNotecardInventoryID; + LLNotifications::instance().add( "ConfirmItemCopy", LLSD(), payload, + boost::bind(&LLViewerTextEditor::onCopyToInvDialog, this, _1, _2)); } -// static -void LLViewerTextEditor::onCopyToInvDialog( S32 option, void* userdata ) +bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD& response) { - LLNotecardCopyInfo *info = (LLNotecardCopyInfo *)userdata; + S32 option = LLNotification::getSelectedOption(notification, response); if( 0 == option ) { - info->mTextEd->copyInventory(info->mItem); + LLInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + copyInventory(itemp); } - delete info; + return false; } diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index 7ce28fc60a..2e1c0f1d86 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -113,8 +113,8 @@ private: void showCopyToInvDialog( LLInventoryItem* item ); void showUnsavedAlertDialog( LLInventoryItem* item ); - static void onCopyToInvDialog( S32 option, void* userdata ); - static void onNotecardDialog( S32 option, void* userdata ); + bool onCopyToInvDialog(const LLSD& notification, const LLSD& response ); + static bool onNotecardDialog(const LLSD& notification, const LLSD& response ); LLPointer<LLInventoryItem> mDragItem; BOOL mDragItemSaved; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 48b4a79afa..a129fac47b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -182,6 +182,9 @@ #include "llviewerjoystick.h" #include "llviewernetwork.h" +#include "llfloatertest.h" // HACK! +#include "llfloaternotificationsconsole.h" + #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods #endif @@ -246,6 +249,7 @@ std::string LLViewerWindow::sMovieBaseName; extern void toggle_debug_menus(void*); + //////////////////////////////////////////////////////////////////////////// // // LLDebugText @@ -1421,6 +1425,13 @@ LLViewerWindow::LLViewerWindow( mIsFullscreenChecked(false), mCurrResolutionIndex(0) { + // these are self registering so they don't need to be retained here + new LLNotificationChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")); + new LLNotificationChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")); + + LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert); + LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert); + // Default to application directory. LLViewerWindow::sSnapshotBaseName = "Snapshot"; LLViewerWindow::sMovieBaseName = "SLmovie"; @@ -1532,8 +1543,6 @@ LLViewerWindow::LLViewerWindow( // Can't have spaces in settings.ini strings, so use underscores instead and convert them. LLStringUtil::replaceChar(mOverlayTitle, '_', ' '); - LLAlertDialog::setDisplayCallback(alertCallback); // call this before calling any modal dialogs - // sync the keyboard's setting with the saved setting gSavedSettings.getControl("NumpadControl")->firePropertyChanged(); @@ -2179,7 +2188,7 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible ) void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) { - LLStringUtil::format_map_t args; + LLSD args; LLColor4 new_bg_color; if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid()) @@ -2232,12 +2241,6 @@ void LLViewerWindow::draw() stop_glerror(); LLUI::setLineWidth(1.f); - //popup alerts from the UI - LLAlertInfo alert; - while (LLPanel::nextAlert(alert)) - { - alertXml(alert.mLabel, alert.mArgs); - } LLUI::setLineWidth(1.f); // Reset any left-over transforms @@ -2421,6 +2424,15 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } } + // Debugging view for unified notifications + if ((MASK_SHIFT & mask) + && (MASK_CONTROL & mask) + && ('N' == key || 'n' == key)) + { + LLFloaterNotificationConsole::showInstance(); + return TRUE; + } + // handle escape key //if (key == KEY_ESCAPE && mask == MASK_NONE) //{ @@ -4909,10 +4921,10 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, if (!result_first_try) { - LLStringUtil::format_map_t args; - args["[RESX]"] = llformat("%d",size.mX); - args["[RESY]"] = llformat("%d",size.mY); - alertXml("ResolutionSwitchFail", args); + LLSD args; + args["RESX"] = llformat("%d",size.mX); + args["RESY"] = llformat("%d",size.mY); + LLNotifications::instance().add("ResolutionSwitchFail", args); size = old_size; // for reshape below } @@ -5027,72 +5039,18 @@ S32 LLViewerWindow::getChatConsoleBottomPad() //---------------------------------------------------------------------------- -// static -bool LLViewerWindow::alertCallback(S32 modal) -{ - if (gNoRender) - { - return false; - } - else - { -// if (modal) // we really always want to take you out of mouselook - { - // If we're in mouselook, the mouse is hidden and so the user can't click - // the dialog buttons. In that case, change to First Person instead. - if( gAgent.cameraMouselook() ) - { - gAgent.changeCameraToDefault(); - } - } - return true; - } -} - -LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, - LLAlertDialog::alert_callback_t callback, void* user_data) -{ - LLStringUtil::format_map_t args; - return alertXml( xml_filename, args, callback, user_data ); -} -LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, const LLStringUtil::format_map_t& args, - LLAlertDialog::alert_callback_t callback, void* user_data) +//static +bool LLViewerWindow::onAlert(const LLSD& notify) { - if (gNoRender) - { - llinfos << "Alert: " << xml_filename << llendl; - if (callback) - { - callback(-1, user_data); - } - return NULL; - } + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); - // If we're in mouselook, the mouse is hidden and so the user can't click - // the dialog buttons. In that case, change to First Person instead. - if( gAgent.cameraMouselook() ) - { - gAgent.changeCameraToDefault(); - } - - // Note: object adds, removes, and destroys itself. - return LLAlertDialog::showXml( xml_filename, args, callback, user_data ); -} - -LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename, const LLStringUtil::format_map_t& args, - LLAlertDialog::alert_callback_t callback, void* user_data, - LLAlertDialog::alert_text_callback_t text_callback, void *text_data, - const LLStringUtil::format_map_t& edit_args, BOOL draw_asterixes) -{ if (gNoRender) { - llinfos << "Alert: " << xml_filename << llendl; - if (callback) - { - callback(-1, user_data); - } - return NULL; + llinfos << "Alert: " << notification->getName() << llendl; + notification->respond(LLSD::emptyMap()); + LLNotifications::instance().cancel(notification); + return false; } // If we're in mouselook, the mouse is hidden and so the user can't click @@ -5101,20 +5059,7 @@ LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename, { gAgent.changeCameraToDefault(); } - - // Note: object adds, removes, and destroys itself. - LLAlertDialog* alert = LLAlertDialog::createXml( xml_filename, args, callback, user_data ); - if (alert) - { - if (text_callback) - { - alert->setEditTextCallback(text_callback, text_data); - } - alert->setEditTextArgs(edit_args); - alert->setDrawAsterixes(draw_asterixes); - alert->show(); - } - return alert; + return false; } //////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 6309cec819..d6c27a31bc 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -47,6 +47,7 @@ #include "lltimer.h" #include "llstat.h" #include "llalertdialog.h" +#include "llnotifications.h" class LLView; class LLViewerObject; @@ -353,20 +354,10 @@ public: void drawPickBuffer() const; - LLAlertDialog* alertXml(const std::string& xml_filename, - LLAlertDialog::alert_callback_t callback = NULL, void* user_data = NULL); - LLAlertDialog* alertXml(const std::string& xml_filename, const LLStringUtil::format_map_t& args, - LLAlertDialog::alert_callback_t callback = NULL, void* user_data = NULL); - LLAlertDialog* alertXmlEditText(const std::string& xml_filename, const LLStringUtil::format_map_t& args, - LLAlertDialog::alert_callback_t callback, void* user_data, - LLAlertDialog::alert_text_callback_t text_callback, void *text_data, - const LLStringUtil::format_map_t& edit_args = LLStringUtil::format_map_t(), - BOOL draw_asterixes = FALSE); - - static bool alertCallback(S32 modal); - private: bool shouldShowToolTipFor(LLMouseHandler *mh); + static bool onAlert(const LLSD& notify); + void switchToolByMask(MASK mask); void destroyWindow(); void drawMouselookInstructions(); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index d416ae5bf6..d644ad5085 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -109,12 +109,6 @@ void LLVOGrass::updateSpecies() } -void alert_done(S32 option, void* user_data) -{ - return; -} - - void LLVOGrass::initClass() { LLVector3 pos(0.0f, 0.0f, 0.0f); @@ -224,9 +218,9 @@ void LLVOGrass::initClass() if (!have_all_grass) { - LLStringUtil::format_map_t args; - args["[SPECIES]"] = err; - gViewerWindow->alertXml("ErrorUndefinedGrasses", args, alert_done ); + LLSD args; + args["SPECIES"] = err; + LLNotifications::instance().add("ErrorUndefinedGrasses", args); } for (S32 i = 0; i < GRASS_MAX_BLADES; ++i) diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 8b1eba11a0..fb28420715 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -4188,7 +4188,7 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode if (!sAlertedUser) { //sAlertedUser = TRUE; - gViewerWindow->alertXml("VoiceVersionMismatch"); + LLNotifications::instance().add("VoiceVersionMismatch"); gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener } } diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 7e3b96eb8f..486ecb82e3 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -253,9 +253,9 @@ void LLVOTree::initClass() if (!have_all_trees) { - LLStringUtil::format_map_t args; - args["[SPECIES]"] = err; - gViewerWindow->alertXml("ErrorUndefinedTrees", args ); + LLSD args; + args["SPECIES"] = err; + LLNotifications::instance().add("ErrorUndefinedTrees", args); } }; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index ef077101e9..c473fed04a 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -867,9 +867,9 @@ void LLWearable::saveNewAsset() std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); llwarns << buffer << llendl; - LLStringUtil::format_map_t args; - args["[NAME]"] = mName; - gViewerWindow->alertXml("CannotSaveWearableOutOfSpace", args); + LLSD args; + args["NAME"] = mName; + LLNotifications::instance().add("CannotSaveWearableOutOfSpace", args); return; } @@ -915,9 +915,9 @@ void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userda { std::string buffer = llformat("Unable to save %s to central asset store.", type_name.c_str()); llwarns << buffer << " Status: " << status << llendl; - LLStringUtil::format_map_t args; - args["[NAME]"] = type_name; - gViewerWindow->alertXml("CannotSaveToAssetStore", args); + LLSD args; + args["NAME"] = type_name; + LLNotifications::instance().add("CannotSaveToAssetStore", args); } // Delete temp file diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index a32c43302d..70719b827c 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -149,27 +149,27 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID { // Fail break; - } + } default: - { + { static const S32 MAX_RETRIES = 3; if (data->mRetries < MAX_RETRIES) { - // Try again + // Try again data->mRetries++; - gAssetStorage->getAssetData(uuid, - data->mAssetType, - LLWearableList::processGetAssetReply, - userdata); // re-use instead of deleting. - return; - } + gAssetStorage->getAssetData(uuid, + data->mAssetType, + LLWearableList::processGetAssetReply, + userdata); // re-use instead of deleting. + return; + } else { // Fail break; } } - } + } } if (wearable) // success @@ -180,17 +180,17 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID } else { - LLStringUtil::format_map_t args; + LLSD args; // *TODO:translate - args["[TYPE]"] = LLAssetType::lookupHumanReadable(data->mAssetType); + args["TYPE"] = LLAssetType::lookupHumanReadable(data->mAssetType); if (data->mName.empty()) { - LLNotifyBox::showXml("FailedToFindWearableUnnamed", args); + LLNotifications::instance().add("FailedToFindWearableUnnamed", args); } else { - args["[DESC]"] = data->mName; - LLNotifyBox::showXml("FailedToFindWearable", args); + args["DESC"] = data->mName; + LLNotifications::instance().add("FailedToFindWearable", args); } } // Always call callback; wearable will be NULL if we failed diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp index 1abf760580..9f8ddc1029 100644 --- a/indra/newview/llwldaycycle.cpp +++ b/indra/newview/llwldaycycle.cpp @@ -82,9 +82,9 @@ void LLWLDayCycle::loadDayCycle(const std::string & fileName) if(!success) { // alert the user - LLStringUtil::format_map_t args; - args["[SKY]"] = day_data[i][1].asString(); - gViewerWindow->alertXml("WLMissingSky", args); + LLSD args; + args["SKY"] = day_data[i][1].asString(); + LLNotifications::instance().add("WLMissingSky", args); continue; } diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index d9c6b6c58a..7fbcaf6c21 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -417,28 +417,10 @@ void LLXMLRPCTransaction::Impl::setStatus(Status status, mStatusMessage = "Despite our best efforts, something unexpected has gone wrong. \n" " \n" - "Please check www.secondlife.com/status \n" + "Please check secondlife.com/status \n" "to see if there is a known problem with the service."; mStatusURI = "http://secondlife.com/status/"; - /* - mStatusMessage = - "Despite our best efforts, something unexpected has gone wrong.\n" - "Please go to the Support section of the SecondLife.com web site\n" - "and report the problem. If possible, include your SecondLife.log\n" - "file from:\n" -#if LL_WINDOWS - "C:\\Documents and Settings\\<name>\\Application Data\\SecondLife\\logs\n" -#elif LL_DARWIN - "~/Library/Application Support/SecondLife/logs\n" -#elif LL_LINUX - "~/.secondlife/logs\n" -#else -#error "Need platform here." -#endif - "Thank you."; - mStatusURI = "http://secondlife.com/community/support.php"; - */ } } } |