diff options
75 files changed, 1032 insertions, 416 deletions
diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp index cf509bee14..689f649d0a 100644 --- a/indra/llcommon/llformat.cpp +++ b/indra/llcommon/llformat.cpp @@ -37,16 +37,40 @@ #include <cstdarg> -std::string llformat(const char *fmt, ...) +// common used function with va_list argument +// wrapper for vsnprintf to be called from llformatXXX functions. +static void va_format(std::string& out, const char *fmt, va_list va) { char tstr[1024]; /* Flawfinder: ignore */ - va_list va; - va_start(va, fmt); #if LL_WINDOWS _vsnprintf(tstr, 1024, fmt, va); #else vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ #endif + out.assign(tstr); +} + +std::string llformat(const char *fmt, ...) +{ + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); va_end(va); - return std::string(tstr); + return res; +} + +std::string llformat_to_utf8(const char *fmt, ...) +{ + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); + va_end(va); + +#if LL_WINDOWS + // made converting to utf8. See EXT-8318. + res = ll_convert_string_to_utf8_string(res); +#endif + return res; } diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h index dc64edb26d..17d8b4a8ad 100644 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -42,4 +42,8 @@ std::string LL_COMMON_API llformat(const char *fmt, ...); +// the same version as above but ensures that returned string is in utf8 on windows +// to enable correct converting utf8_to_wstring. +std::string LL_COMMON_API llformat_to_utf8(const char *fmt, ...); + #endif // LL_LLFORMAT_H diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 1561bda201..671b0a108c 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -633,14 +633,14 @@ namespace snprintf_hack } } -std::string ll_convert_wide_to_string(const wchar_t* in) +std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) { std::string out; if(in) { int len_in = wcslen(in); int len_out = WideCharToMultiByte( - CP_ACP, + code_page, 0, in, len_in, @@ -655,7 +655,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in) if(pout) { WideCharToMultiByte( - CP_ACP, + code_page, 0, in, len_in, @@ -669,6 +669,38 @@ std::string ll_convert_wide_to_string(const wchar_t* in) } return out; } + +wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page) +{ + // From review: + // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
+ // plus one for a null terminator, and be guaranteed to not overflow.
+
+ // Normally, I'd call that sort of thing premature optimization, + // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets. +// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0); + + // reserve place to NULL terminator + int output_str_len = in.length(); + wchar_t* w_out = new wchar_t[output_str_len + 1]; + + memset(w_out, 0, output_str_len + 1); + int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len); + + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. + w_out[real_output_str_len] = 0; + + return w_out; +} + +std::string ll_convert_string_to_utf8_string(const std::string& in) +{ + wchar_t* w_mesg = ll_convert_string_to_wide(in, CP_ACP); + std::string out_utf8(ll_convert_wide_to_string(w_mesg, CP_UTF8)); + delete[] w_mesg; + + return out_utf8; +} #endif // LL_WINDOWS long LLStringOps::sPacificTimeOffset = 0; diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 8071c8aa2d..41fac0f8cc 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -564,7 +564,20 @@ using snprintf_hack::snprintf; * * This replaces the unsafe W2A macro from ATL. */ -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page); + +/** + * Converts a string to wide string. + * + * It will allocate memory for result string with "new []". Don't forget to release it with "delete []". + */ +LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page); + +/** + * Converts incoming string into urf8 string + * + */ +LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in); //@} #endif // LL_WINDOWS diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 36874a5d48..ac50411de8 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -364,13 +364,6 @@ U32 LLCurl::Easy::report(CURLcode code) responseCode = 499; responseReason = strerror(code) + " : " + mErrorBuffer; } - - if(responseCode >= 300 && responseCode < 400) //redirect - { - char new_url[512] ; - curl_easy_getinfo(mCurlEasyHandle, CURLINFO_REDIRECT_URL, new_url); - responseReason = new_url ; //get the new URL. - } if (mResponder) { @@ -469,6 +462,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback); setopt(CURLOPT_HEADERDATA, (void*)this); + // Allow up to five redirects + if(responder && responder->followRedir()) + { + setopt(CURLOPT_FOLLOWLOCATION, 1); + setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS); + } + setErrorBuffer(); setCA(); @@ -1061,3 +1061,4 @@ void LLCurl::cleanupClass() curl_global_cleanup(); } +const unsigned int LLCurl::MAX_REDIRECTS = 5; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index b6a637ae5b..20ca87c87b 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -123,6 +123,11 @@ public: // Used internally to set the url for debugging later. void setURL(const std::string& url); + virtual bool followRedir() + { + return false; + } + public: /* but not really -- don't touch this */ U32 mReferenceCount; @@ -182,6 +187,7 @@ public: private: static std::string sCAPath; static std::string sCAFile; + static const unsigned int MAX_REDIRECTS; }; namespace boost diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e22f8d2ddc..1a48c8a06c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -109,11 +109,20 @@ void LLImageGL::checkTexSize(bool forced) const { if ((forced || gDebugGL) && mTarget == GL_TEXTURE_2D) { + { + //check viewport + GLint vp[4] ; + glGetIntegerv(GL_VIEWPORT, vp) ; + llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ; + } + GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); BOOL error = FALSE; if (texname != mTexName) { + llinfos << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << llendl; + error = TRUE; if (gDebugSession) { diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 673631f99a..2bc8ea054a 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -811,6 +811,31 @@ void LLAccordionCtrl::reset () mScrollbar->setDocPos(0); } +void LLAccordionCtrl::expandDefaultTab() +{ + if (mAccordionTabs.size() > 0) + { + LLAccordionCtrlTab* tab = mAccordionTabs.front(); + + if (!tab->getDisplayChildren()) + { + tab->setDisplayChildren(true); + } + + for (size_t i = 1; i < mAccordionTabs.size(); ++i) + { + tab = mAccordionTabs[i]; + + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } + + arrange(); + } +} + void LLAccordionCtrl::sort() { if (!mTabComparator) diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index b5fdf796cd..8241ee1518 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -122,6 +122,7 @@ public: S32 notifyParent(const LLSD& info); void reset (); + void expandDefaultTab(); void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } void sort(); diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index 3d32157406..0c524cd470 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -81,17 +81,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) // must be big enough to hold all children setUseBoundingRect(TRUE); - // Label (add a little space to make sure text actually renders) - const S32 FUDGE = 10; - S32 text_width = mFont->getWidth( p.label ) + FUDGE; - S32 text_height = llround(mFont->getLineHeight()); - LLRect label_rect; - label_rect.setOriginAndSize( - llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, - llcheckboxctrl_vpad + 1, // padding to get better alignment - text_width + llcheckboxctrl_hpad, - text_height ); - // *HACK Get rid of this with SL-55508... // this allows blank check boxes and radio boxes for now std::string local_label = p.label; @@ -101,7 +90,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) } LLTextBox::Params tbparams = p.label_text; - tbparams.rect(label_rect); tbparams.initial_value(local_label); if (p.font.isProvided()) { @@ -111,6 +99,17 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams); addChild(mLabel); + S32 text_width = mLabel->getTextBoundingRect().getWidth(); + S32 text_height = llround(mFont->getLineHeight()); + LLRect label_rect; + label_rect.setOriginAndSize( + llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, + llcheckboxctrl_vpad + 1, // padding to get better alignment + text_width + llcheckboxctrl_hpad, + text_height ); + mLabel->setShape(label_rect); + + // Button // Note: button cover the label by extending all the way to the right. LLRect btn_rect; @@ -190,8 +189,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); - const S32 FUDGE = 10; - S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE; + S32 text_width = mLabel->getTextBoundingRect().getWidth(); S32 text_height = llround(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( @@ -199,7 +197,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) llcheckboxctrl_vpad, text_width, text_height ); - mLabel->setRect(label_rect); + mLabel->setShape(label_rect); LLRect btn_rect; btn_rect.setOriginAndSize( @@ -207,7 +205,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) llcheckboxctrl_vpad, llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width, llmax( text_height, llcheckboxctrl_btn_size() ) ); - mButton->setRect( btn_rect ); + mButton->setShape( btn_rect ); LLUICtrl::reshape(width, height, called_from_parent); } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 39a6855273..22d6f6ca52 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -451,6 +451,14 @@ void LLFloater::enableResizeCtrls(bool enable) } } +void LLFloater::destroy() +{ + // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before + // it was deleted via LLMortician::updateClass(). See EXT-8458. + LLFloaterReg::removeInstance(mInstanceName, mKey); + die(); +} + // virtual LLFloater::~LLFloater() { diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 3ea035777c..42f422f91c 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -308,7 +308,7 @@ protected: BOOL getAutoFocus() const { return mAutoFocus; } LLDragHandle* getDragHandle() const { return mDragHandle; } - void destroy() { die(); } // Don't call this directly. You probably want to call closeFloater() + void destroy(); // Don't call this directly. You probably want to call closeFloater() virtual void onClickCloseBtn(); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index b4a1bcb7c5..8610d79142 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -218,6 +218,12 @@ void LLMenuItemGL::setValue(const LLSD& value) } //virtual +LLSD LLMenuItemGL::getValue() const +{ + return getLabel(); +} + +//virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 7668f301ea..a484405eaa 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -95,6 +95,7 @@ public: // LLUICtrl overrides /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index ed870d46d5..9158bc70f5 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -298,11 +298,11 @@ void LLResMgr::getIntegerString( std::string& output, S32 input ) const { if (fraction == remaining_count) { - fraction_string = llformat("%d%c", fraction, getThousandsSeparator()); + fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator()); } else { - fraction_string = llformat("%3.3d%c", fraction, getThousandsSeparator()); + fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator()); } output = fraction_string + output; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 53b7febba7..e85d108bb2 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3079,7 +3079,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * return; } - if (gAgentCamera.cameraCustomizeAvatar()) + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) { // ignore baked textures when in customize mode return; @@ -3548,7 +3548,7 @@ void LLAgent::sendAgentSetAppearance() { if (!isAgentAvatarValid()) return; - if (gAgentQueryManager.mNumPendingQueries > 0 && !gAgentCamera.cameraCustomizeAvatar()) + if (gAgentQueryManager.mNumPendingQueries > 0 && (isAgentAvatarValid() && gAgentAvatarp->isUsingBakedTextures())) { return; } diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 1ef9e34f87..4dc78e9a1d 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -941,7 +941,7 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) */ } - if( cameraCustomizeAvatar() ) + if(cameraCustomizeAvatar()) { new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index d2449abf08..b64007aa75 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1801,9 +1801,9 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool llinfos << "wearInventoryCategory( " << category->getName() << " )" << llendl; - callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, - &LLAppearanceMgr::instance(), - category->getUUID(), copy, append)); + callAfterCategoryFetch(category->getUUID(), boost::bind(&LLAppearanceMgr::wearCategoryFinal, + &LLAppearanceMgr::instance(), + category->getUUID(), copy, append)); } void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) @@ -2699,6 +2699,21 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const return gInventory.isObjectDescendentOf(obj_id, getCOF()); } +// static +bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + find_links); + + return !items.empty(); +} + BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const { if (!getIsInCOF(obj_id)) return FALSE; @@ -2726,3 +2741,192 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const return FALSE; */ } + +// Shim class to allow arbitrary boost::bind +// expressions to be run as one-time idle callbacks. +// +// TODO: rework idle function spec to take a boost::function in the first place. +class OnIdleCallbackOneTime +{ +public: + OnIdleCallbackOneTime(nullary_func_t callable): + mCallable(callable) + { + } + static void onIdle(void *data) + { + gIdleCallbacks.deleteFunction(onIdle, data); + OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); + self->call(); + delete self; + } + void call() + { + mCallable(); + } +private: + nullary_func_t mCallable; +}; + +void doOnIdleOneTime(nullary_func_t callable) +{ + OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); +} + +// Shim class to allow generic boost functions to be run as +// recurring idle callbacks. Callable should return true when done, +// false to continue getting called. +// +// TODO: rework idle function spec to take a boost::function in the first place. +class OnIdleCallbackRepeating +{ +public: + OnIdleCallbackRepeating(bool_func_t callable): + mCallable(callable) + { + } + // Will keep getting called until the callable returns true. + static void onIdle(void *data) + { + OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); + bool done = self->call(); + if (done) + { + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; + } + } + bool call() + { + return mCallable(); + } +private: + bool_func_t mCallable; +}; + +void doOnIdleRepeating(bool_func_t callable) +{ + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); +} + +class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver +{ +public: + CallAfterCategoryFetchStage2(const uuid_vec_t& ids, + nullary_func_t callable) : + LLInventoryFetchItemsObserver(ids), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage2() + { + } + virtual void done() + { + llinfos << this << " done with incomplete " << mIncomplete.size() + << " complete " << mComplete.size() << " calling callable" << llendl; + + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); + delete this; + } +protected: + nullary_func_t mCallable; +}; + +class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver +{ +public: + CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : + LLInventoryFetchDescendentsObserver(cat_id), + mCallable(callable) + { + } + ~CallAfterCategoryFetchStage1() + { + } + virtual void done() + { + // What we do here is get the complete information on the items in + // the library, and set up an observer that will wait for that to + // happen. + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(mComplete.front(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + S32 count = item_array.count(); + if(!count) + { + llwarns << "Nothing fetched in category " << mComplete.front() + << llendl; + //dec_busy_count(); + gInventory.removeObserver(this); + + // lets notify observers that loading is finished. + gAgentWearables.notifyLoadingFinished(); + delete this; + return; + } + + llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl; + uuid_vec_t ids; + for(S32 i = 0; i < count; ++i) + { + ids.push_back(item_array.get(i)->getUUID()); + } + + gInventory.removeObserver(this); + + // do the fetch + CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); + stage2->startFetch(); + if(stage2->isFinished()) + { + // everything is already here - call done. + stage2->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(stage2); + } + delete this; + } +protected: + nullary_func_t mCallable; +}; + +void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb) +{ + CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb); + stage1->startFetch(); + if (stage1->isFinished()) + { + stage1->done(); + } + else + { + gInventory.addObserver(stage1); + } +} + +void wear_multiple(const uuid_vec_t& ids, bool replace) +{ + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; + + bool first = true; + uuid_vec_t::const_iterator it; + for (it = ids.begin(); it != ids.end(); ++it) + { + // if replace is requested, the first item worn will replace the current top + // item, and others will be added. + LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb); + first = false; + } +} + diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 84c911c038..9f554dbdef 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -223,6 +223,11 @@ public: BOOL getIsInCOF(const LLUUID& obj_id) const; // Is this in the COF and can the user delete it from the COF? BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; + + /** + * Checks if COF contains link to specified object. + */ + static bool isLinkInCOF(const LLUUID& obj_id); }; class LLUpdateAppearanceOnDestroy: public LLInventoryCallback @@ -242,180 +247,19 @@ private: LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); -// Shim class and template function to allow arbitrary boost::bind -// expressions to be run as one-time idle callbacks. -template <typename T> -class OnIdleCallbackOneTime -{ -public: - OnIdleCallbackOneTime(T callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime<T>* self = reinterpret_cast<OnIdleCallbackOneTime<T>*>(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } -private: - T mCallable; -}; +typedef boost::function<void ()> nullary_func_t; +typedef boost::function<bool ()> bool_func_t; -template <typename T> -void doOnIdleOneTime(T callable) -{ - OnIdleCallbackOneTime<T>* cb_functor = new OnIdleCallbackOneTime<T>(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime<T>::onIdle,cb_functor); -} - -// Shim class and template function to allow arbitrary boost::bind -// expressions to be run as recurring idle callbacks. -// Callable should return true when done, false to continue getting called. -template <typename T> -class OnIdleCallbackRepeating -{ -public: - OnIdleCallbackRepeating(T callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating<T>* self = reinterpret_cast<OnIdleCallbackRepeating<T>*>(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } -private: - T mCallable; -}; +// Call a given callable once in idle loop. +void doOnIdleOneTime(nullary_func_t callable); -template <typename T> -void doOnIdleRepeating(T callable) -{ - OnIdleCallbackRepeating<T>* cb_functor = new OnIdleCallbackRepeating<T>(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating<T>::onIdle,cb_functor); -} +// Repeatedly call a callable in idle loop until it returns true. +void doOnIdleRepeating(bool_func_t callable); -template <class T> -class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver -{ -public: - CallAfterCategoryFetchStage2(const uuid_vec_t& ids, - T callable) : - LLInventoryFetchItemsObserver(ids), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage2() - { - } - virtual void done() - { - llinfos << this << " done with incomplete " << mIncomplete.size() - << " complete " << mComplete.size() << " calling callable" << llendl; - - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); - delete this; - } -protected: - T mCallable; -}; +// Invoke a given callable after category contents are fully fetched. +void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb); -template <class T> -class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver -{ -public: - CallAfterCategoryFetchStage1(const LLUUID& cat_id, T callable) : - LLInventoryFetchDescendentsObserver(cat_id), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage1() - { - } - virtual void done() - { - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mComplete.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); - if(!count) - { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; - //dec_busy_count(); - gInventory.removeObserver(this); - - // lets notify observers that loading is finished. - gAgentWearables.notifyLoadingFinished(); - delete this; - return; - } - - llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl; - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(item_array.get(i)->getUUID()); - } - - gInventory.removeObserver(this); - - // do the fetch - CallAfterCategoryFetchStage2<T> *stage2 = new CallAfterCategoryFetchStage2<T>(ids, mCallable); - stage2->startFetch(); - if(stage2->isFinished()) - { - // everything is already here - call done. - stage2->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(stage2); - } - delete this; - } -protected: - T mCallable; -}; - -template <class T> -void callAfterCategoryFetch(const LLUUID& cat_id, T callable) -{ - CallAfterCategoryFetchStage1<T> *stage1 = new CallAfterCategoryFetchStage1<T>(cat_id, callable); - stage1->startFetch(); - if (stage1->isFinished()) - { - stage1->done(); - } - else - { - gInventory.addObserver(stage1); - } -} +// Wear all items in a uuid vector. +void wear_multiple(const uuid_vec_t& ids, bool replace); #endif diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 21766a731d..d222d94ec6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -357,7 +357,7 @@ static void ui_audio_callback(const LLUUID& uuid) bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) { - if(!match || !base) + if(!match || !base || base->getPlainText()) return false; LLUUID match_id = match->getID(); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 752a2e7504..1e59e5b805 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -550,9 +550,10 @@ namespace action_give_inventory } LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); - if (NULL == active_panel) + if (!active_panel) { - return; + active_panel = get_outfit_editor_inventory_panel(); + if (!active_panel) return; } const uuid_set_t inventory_selected_uuids = active_panel->getRootFolder()->getSelectionList(); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index c0fa910f86..7c33923f04 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -111,6 +111,12 @@ public: return pInstance; } + ~LLChatHistoryHeader() + { + // Detach the info button so that it doesn't get destroyed (EXT-8463). + hideInfoCtrl(); + } + BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return LLPanel::handleMouseUp(x,y,mask); @@ -382,8 +388,18 @@ protected: if (!sInfoCtrl) { + // *TODO: Delete the button at exit. sInfoCtrl = LLUICtrlFactory::createFromFile<LLUICtrl>("inspector_info_ctrl.xml", NULL, LLPanel::child_registry_t::instance()); - sInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, sInfoCtrl)); + if (sInfoCtrl) + { + sInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, sInfoCtrl)); + } + } + + if (!sInfoCtrl) + { + llassert(sInfoCtrl != NULL); + return; } LLTextBase* name = getChild<LLTextBase>("user_name"); diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 35a1ad747b..01932949e4 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -284,7 +284,8 @@ LLCOFWearables::LLCOFWearables() : LLPanel(), mAttachmentsTab(NULL), mBodyPartsTab(NULL), mLastSelectedTab(NULL), - mCOFVersion(-1) + mCOFVersion(-1), + mAccordionCtrl(NULL) { mClothingMenu = new CofClothingContextMenu(this); mAttachmentMenu = new CofAttachmentContextMenu(this); @@ -336,6 +337,8 @@ BOOL LLCOFWearables::postBuild() mTab2AssetType[mAttachmentsTab] = LLAssetType::AT_OBJECT; mTab2AssetType[mBodyPartsTab] = LLAssetType::AT_BODYPART; + mAccordionCtrl = getChild<LLAccordionCtrl>("cof_wearables_accordion"); + return LLPanel::postBuild(); } @@ -652,18 +655,35 @@ LLAssetType::EType LLCOFWearables::getExpandedAccordionAssetType() typedef std::map<std::string, LLAssetType::EType> type_map_t; static type_map_t type_map; - static LLAccordionCtrl* accordion_ctrl = getChild<LLAccordionCtrl>("cof_wearables_accordion"); - const LLAccordionCtrlTab* expanded_tab = accordion_ctrl->getExpandedTab(); - return get_if_there(mTab2AssetType, expanded_tab, LLAssetType::AT_NONE); + if (mAccordionCtrl != NULL) + { + const LLAccordionCtrlTab* expanded_tab = mAccordionCtrl->getExpandedTab(); + + return get_if_there(mTab2AssetType, expanded_tab, LLAssetType::AT_NONE); } + return LLAssetType::AT_NONE; +} + LLAssetType::EType LLCOFWearables::getSelectedAccordionAssetType() +{ + if (mAccordionCtrl != NULL) { - static LLAccordionCtrl* accordion_ctrl = getChild<LLAccordionCtrl>("cof_wearables_accordion"); - const LLAccordionCtrlTab* selected_tab = accordion_ctrl->getSelectedTab(); + const LLAccordionCtrlTab* selected_tab = mAccordionCtrl->getSelectedTab(); - return get_if_there(mTab2AssetType, selected_tab, LLAssetType::AT_NONE); + return get_if_there(mTab2AssetType, selected_tab, LLAssetType::AT_NONE); + } + + return LLAssetType::AT_NONE; +} + +void LLCOFWearables::expandDefaultAccordionTab() +{ + if (mAccordionCtrl != NULL) + { + mAccordionCtrl->expandDefaultTab(); + } } void LLCOFWearables::onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu) diff --git a/indra/newview/llcofwearables.h b/indra/newview/llcofwearables.h index d005b75eaa..cd7cc060e5 100644 --- a/indra/newview/llcofwearables.h +++ b/indra/newview/llcofwearables.h @@ -40,6 +40,7 @@ #include "llappearancemgr.h" #include "llinventorymodel.h" +class LLAccordionCtrl; class LLAccordionCtrlTab; class LLListContextMenu; class LLPanelClothingListItem; @@ -87,6 +88,7 @@ public: LLAssetType::EType getExpandedAccordionAssetType(); LLAssetType::EType getSelectedAccordionAssetType(); + void expandDefaultAccordionTab(); LLCOFCallbacks& getCOFCallbacks() { return mCOFCallbacks; } @@ -125,6 +127,8 @@ protected: LLListContextMenu* mAttachmentMenu; LLListContextMenu* mBodyPartMenu; + LLAccordionCtrl* mAccordionCtrl; + /* COF category version since last refresh */ S32 mCOFVersion; }; diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index c423473740..bb4e6c7a3e 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -167,6 +167,10 @@ void LLViewerDynamicTexture::postRender(BOOL success) { generateGLTexture() ; } + if(!mGLTexturep->getHasGLTexture()) + { + generateGLTexture() ; + } llcallstacks << "class type: " << (S32)getType() << llcallstacksendl ; success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 913bb676b0..f0ed659f5a 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2088,7 +2088,8 @@ void LLPanelLandOptions::refresh() LLStyle::Params style; style.image(LLUI::getUIImage(gFloaterView->getParentFloater(this)->getString("maturity_icon_moderate"))); LLCheckBoxWithTBAcess* fullaccess_mature_ctrl = (LLCheckBoxWithTBAcess*)mMatureCtrl; - fullaccess_mature_ctrl->getTextBox()->setText(std::string("icon"),style); + fullaccess_mature_ctrl->getTextBox()->setText(LLStringExplicit("")); + fullaccess_mature_ctrl->getTextBox()->appendImageSegment(style); fullaccess_mature_ctrl->getTextBox()->appendText(getString("mature_check_mature"), false); fullaccess_mature_ctrl->setToolTip(getString("mature_check_mature_tooltip")); fullaccess_mature_ctrl->reshape(fullaccess_mature_ctrl->getRect().getWidth(), fullaccess_mature_ctrl->getRect().getHeight(), FALSE); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 3944fa53c9..03e1bb9eee 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -263,6 +263,7 @@ public: BOOL needsAutoRename() { return mNeedsAutoRename; } void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; } + void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; } void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 996553ccf7..d464b67105 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -903,7 +903,15 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) if (member_id.notNull()) { - formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25 + if (online_status == "Online") + { + static std::string localized_online(LLTrans::getString("group_member_status_online")); + online_status = localized_online; + } + else + { + formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25 + } //llinfos << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << llendl; LLGroupMemberData* newdata = new LLGroupMemberData(member_id, diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp index ea57d36c06..b1f5b3be2f 100644 --- a/indra/newview/llinventorylistitem.cpp +++ b/indra/newview/llinventorylistitem.cpp @@ -96,9 +96,12 @@ void LLPanelInventoryListItemBase::draw() if (mSeparatorVisible && mSeparatorImage) { - // stretch along bottom of listitem, using image height + // place under bottom of listitem, using image height + // item_pad in list using the item should be >= image height + // to avoid cropping of top of the next item. LLRect separator_rect = getLocalRect(); - separator_rect.mTop = mSeparatorImage->getHeight(); + separator_rect.mTop = separator_rect.mBottom; + separator_rect.mBottom -= mSeparatorImage->getHeight(); mSeparatorImage->draw(separator_rect); } diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 06f490e8e3..ae8efc01a3 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -58,6 +58,7 @@ #endif #include "llsecapi.h" #include "llstartup.h" +#include "llmachineid.h" static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback"; static const char * const TOS_LISTENER_NAME = "lllogininstance_tos"; @@ -165,22 +166,24 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia // (re)initialize the request params with creds. LLSD request_params = user_credential->getLoginParams(); - char hashed_mac_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ - LLMD5 hashed_mac; - unsigned char MACAddress[MAC_ADDRESS_BYTES]; - if(LLUUID::getNodeID(MACAddress) == 0) { - llerrs << "Failed to get node id; cannot uniquely identify this machine." << llendl; + char hashed_unique_id_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ + LLMD5 hashed_unique_id; + unsigned char unique_id[MAC_ADDRESS_BYTES]; + if(LLUUID::getNodeID(unique_id) == 0) { + if(LLMachineID::getUniqueID(unique_id, sizeof(unique_id)) == 0) { + llerrs << "Failed to get an id; cannot uniquely identify this machine." << llendl; + } } - hashed_mac.update( MACAddress, MAC_ADDRESS_BYTES ); - hashed_mac.finalize(); - hashed_mac.hex_digest(hashed_mac_string); + hashed_unique_id.update(unique_id, MAC_ADDRESS_BYTES); + hashed_unique_id.finalize(); + hashed_unique_id.hex_digest(hashed_unique_id_string); request_params["start"] = construct_start_string(); request_params["skipoptional"] = mSkipOptionalUpdate; request_params["agree_to_tos"] = false; // Always false here. Set true in request_params["read_critical"] = false; // handleTOSResponse request_params["last_exec_event"] = mLastExecEvent; - request_params["mac"] = hashed_mac_string; + request_params["mac"] = hashed_unique_id_string; request_params["version"] = gCurrentVersion; // Includes channel name request_params["channel"] = gSavedSettings.getString("VersionChannelName"); request_params["id0"] = mSerialNumber; diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 6ae4a5e5e4..fc41137686 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -83,6 +83,16 @@ LLFloaterMove::LLFloaterMove(const LLSD& key) { } +LLFloaterMove::~LLFloaterMove() +{ + // Ensure LLPanelStandStopFlying panel is not among floater's children. See EXT-8458. + setVisible(FALSE); + + // Otherwise it can be destroyed and static pointer in LLPanelStandStopFlying::getInstance() will become invalid. + // Such situation was possible when LLFloaterReg returns "dead" instance of floater. + // Should not happen after LLFloater::destroy was modified to remove "dead" instances from LLFloaterReg. +} + // virtual BOOL LLFloaterMove::postBuild() { diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index d463861188..43b0342744 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -51,7 +51,7 @@ class LLFloaterMove private: LLFloaterMove(const LLSD& key); - ~LLFloaterMove() {} + ~LLFloaterMove(); public: /*virtual*/ BOOL postBuild(); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 63ffb80ff2..c3eee1d1ad 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -665,7 +665,18 @@ bool LLOutfitsList::isActionEnabled(const LLSD& userdata) } if (command_name == "wear") { - return !gAgentWearables.isCOFChangeInProgress(); + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } + + if (hasItemSelected()) + { + return canWearSelected(); + } + + // outfit selected + return LLAppearanceMgr::getCanAddToCOF(mSelectedOutfitUUID); } if (command_name == "take_off") { @@ -677,6 +688,7 @@ bool LLOutfitsList::isActionEnabled(const LLSD& userdata) if (command_name == "wear_add") { + // *TODO: do we ever get here? if (gAgentWearables.isCOFChangeInProgress()) { return false; @@ -984,6 +996,31 @@ bool LLOutfitsList::canTakeOffSelected() return false; } +bool LLOutfitsList::canWearSelected() +{ + uuid_vec_t selected_items; + getSelectedItemsUUIDs(selected_items); + + for (uuid_vec_t::const_iterator it = selected_items.begin(); it != selected_items.end(); ++it) + { + const LLUUID& id = *it; + + if (LLAppearanceMgr::isLinkInCOF(id)) + { + return false; + } + + // Check whether the item is worn. + if (!get_can_item_be_worn(id)) + { + return false; + } + } + + // All selected items can be worn. + return true; +} + void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) { LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index d7cf8a8c08..206854b232 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -183,6 +183,11 @@ private: */ bool canTakeOffSelected(); + /** + * Returns true if all selected items can be worn. + */ + bool canWearSelected(); + void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id); void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); void onCOFChanged(); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 094769b8f5..ac71069621 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -47,6 +47,7 @@ #include "llvoavatarself.h" #include "lltexteditor.h" #include "lltextbox.h" +#include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagentwearables.h" #include "llscrollingpanelparam.h" @@ -666,6 +667,35 @@ void LLPanelEditWearable::updateAvatarHeightLabel() mTxtAvatarHeight->appendText(this->mReplacementMetricUrl, false, param); } +void LLPanelEditWearable::onWearablePanelVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl) +{ + if (in_visible_chain.asBoolean() && accordion_ctrl != NULL) + { + accordion_ctrl->expandDefaultTab(); + } +} + +void LLPanelEditWearable::setWearablePanelVisibilityChangeCallback(LLPanel* bodypart_panel) +{ + if (bodypart_panel != NULL) + { + LLAccordionCtrl* accordion_ctrl = bodypart_panel->getChild<LLAccordionCtrl>("wearable_accordion"); + + if (accordion_ctrl != NULL) + { + bodypart_panel->setVisibleCallback( + boost::bind(&LLPanelEditWearable::onWearablePanelVisibilityChange, this, _2, accordion_ctrl)); + } + else + { + llwarns << "accordion_ctrl is NULL" << llendl; + } + } + else + { + llwarns << "bodypart_panel is NULL" << llendl; + } +} // virtual BOOL LLPanelEditWearable::postBuild() @@ -695,6 +725,14 @@ BOOL LLPanelEditWearable::postBuild() mPanelEyes = getChild<LLPanel>("edit_eyes_panel"); mPanelHair = getChild<LLPanel>("edit_hair_panel"); + // Setting the visibility callback is applied only to the bodyparts panel + // because currently they are the only ones whose 'wearable_accordion' has + // multiple accordion tabs (see EXT-8164 for details). + setWearablePanelVisibilityChangeCallback(mPanelShape); + setWearablePanelVisibilityChangeCallback(mPanelSkin); + setWearablePanelVisibilityChangeCallback(mPanelEyes); + setWearablePanelVisibilityChangeCallback(mPanelHair); + //clothes mPanelShirt = getChild<LLPanel>("edit_shirt_panel"); mPanelPants = getChild<LLPanel>("edit_pants_panel"); @@ -905,7 +943,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) { // Set the new version LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID()); - if( image->getID().isNull() ) + if( image->getID() == IMG_DEFAULT ) { image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); } diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 1c980c207e..03b2cb7932 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -39,6 +39,7 @@ #include "llvoavatardefines.h" #include "llwearabletype.h" +class LLAccordionCtrl; class LLCheckBoxCtrl; class LLWearable; class LLTextBox; @@ -115,6 +116,10 @@ private: // updates avatar height label void updateAvatarHeightLabel(); + void onWearablePanelVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl); + + void setWearablePanelVisibilityChangeCallback(LLPanel* bodypart_panel); + // the pointer to the wearable we're editing. NULL means we're not editing a wearable. LLWearable *mWearablePtr; LLViewerInventoryItem* mWearableItem; diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 2112c8c026..2fc74e138b 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -182,6 +182,11 @@ BOOL LLPanelGroup::postBuild() LLPanelGroupTab* panel_notices = findChild<LLPanelGroupTab>("group_notices_tab_panel"); LLPanelGroupTab* panel_land = findChild<LLPanelGroupTab>("group_land_tab_panel"); + if (LLAccordionCtrl* accordion_ctrl = getChild<LLAccordionCtrl>("groups_accordion")) + { + setVisibleCallback(boost::bind(&LLPanelGroup::onVisibilityChange, this, _2, accordion_ctrl)); + } + if(panel_general) mTabs.push_back(panel_general); if(panel_roles) mTabs.push_back(panel_roles); if(panel_notices) mTabs.push_back(panel_notices); @@ -305,6 +310,13 @@ void LLPanelGroup::onBtnCancel() onBackBtnClick(); } +void LLPanelGroup::onVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl) +{ + if (in_visible_chain.asBoolean() && accordion_ctrl != NULL) + { + accordion_ctrl->expandDefaultTab(); + } +} void LLPanelGroup::changed(LLGroupChange gc) { diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 13a03b0713..2b21e9895a 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -42,6 +42,7 @@ class LLOfferInfo; const S32 UPDATE_MEMBERS_PER_FRAME = 500; // Forward declares +class LLAccordionCtrl; class LLPanelGroupTab; class LLTabContainer; class LLAgent; @@ -102,6 +103,7 @@ protected: void onBackBtnClick(); void onBtnJoin(); void onBtnCancel(); + void onVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl); static void onBtnApply(void*); static void onBtnRefresh(void*); @@ -126,7 +128,6 @@ protected: LLButton* mButtonJoin; LLUICtrl* mJoinText; - }; class LLPanelGroupTab : public LLPanel diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index 65fe7165c2..b7d6b65ce5 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -1432,10 +1432,10 @@ void LLGroupMoneyPlanningTabEventHandler::processReply(LLMessageSystem* msg, // text.append(llformat( "%-24s %6d %6d \n", LLTrans::getString("GroupMoneyDebits").c_str(), total_debits, (S32)floor((F32)total_debits/(F32)non_exempt_members))); // text.append(llformat( "%-24s %6d %6d \n", LLTrans::getString("GroupMoneyTotal").c_str(), total_credits + total_debits, (S32)floor((F32)(total_credits + total_debits)/(F32)non_exempt_members))); - text.append( " Group\n"); - text.append(llformat( "%-24s %6d\n", "Credits", total_credits)); - text.append(llformat( "%-24s %6d\n", "Debits", total_debits)); - text.append(llformat( "%-24s %6d\n", "Total", total_credits + total_debits)); + text.append(llformat( "%s\n", LLTrans::getString("GroupColumn").c_str())); + text.append(llformat( "%-24s %6d\n", LLTrans::getString("GroupMoneyCredits").c_str(), total_credits)); + text.append(llformat( "%-24s %6d\n", LLTrans::getString("GroupMoneyDebits").c_str(), total_debits)); + text.append(llformat( "%-24s %6d\n", LLTrans::getString("GroupMoneyTotal").c_str(), total_credits + total_debits)); if ( mImplementationp->mTextEditorp ) { diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 26e8a932aa..445cfe64f7 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1593,6 +1593,7 @@ void LLPanelGroupMembersSubTab::updateMembers() LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); + LLUIString donated = getString("donation_area"); S32 i = 0; for( ; mMemberProgress != end && i<UPDATE_MEMBERS_PER_FRAME; @@ -1614,9 +1615,7 @@ void LLPanelGroupMembersSubTab::updateMembers() if (add_member) { - // Build the donated tier string. - std::ostringstream donated; - donated << mMemberProgress->second->getContribution() << " sq. m."; + donated.setArg("[AREA]", llformat("%d", mMemberProgress->second->getContribution())); LLSD row; row["id"] = (*mMemberProgress).first; @@ -1625,7 +1624,7 @@ void LLPanelGroupMembersSubTab::updateMembers() // value is filled in by name list control row["columns"][1]["column"] = "donated"; - row["columns"][1]["value"] = donated.str(); + row["columns"][1]["value"] = donated.getString(); row["columns"][2]["column"] = "online"; row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus(); diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 6ab7fd6a2b..6c6f830000 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -421,6 +421,8 @@ LLPanelOutfitEdit::~LLPanelOutfitEdit() delete mCOFDragAndDropObserver; + delete mWearableListViewItemsComparator; + while (!mListViewItemTypes.empty()) { delete mListViewItemTypes.back(); mListViewItemTypes.pop_back(); @@ -526,12 +528,25 @@ BOOL LLPanelOutfitEdit::postBuild() childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); + /* + * By default AT_CLOTHING are sorted by (in in MY OUTFITS): + * - by type (types order determined in LLWearableType::EType) + * - each LLWearableType::EType by outer layer on top + * + * In Add More panel AT_CLOTHING should be sorted in a such way: + * - by type (types order determined in LLWearableType::EType) + * - each LLWearableType::EType by name (EXT-8205) + */ + mWearableListViewItemsComparator = new LLWearableItemTypeNameComparator(); + mWearableListViewItemsComparator->setOrder(LLAssetType::AT_CLOTHING, LLWearableItemTypeNameComparator::ORDER_RANK_1, false, true); + mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel"); mWearableItemsList = getChild<LLWearableItemsList>("list_view"); mWearableItemsList->setCommitOnSelectionChange(true); mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this)); mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this)); - mWearableItemsList->setSortOrder((LLWearableItemsList::ESortOrder)gSavedSettings.getU32("AddWearableSortOrder")); + mWearableItemsList->setComparator(mWearableListViewItemsComparator); + mWearableItemsList->setSortOrder((LLWearableItemsList::ESortOrder)gSavedSettings.getU32("AddWearableSortOrder")); mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this)); return TRUE; @@ -901,7 +916,9 @@ void LLPanelOutfitEdit::updatePlusButton() } // If any of the selected items are not wearable (due to already being worn OR being of the wrong type), disable the add button. - uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(& get_can_item_be_worn, _1)); + uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(& get_can_item_be_worn, _1) + // since item can be not worn but in wearing process at that time - we need to check is link to item presents in COF + || boost::bind(&LLAppearanceMgr::isLinkInCOF, _1)); bool can_add = ( unwearable_item == selected_items.end() ); mPlusBtn->setEnabled(can_add); @@ -1149,16 +1166,18 @@ bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch return false; } -void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button) +void LLPanelOutfitEdit::resetAccordionState() { - LLMenuGL* menu = NULL; + if (mCOFWearables != NULL) if (mAddWearablesPanel->getVisible()) { - if (!mAddWearablesGearMenu) - { - mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel); - } + mCOFWearables->expandDefaultAccordionTab(); + } + else + { + llwarns << "mCOFWearables is NULL" << llendl; + } menu = mAddWearablesGearMenu; } diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 93215c5920..fa3c48c3e7 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -64,6 +64,7 @@ class LLMenuGL; class LLFindNonLinksByMask; class LLFindWearablesOfType; class LLSaveOutfitComboBtn; +class LLWearableItemTypeNameComparator; class LLPanelOutfitEdit : public LLPanel { @@ -188,6 +189,8 @@ public: */ bool switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel); + void resetAccordionState(); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, @@ -228,6 +231,7 @@ private: LLFilteredWearableListManager* mWearableListManager; LLWearableItemsList* mWearableItemsList; LLPanel* mWearablesListViewPanel; + LLWearableItemTypeNameComparator* mWearableListViewItemsComparator; LLCOFDragAndDropObserver* mCOFDragAndDropObserver; diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index ca5679d5b0..16ef7998b3 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -337,7 +337,7 @@ bool LLPanelOutfitsInventory::isCOFPanelActive() const void LLPanelOutfitsInventory::setWearablesLoading(bool val) { - mListCommands->childSetEnabled("wear_btn", !val); + updateVerbs(); } void LLPanelOutfitsInventory::onWearablesLoaded() diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 8c1f5d0915..99e48cca6d 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -60,7 +60,8 @@ LLPanelPlaceInfo::LLPanelPlaceInfo() mScrollingPanelWidth(0), mInfoType(UNKNOWN), mScrollingPanel(NULL), - mScrollContainer(NULL) + mScrollContainer(NULL), + mDescEditor(NULL) {} //virtual @@ -248,6 +249,16 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) // virtual void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) { + + // This if was added to force collapsing description textbox on Windows at the beginning of reshape + // (the only case when reshape is skipped here is when it's caused by this textbox, so called_from_parent is FALSE) + // This way it is consistent with Linux where topLost collapses textbox at the beginning of reshape. + // On windows it collapsed only after reshape which caused EXT-8342. + if(called_from_parent) + { + if(mDescEditor) mDescEditor->onTopLost(); + } + LLPanel::reshape(width, height, called_from_parent); if (!mScrollContainer || !mScrollingPanel) diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 1f979b0ef1..08835dc2b8 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -79,7 +79,8 @@ LLPanelPlaceProfile::LLPanelPlaceProfile() : LLPanelPlaceInfo(), mForSalePanel(NULL), mYouAreHerePanel(NULL), - mSelectedParcelID(-1) + mSelectedParcelID(-1), + mAccordionCtrl(NULL) {} // virtual @@ -139,6 +140,7 @@ BOOL LLPanelPlaceProfile::postBuild() mSubdivideText = getChild<LLTextEditor>("subdivide"); mResaleText = getChild<LLTextEditor>("resale"); mSaleToText = getChild<LLTextBox>("sale_to"); + mAccordionCtrl = getChild<LLAccordionCtrl>("advanced_info_accordion"); icon_pg = getString("icon_PG"); icon_m = getString("icon_M"); @@ -278,6 +280,11 @@ void LLPanelPlaceProfile::handleVisibilityChange(BOOL new_visibility) parcel_mgr->deselectUnused(); } } + + if (mAccordionCtrl != NULL) + { + mAccordionCtrl->expandDefaultTab(); + } } void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h index e77b441567..49c13ff5e3 100644 --- a/indra/newview/llpanelplaceprofile.h +++ b/indra/newview/llpanelplaceprofile.h @@ -35,6 +35,7 @@ #include "llpanelplaceinfo.h" +class LLAccordionCtrl; class LLIconCtrl; class LLTextEditor; @@ -118,6 +119,7 @@ private: LLTextEditor* mSubdivideText; LLTextEditor* mResaleText; LLTextBox* mSaleToText; + LLAccordionCtrl* mAccordionCtrl; }; #endif // LL_LLPANELPLACEPROFILE_H diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 7a7ffb9983..98cd0b88eb 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -190,13 +190,16 @@ void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility) { if (new_visibility.asBoolean()) { - if ((mOutfitEdit && mOutfitEdit->getVisible()) || (mEditWearable && mEditWearable->getVisible())) + bool is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible(); + bool is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible(); + + if (is_outfit_edit_visible || is_wearable_edit_visible) { if (!gAgentCamera.cameraCustomizeAvatar() && gSavedSettings.getBOOL("AppearanceCameraMovement")) { gAgentCamera.changeCameraToCustomizeAvatar(); } - if (mEditWearable && mEditWearable->getVisible()) + if (is_wearable_edit_visible) { LLWearable *wearable_ptr = mEditWearable->getWearable(); if (gAgentWearables.getWearableIndex(wearable_ptr) == LLAgentWearables::MAX_CLOTHING_PER_TYPE) @@ -205,6 +208,11 @@ void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility) showOutfitEditPanel(); } } + + if (is_outfit_edit_visible) + { + mOutfitEdit->resetAccordionState(); + } } } else @@ -283,6 +291,15 @@ void LLSidepanelAppearance::showOutfitsInventoryPanel() void LLSidepanelAppearance::showOutfitEditPanel() { + // Accordion's state must be reset in all cases except the one when user + // is returning back to the mOutfitEdit panel from the mEditWearable panel. + // The simplest way to control this is to check the visibility state of the mEditWearable + // BEFORE it is changed by the call to the toggleWearableEditPanel(FALSE, NULL, TRUE). + if (mEditWearable != NULL && !mEditWearable->getVisible() && mOutfitEdit != NULL) + { + mOutfitEdit->resetAccordionState(); + } + togglMyOutfitsPanel(FALSE); toggleWearableEditPanel(FALSE, NULL, TRUE); // don't switch out of edit appearance mode toggleOutfitEditPanel(TRUE); diff --git a/indra/newview/lltexlayerparams.cpp b/indra/newview/lltexlayerparams.cpp index f2d1b5d032..dc97c4b673 100644 --- a/indra/newview/lltexlayerparams.cpp +++ b/indra/newview/lltexlayerparams.cpp @@ -180,7 +180,7 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) if ((mAvatar->getSex() & getSex()) && (mAvatar->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { - if (gAgentCamera.cameraCustomizeAvatar()) + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) { upload_bake = FALSE; } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 0b02861b75..c0518b705b 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -175,6 +175,8 @@ protected: BOOL mNoCopyTextureSelected; F32 mContextConeOpacity; LLSaveFolderState mSavedFolderState; + + BOOL mSelectedItemPinned; }; LLFloaterTexturePicker::LLFloaterTexturePicker( @@ -197,7 +199,8 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mFilterEdit(NULL), mImmediateFilterPermMask(immediate_filter_perm_mask), mNonImmediateFilterPermMask(non_immediate_filter_perm_mask), - mContextConeOpacity(0.f) + mContextConeOpacity(0.f), + mSelectedItemPinned( FALSE ) { mCanApplyImmediately = can_apply_immediately; LLUICtrlFactory::getInstance()->buildFloater(this,"floater_texture_ctrl.xml",NULL); @@ -597,6 +600,31 @@ void LLFloaterTexturePicker::draw() mTentativeLabel->setVisible( TRUE ); drawChild(mTentativeLabel); } + + if (mSelectedItemPinned) return; + + LLFolderView* folder_view = mInventoryPanel->getRootFolder(); + if (!folder_view) return; + + LLInventoryFilter* filter = folder_view->getFilter(); + if (!filter) return; + + bool is_filter_active = folder_view->getCompletedFilterGeneration() < filter->getCurrentGeneration() && + filter->isNotDefault(); + + // After inventory panel filter is applied we have to update + // constraint rect for the selected item because of folder view + // AutoSelectOverride set to TRUE. We force PinningSelectedItem + // flag to FALSE state and setting filter "dirty" to update + // scroll container to show selected item (see LLFolderView::doIdle()). + if (!is_filter_active && !mSelectedItemPinned) + { + folder_view->setPinningSelectedItem(mSelectedItemPinned); + folder_view->dirtyFilter(); + folder_view->arrangeFromRoot(); + + mSelectedItemPinned = TRUE; + } } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index ceed90e210..dddfed097d 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -290,8 +290,8 @@ class HTTPGetResponder : public LLCurl::Responder { LOG_CLASS(HTTPGetResponder); public: - HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset) - : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset) + HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir) + : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir) { } ~HTTPGetResponder() @@ -344,6 +344,11 @@ public: llwarns << "Worker not found: " << mID << llendl; } } + + virtual bool followRedir() + { + return mFollowRedir; + } private: LLTextureFetch* mFetcher; @@ -351,6 +356,7 @@ private: U64 mStartTime; S32 mRequestedSize; U32 mOffset; + bool mFollowRedir; }; ////////////////////////////////////////////////////////////////////////////// @@ -897,7 +903,7 @@ bool LLTextureFetchWorker::doWork(S32 param) std::vector<std::string> headers; headers.push_back("Accept: image/x-j2c"); res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize, - new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset)); + new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true)); } if (!res) { @@ -945,17 +951,6 @@ bool LLTextureFetchWorker::doWork(S32 param) max_attempts = mHTTPFailCount+1; // Keep retrying LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; } - else if(mGetStatus >= HTTP_MULTIPLE_CHOICES && mGetStatus < HTTP_BAD_REQUEST) //http re-direct - { - ++mHTTPFailCount; - max_attempts = 5 ; //try at most 5 times to avoid infinite redirection loop. - - llwarns << "HTTP GET failed because of redirection: " << mUrl - << " Status: " << mGetStatus << " Reason: '" << mGetReason << llendl ; - - //assign to the new url - mUrl = mGetReason ; - } else { const S32 HTTP_MAX_RETRY_COUNT = 3; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 2d57c16889..9926c8d15f 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -96,6 +96,7 @@ public: mInventoryItemsDict["New Gesture"] = LLTrans::getString("New Gesture"); mInventoryItemsDict["New Script"] = LLTrans::getString("New Script"); mInventoryItemsDict["New Folder"] = LLTrans::getString("New Folder"); + mInventoryItemsDict["New Note"] = LLTrans::getString("New Note"); mInventoryItemsDict["Contents"] = LLTrans::getString("Contents"); mInventoryItemsDict["Gesture"] = LLTrans::getString("Gesture"); @@ -935,7 +936,7 @@ void ModifiedCOFCallback::fire(const LLUUID& inv_item) gAgentWearables.editWearableIfRequested(inv_item); // TODO: camera mode may not be changed if a debug setting is tweaked - if( gAgentCamera.cameraCustomizeAvatar() ) + if(gAgentCamera.cameraCustomizeAvatar()) { // If we're in appearance editing mode, the current tab may need to be refreshed LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLSideTray::getInstance()->getPanel("sidepanel_appearance")); @@ -1172,6 +1173,14 @@ void move_inventory_item( void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecard_inv_id, const LLInventoryItem *src, U32 callback_id) { + if (NULL == src) + { + LL_WARNS("copy_inventory_from_notecard") << "Null pointer to item was passed for object_id " + << object_id << " and notecard_inv_id " + << notecard_inv_id << LL_ENDL; + return; + } + LLViewerRegion* viewer_region = NULL; LLViewerObject* vo = NULL; if (object_id.notNull() && (vo = gObjectList.findObject(object_id)) != NULL) @@ -1194,6 +1203,16 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar return; } + // check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459. + std::string url = viewer_region->getCapability("CopyInventoryFromNotecard"); + if (url.empty()) + { + LL_WARNS("copy_inventory_from_notecard") << "There is no 'CopyInventoryFromNotecard' capability" + << " for region: " << viewer_region->getName() + << LL_ENDL; + return; + } + LLSD request, body; body["notecard-id"] = notecard_inv_id; body["object-id"] = object_id; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index b3fc0df1bf..090b7bba90 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -108,9 +108,12 @@ #include "llappearancemgr.h" #include "lltrans.h" #include "lleconomy.h" +#include "boost/unordered_map.hpp" using namespace LLVOAvatarDefines; +static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels; + BOOL enable_land_build(void*); BOOL enable_object_build(void*); @@ -2403,31 +2406,53 @@ void handle_object_touch() msg->sendMessage(object->getRegion()->getHost()); } -// One object must have touch sensor -class LLObjectEnableTouch : public view_listener_t +static void init_default_item_label(const std::string& item_name) { - bool handleEvent(const LLSD& userdata) + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it == sDefaultItemLabels.end()) { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - bool new_value = obj && obj->flagHandleTouch(); - - // Update label based on the node touch name if available. - std::string touch_text; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - touch_text = node->mTouchName; - } - else + LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString(); + if (!default_label.empty()) { - touch_text = userdata.asString(); + sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); } - gMenuHolder->childSetText("Object Touch", touch_text); - gMenuHolder->childSetText("Attachment Object Touch", touch_text); + } +} - return new_value; +static LLStringExplicit get_default_item_label(const std::string& item_name) +{ + LLStringExplicit res(""); + boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); + if (it != sDefaultItemLabels.end()) + { + res = it->second; + } + + return res; +} + + +bool enable_object_touch(LLUICtrl* ctrl) +{ + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + + bool new_value = obj && obj->flagHandleTouch(); + + std::string item_name = ctrl->getName(); + init_default_item_label(item_name); + + // Update label based on the node touch name if available. + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid && !node->mTouchName.empty()) + { + gMenuHolder->childSetText(item_name, node->mTouchName); + } + else + { + gMenuHolder->childSetText(item_name, get_default_item_label(item_name)); } + + return new_value; }; //void label_touch(std::string& label, void*) @@ -5519,27 +5544,27 @@ bool enable_object_stand_up() return sitting_on_selection(); } -bool enable_object_sit() +bool enable_object_sit(LLUICtrl* ctrl) { // 'Object Sit' menu item is enabled when agent is not sitting on selection bool sitting_on_sel = sitting_on_selection(); if (!sitting_on_sel) { - LLMenuItemGL* sit_menu_item = gMenuHolder->getChild<LLMenuItemGL>("Object Sit"); - // Init default 'Object Sit' menu item label - static const LLStringExplicit sit_text(sit_menu_item->getLabel()); + std::string item_name = ctrl->getName(); + + // init default labels + init_default_item_label(item_name); + // Update label - std::string label; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if (node && node->mValid && !node->mSitName.empty()) { - label.assign(node->mSitName); + gMenuHolder->childSetText(item_name, node->mSitName); } else { - label = sit_text; + gMenuHolder->childSetText(item_name, get_default_item_label(item_name)); } - sit_menu_item->setLabel(label); } return !sitting_on_sel && is_object_sittable(); } @@ -8087,7 +8112,6 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); commit.add("Object.Touch", boost::bind(&handle_object_touch)); commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - enable.add("Object.EnableGearSit", boost::bind(&is_object_sittable)); commit.add("Object.Delete", boost::bind(&handle_object_delete)); view_listener_t::addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar"); view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); @@ -8103,12 +8127,12 @@ void initialize_menus() commit.add("Object.Open", boost::bind(&handle_object_open)); commit.add("Object.Take", boost::bind(&handle_take)); enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); - view_listener_t::addMenu(new LLObjectEnableTouch(), "Object.EnableTouch"); + enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid)); enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); - enable.add("Object.EnableSit", boost::bind(&enable_object_sit)); + enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 2b6eadcc04..401433e6e1 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1138,10 +1138,26 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam } else if(from_name.empty()) { + std::string folder_name; + if (parent_folder) + { + // Localize folder name. + // *TODO: share this code? + folder_name = parent_folder->getName(); + if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) + { + LLTrans::findString(folder_name, "InvFolder " + folder_name); + } + } + else + { + folder_name = LLTrans::getString("Unknown"); + } + // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. LLSD args; args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown"); + args["FOLDER_NAME"] = folder_name; LLNotificationsUtil::add("LandmarkCreated", args); } } diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 59efae4cb2..8bd43bb30c 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -90,7 +90,7 @@ public: } static void processForeignLandmark(LLLandmark* landmark, const LLUUID& object_id, const LLUUID& notecard_inventory_id, - LLInventoryItem* item) + LLPointer<LLInventoryItem> item_ptr) { LLVector3d global_pos; landmark->getGlobalPos(global_pos); @@ -103,8 +103,16 @@ public: } else { - LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied(); - copy_inventory_from_notecard(object_id, notecard_inventory_id, item, gInventoryCallbacks.registerCB(cb)); + if (item_ptr.isNull()) + { + // check to prevent a crash. See EXT-8459. + llwarns << "Passed handle contains a dead inventory item. Most likely notecard has been closed and embedded item was destroyed." << llendl; + } + else + { + LLPointer<LLEmbeddedLandmarkCopied> cb = new LLEmbeddedLandmarkCopied(); + copy_inventory_from_notecard(object_id, notecard_inventory_id, item_ptr.get(), gInventoryCallbacks.registerCB(cb)); + } } } }; @@ -300,14 +308,14 @@ public: void markSaved(); - static LLInventoryItem* getEmbeddedItem(llwchar ext_char); // returns item from static list + static LLPointer<LLInventoryItem> getEmbeddedItemPtr(llwchar ext_char); // returns pointer to item from static list static BOOL getEmbeddedItemSaved(llwchar ext_char); // returns whether item from static list is saved private: struct embedded_info_t { - LLPointer<LLInventoryItem> mItem; + LLPointer<LLInventoryItem> mItemPtr; BOOL mSaved; }; typedef std::map<llwchar, embedded_info_t > item_map_t; @@ -378,7 +386,7 @@ BOOL LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_ch ++wc_emb; } - sEntries[wc_emb].mItem = item; + sEntries[wc_emb].mItemPtr = item; sEntries[wc_emb].mSaved = is_new ? FALSE : TRUE; *ext_char = wc_emb; mEmbeddedUsedChars.insert(wc_emb); @@ -400,14 +408,14 @@ BOOL LLEmbeddedItems::removeEmbeddedItem( llwchar ext_char ) } // static -LLInventoryItem* LLEmbeddedItems::getEmbeddedItem(llwchar ext_char) +LLPointer<LLInventoryItem> LLEmbeddedItems::getEmbeddedItemPtr(llwchar ext_char) { if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR ) { item_map_t::iterator iter = sEntries.find(ext_char); if (iter != sEntries.end()) { - return iter->second.mItem; + return iter->second.mItemPtr; } } return NULL; @@ -505,7 +513,7 @@ BOOL LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char) LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const { - LLInventoryItem* item = getEmbeddedItem(ext_char); + LLInventoryItem* item = getEmbeddedItemPtr(ext_char); if (item) { const char* img_name = ""; @@ -567,7 +575,7 @@ void LLEmbeddedItems::getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter) { llwchar wc = *iter; - LLPointer<LLInventoryItem> item = getEmbeddedItem(wc); + LLPointer<LLInventoryItem> item = getEmbeddedItemPtr(wc); if (item) { items.push_back(item); @@ -698,7 +706,7 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { wc = getWText()[mCursorPos]; } - LLInventoryItem* item_at_pos = LLEmbeddedItems::getEmbeddedItem(wc); + LLPointer<LLInventoryItem> item_at_pos = LLEmbeddedItems::getEmbeddedItemPtr(wc); if (item_at_pos) { mDragItem = item_at_pos; @@ -1019,7 +1027,7 @@ llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char) { return ext_char; // already exists in my list } - LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(ext_char); + LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItemPtr(ext_char); if (item) { // Add item to my list and return new llwchar associated with it @@ -1053,7 +1061,7 @@ void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end) && embedded_char <= LAST_EMBEDDED_CHAR && mEmbeddedItemList->hasEmbeddedItem(embedded_char) ) { - LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItem(embedded_char); + LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItemPtr(embedded_char); LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char); insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this)); } @@ -1065,7 +1073,7 @@ BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos) if( pos < getLength()) { llwchar wc = getWText()[pos]; - LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem( wc ); + LLPointer<LLInventoryItem> item = LLEmbeddedItems::getEmbeddedItemPtr( wc ); if( item ) { BOOL saved = LLEmbeddedItems::getEmbeddedItemSaved( wc ); @@ -1083,7 +1091,7 @@ BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos) } -BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, llwchar wc) +BOOL LLViewerTextEditor::openEmbeddedItem(LLPointer<LLInventoryItem> item, llwchar wc) { switch( item->getType() ) @@ -1151,17 +1159,17 @@ void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item, llwchar wc ) } -void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item, llwchar wc ) +void LLViewerTextEditor::openEmbeddedLandmark( LLPointer<LLInventoryItem> item_ptr, llwchar wc ) { - if (!item) + if (item_ptr.isNull()) return; - LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID(), - boost::bind(&LLEmbeddedLandmarkCopied::processForeignLandmark, _1, mObjectID, mNotecardInventoryID, item)); + LLLandmark* landmark = gLandmarkList.getAsset(item_ptr->getAssetUUID(), + boost::bind(&LLEmbeddedLandmarkCopied::processForeignLandmark, _1, mObjectID, mNotecardInventoryID, item_ptr)); if (landmark) { LLEmbeddedLandmarkCopied::processForeignLandmark(landmark, mObjectID, - mNotecardInventoryID, item); + mNotecardInventoryID, item_ptr); } } @@ -1220,7 +1228,7 @@ bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD& { LLUUID item_id = notification["payload"]["item_id"].asUUID(); llwchar wc = llwchar(notification["payload"]["item_wc"].asInteger()); - LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItem(wc); + LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItemPtr(wc); if (itemp) copyInventory(itemp); } diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index ba0c40cb2e..74b6d70640 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -104,13 +104,16 @@ private: virtual llwchar pasteEmbeddedItem(llwchar ext_char); BOOL openEmbeddedItemAtPos( S32 pos ); - BOOL openEmbeddedItem(LLInventoryItem* item, llwchar wc); + BOOL openEmbeddedItem(LLPointer<LLInventoryItem> item, llwchar wc); S32 insertEmbeddedItem(S32 pos, LLInventoryItem* item); + // *NOTE: most of openEmbeddedXXX methods except openEmbeddedLandmark take pointer to LLInventoryItem. + // Be sure they don't bind it to callback function to avoid situation when it gets invalid when + // callback is trigged after text editor is closed. See EXT-8459. void openEmbeddedTexture( LLInventoryItem* item, llwchar wc ); void openEmbeddedSound( LLInventoryItem* item, llwchar wc ); - void openEmbeddedLandmark( LLInventoryItem* item, llwchar wc ); + void openEmbeddedLandmark( LLPointer<LLInventoryItem> item_ptr, llwchar wc ); void openEmbeddedNotecard( LLInventoryItem* item, llwchar wc); void openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc); void showCopyToInvDialog( LLInventoryItem* item, llwchar wc ); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2f63e7ef01..00873a797c 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4390,7 +4390,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) gResizeScreenTexture = TRUE; - if (gAgentCamera.cameraCustomizeAvatar()) + if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) { LLVisualParamHint::requestHintUpdates(); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9353c6daef..68085b1baf 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4095,9 +4095,13 @@ void LLVOAvatar::updateTextures() } else { - render_avatar = isVisible() && !mCulled; + if(!isVisible()) + { + return ;//do not update for invisible avatar. + } + + render_avatar = !mCulled; //visible and not culled. } - checkTextureLoading() ; std::vector<BOOL> layer_baked; // GL NOT ACTIVE HERE - *TODO @@ -4138,7 +4142,7 @@ void LLVOAvatar::updateTextures() } } } - if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar) + if (isIndexBakedTexture((ETextureIndex) texture_index)) { const S32 boost_level = getAvatarBakedBoostLevel(); imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); @@ -4172,10 +4176,11 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture return; } - +const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. +const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames void LLVOAvatar::checkTextureLoading() { - static const F32 MAX_INVISIBLE_WAITING_TIME = 30.f ; //seconds + static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds BOOL pause = !isVisible() ; if(!pause) @@ -4195,9 +4200,9 @@ void LLVOAvatar::checkTextureLoading() if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME) { - return ; + return ; //have not been invisible for enough time. } - + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); iter != mCallbackTextureList.end(); ++iter) { @@ -4207,17 +4212,22 @@ void LLVOAvatar::checkTextureLoading() if(pause)//pause texture fetching. { tex->pauseLoadedCallbacks(&mCallbackTextureList) ; + + //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames. + tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL); + tex->resetMaxVirtualSizeResetCounter() ; } else//unpause { - static const F32 START_AREA = 100.f ; - - tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; - tex->addTextureStats(START_AREA); //jump start the fetching again + tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; } } } + if(!pause) + { + updateTextures() ; //refresh texture stats. + } mLoadedCallbacksPaused = pause ; return ; } @@ -4226,12 +4236,14 @@ const F32 SELF_ADDITIONAL_PRI = 0.75f ; const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { - //if this function is not called for the last 512 frames, the texture pipeline will stop fetching this texture. - static const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 512 ; //frames - + //Note: + //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //the texture pipeline will stop fetching this texture. + imagep->resetTextureStats(); imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures. imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->resetMaxVirtualSizeResetCounter() ; mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); mMinPixelArea = llmin(pixel_area, mMinPixelArea); @@ -6051,7 +6063,7 @@ void LLVOAvatar::updateMeshTextures() } } - const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures + const BOOL self_customizing = isSelf() && !gAgentAvatarp->isUsingBakedTextures(); // During face edit mode, we don't use baked textures const BOOL other_culled = !isSelf() && mCulled; LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; BOOL paused = FALSE; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 83ca299da1..4163810d6c 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -1049,6 +1049,7 @@ protected: // Shared with LLVOAvatarSelf *******************************************************************************/ }; // LLVOAvatar -extern const F32 SELF_ADDITIONAL_PRI; +extern const F32 SELF_ADDITIONAL_PRI; +extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; #endif // LL_VO_AVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 8961d2c285..3a283e7aa6 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1148,11 +1148,11 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr discard_level < local_tex_obj->getDiscard()) { local_tex_obj->setDiscard(discard_level); - if (!gAgentCamera.cameraCustomizeAvatar()) + if (isUsingBakedTextures()) { requestLayerSetUpdate(index); } - else if (gAgentCamera.cameraCustomizeAvatar()) + else { LLVisualParamHint::requestHintUpdates(); } @@ -1622,13 +1622,16 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te if (tex_discard >= 0 && tex_discard <= desired_discard) { local_tex_obj->setDiscard(tex_discard); - if (isSelf() && !gAgentCamera.cameraCustomizeAvatar()) - { - requestLayerSetUpdate(type); - } - else if (isSelf() && gAgentCamera.cameraCustomizeAvatar()) + if (isSelf()) { - LLVisualParamHint::requestHintUpdates(); + if (gAgentAvatarp->isUsingBakedTextures()) + { + requestLayerSetUpdate(type); + } + else + { + LLVisualParamHint::requestHintUpdates(); + } } } else @@ -2032,7 +2035,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe imagep->setBoostLevel(getAvatarBoostLevel()); imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(16); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); imagep->addTextureStats( desired_pixels / texel_area_ratio ); imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; imagep->forceUpdateBindStats() ; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index dfa7ca7136..c5042ca016 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -698,7 +698,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake } } - if( gAgentCamera.cameraCustomizeAvatar() ) + if(gAgentCamera.cameraCustomizeAvatar()) { LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit")); } diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index b614860b74..d9b2dfbec0 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -465,6 +465,29 @@ std::string LLPanelDummyClothingListItem::wearableTypeToString(LLWearableType::E ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +LLWearableItemTypeNameComparator::LLWearableTypeOrder::LLWearableTypeOrder(LLWearableItemTypeNameComparator::ETypeListOrder order_priority, bool sort_asset_by_name, bool sort_wearable_by_name): + mOrderPriority(order_priority), + mSortAssetTypeByName(sort_asset_by_name), + mSortWearableTypeByName(sort_wearable_by_name) +{ +} + +LLWearableItemTypeNameComparator::LLWearableItemTypeNameComparator() +{ + // By default the sort order conforms the order by spec of MY OUTFITS items list: + // 1. CLOTHING - sorted by name + // 2. OBJECT - sorted by type + // 3. BODYPART - sorted by name + mWearableOrder[LLAssetType::AT_CLOTHING] = LLWearableTypeOrder(ORDER_RANK_1, false, false); + mWearableOrder[LLAssetType::AT_OBJECT] = LLWearableTypeOrder(ORDER_RANK_2, true, true); + mWearableOrder[LLAssetType::AT_BODYPART] = LLWearableTypeOrder(ORDER_RANK_3, false, true); +} + +void LLWearableItemTypeNameComparator::setOrder(LLAssetType::EType items_of_type, LLWearableItemTypeNameComparator::ETypeListOrder order_priority, bool sort_asset_items_by_name, bool sort_wearable_items_by_name) +{ + mWearableOrder[items_of_type] = LLWearableTypeOrder(order_priority, sort_asset_items_by_name, sort_wearable_items_by_name); +} + /*virtual*/ bool LLWearableItemNameComparator::doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const { @@ -493,7 +516,7 @@ bool LLWearableItemTypeNameComparator::doCompare(const LLPanelInventoryListItemB return item_type_order1 < item_type_order2; } - if (item_type_order1 & TLO_SORTABLE_BY_NAME) + if (sortAssetTypeByName(item_type1)) { // If both items are of the same asset type except AT_CLOTHING and AT_BODYPART // we can compare them by name. @@ -505,50 +528,62 @@ bool LLWearableItemTypeNameComparator::doCompare(const LLPanelInventoryListItemB if (item_wearable_type1 != item_wearable_type2) { - // If items are of different clothing types they are compared - // by clothing types order determined in LLWearableType::EType. + // If items are of different LLWearableType::EType types they are compared + // by LLWearableType::EType. types order determined in LLWearableType::EType. return item_wearable_type1 < item_wearable_type2; } else { // If both items are of the same clothing type they are compared - // by description and place in reverse order i.e. outer layer item - // on top. + // by description and place in reverse order (i.e. outer layer item + // on top) OR by name + if(sortWearableTypeByName(item_type1)) + { + return LLWearableItemNameComparator::doCompare(wearable_item1, wearable_item2); + } return wearable_item1->getDescription() > wearable_item2->getDescription(); } } -// static -LLWearableItemTypeNameComparator::ETypeListOrder LLWearableItemTypeNameComparator::getTypeListOrder(LLAssetType::EType item_type) +LLWearableItemTypeNameComparator::ETypeListOrder LLWearableItemTypeNameComparator::getTypeListOrder(LLAssetType::EType item_type) const { - switch (item_type) + wearable_type_order_map_t::const_iterator const_it = mWearableOrder.find(item_type); + + if(const_it == mWearableOrder.end()) { - case LLAssetType::AT_OBJECT: - return TLO_ATTACHMENT; + llwarns<<"Absent information about order rang of items of "<<LLAssetType::getDesc(item_type)<<" type"<<llendl; + return ORDER_RANK_UNKNOWN; + } - case LLAssetType::AT_CLOTHING: - return TLO_CLOTHING; + return const_it->second.mOrderPriority; +} - case LLAssetType::AT_BODYPART: - return TLO_BODYPART; +bool LLWearableItemTypeNameComparator::sortAssetTypeByName(LLAssetType::EType item_type) const +{ + wearable_type_order_map_t::const_iterator const_it = mWearableOrder.find(item_type); - default: - return TLO_UNKNOWN; + if(const_it == mWearableOrder.end()) + { + llwarns<<"Absent information about sorting items of "<<LLAssetType::getDesc(item_type)<<" type"<<llendl; + return true; } + + return const_it->second.mSortAssetTypeByName; } -/*virtual*/ +bool LLWearableItemTypeNameComparator::sortWearableTypeByName(LLAssetType::EType item_type) const bool LLWearableItemCreationDateComparator::doCompare(const LLPanelInventoryListItemBase* item1, const LLPanelInventoryListItemBase* item2) const { - time_t date1 = item1->getCreationDate(); + wearable_type_order_map_t::const_iterator const_it = mWearableOrder.find(item_type); time_t date2 = item2->getCreationDate(); - if (date1 == date2) + if(const_it == mWearableOrder.end()) { - return LLWearableItemNameComparator::doCompare(item1, item2); + llwarns<<"Absent information about sorting items of "<<LLAssetType::getDesc(item_type)<<" type"<<llendl; + return true; } - return date1 > date2; + return const_it->second.mSortWearableTypeByName; } ////////////////////////////////////////////////////////////////////////// @@ -718,13 +753,11 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() const uuid_vec_t& ids = mUUIDs; // selected items IDs LLUUID selected_id = ids.front(); // ID of the first selected item - functor_t wear = boost::bind(&LLAppearanceMgr::wearItemOnAvatar, LLAppearanceMgr::getInstance(), _1, true, true, LLPointer<LLInventoryCallback>(NULL)); - functor_t add = boost::bind(&LLAppearanceMgr::wearItemOnAvatar, LLAppearanceMgr::getInstance(), _1, true, false, LLPointer<LLInventoryCallback>(NULL)); functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1); // Register handlers common for all wearable types. - registrar.add("Wearable.Wear", boost::bind(handleMultiple, wear, ids)); - registrar.add("Wearable.Add", boost::bind(handleMultiple, add, ids)); + registrar.add("Wearable.Wear", boost::bind(wear_multiple, ids, true)); + registrar.add("Wearable.Add", boost::bind(wear_multiple, ids, false)); registrar.add("Wearable.Edit", boost::bind(handleMultiple, LLAgentWearables::editWearable, ids)); registrar.add("Wearable.CreateNew", boost::bind(createNewWearable, selected_id)); registrar.add("Wearable.ShowOriginal", boost::bind(show_item_original, selected_id)); diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 55f8996140..84e999cd57 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -307,33 +307,76 @@ class LLWearableItemTypeNameComparator : public LLWearableItemNameComparator LOG_CLASS(LLWearableItemTypeNameComparator); public: - LLWearableItemTypeNameComparator() {}; + + LLWearableItemTypeNameComparator(); virtual ~LLWearableItemTypeNameComparator() {}; + enum ETypeListOrder + { + ORDER_RANK_1 = 1, + ORDER_RANK_2, + ORDER_RANK_3, + ORDER_RANK_UNKNOWN + }; + + void setOrder(LLAssetType::EType items_of_type, ETypeListOrder order_priority, bool sort_items_by_name, bool sort_wearable_items_by_name); + protected: /** - * Returns "true" if wearable_item1 is placed before wearable_item2 sorted by the following: - * - Attachments (abc order) - * - Clothing - * - by type (types order determined in LLWearableType::EType) - * - outer layer on top - * - Body Parts (abc order), - * "false" otherwise. + * All information about sort order is stored in mWearableOrder map + * + * mWearableOrder : KYES VALUES + * [LLAssetType] [struct LLWearableTypeOrder] + * + *--------------------------------------------------------------------------------------------- + * I. Determines order (ORDER_RANK) in which items of LLAssetType should be displayed in list. + * For example by spec in MY OUTFITS the order is: + * 1. AT_CLOTHING (ORDER_RANK_1) + * 2. AT_OBJECT (ORDER_RANK_2) + * 3. AT_BODYPART (ORDER_RANK_3) + * + * II.Items of each type(LLAssetType) are sorted by name or type(LLWearableType) + * For example by spec in MY OUTFITS the order within each items type(LLAssetType) is: + * 1. AT_OBJECTS (abc order) + * 2. AT_CLOTHINGS + * - by type (types order determined in LLWearableType::EType) + * - outer layer on top + * 3. AT_BODYPARTS (abc order) + *--------------------------------------------------------------------------------------------- + * + * For each LLAssetType (KEYS in mWearableOrder) the information about: + * + * I. ORDER_RANK (the flag is LLWearableTypeOrder::mOrderPriority) + * + * II. whether items of this LLAssetType type should be ordered + * by name or by LLWearableType::EType (the flag is LLWearableTypeOrder::mSortAssetTypeByName) + * + * III.whether items of LLWearableType type within this LLAssetType + * should be ordered by name (the flag is LLWearableTypeOrder::mSortWearableTypeByName) + * + * holds in mWearableOrder map as VALUES (struct LLWearableTypeOrder). */ /*virtual*/ bool doCompare(const LLPanelInventoryListItemBase* wearable_item1, const LLPanelInventoryListItemBase* wearable_item2) const; private: - enum ETypeListOrder + + struct LLWearableTypeOrder { - TLO_CLOTHING = 0x01, - TLO_ATTACHMENT = 0x02, - TLO_BODYPART = 0x04, - TLO_UNKNOWN = 0x08, + ETypeListOrder mOrderPriority; + bool mSortAssetTypeByName; + bool mSortWearableTypeByName; - TLO_SORTABLE_BY_NAME = TLO_ATTACHMENT | TLO_UNKNOWN + LLWearableTypeOrder(ETypeListOrder order_priority, bool sort_asset_by_name, bool sort_wearable_by_name); + LLWearableTypeOrder(){}; }; - static LLWearableItemTypeNameComparator::ETypeListOrder getTypeListOrder(LLAssetType::EType item_type); + ETypeListOrder getTypeListOrder(LLAssetType::EType item_type) const; + + bool sortAssetTypeByName(LLAssetType::EType item_type) const; + bool sortWearableTypeByName(LLAssetType::EType item_type) const; + + typedef std::map<LLAssetType::EType,LLWearableTypeOrder> wearable_type_order_map_t; + wearable_type_order_map_t mWearableOrder; }; /** diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 66cb02ce99..9bbe005de8 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -37,6 +37,7 @@ #include "llworldmapmessage.h" #include "message.h" #include "lltracker.h" +#include "lluistring.h" #include "llviewertexturelist.h" #include "lltrans.h" @@ -522,8 +523,12 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& case MAP_ITEM_LAND_FOR_SALE: // land for sale case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale { - std::string tooltip = llformat("%d sq. m. L$%d", extra, extra2); - new_item.setTooltip(tooltip); + static LLUIString tooltip_fmt = LLTrans::getString("worldmap_item_tooltip_format"); + + tooltip_fmt.setArg("[AREA]", llformat("%d", extra)); + tooltip_fmt.setArg("[PRICE]", llformat("%d", extra2)); + new_item.setTooltip(tooltip_fmt.getString()); + if (type == MAP_ITEM_LAND_FOR_SALE) { siminfo->insertLandForSale(new_item); diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index e4e677eb64..b97e5249e1 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -52,7 +52,7 @@ public: LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id); // Setters - void setTooltip(std::string& tooltip) { mToolTip = tooltip; } + void setTooltip(const std::string& tooltip) { mToolTip = tooltip; } void setElevation(F64 z) { mPosGlobal.mdV[VZ] = z; } void setCount(S32 count) { mCount = count; } // void setSelected(bool selected) { mSelected = selected; } diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 68e36ff0b3..99bf3e6bc1 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -1472,8 +1472,10 @@ Only large parcels can be listed in search. left="14" name="MatureCheck" top="177" + label_text.valign="center" + label_text.v_pad="-5" tool_tip=" " - width="107" /> + width="200" /> <text type="string" length="1" diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml index 7239b13466..e2348375d5 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml @@ -11,8 +11,7 @@ function="Object.Touch" /> <menu_item_call.on_enable function="Object.EnableTouch" - name="EnableTouch" - parameter="Touch" /> + name="EnableTouch"/> </menu_item_call> <!--menu_item_call label="Stand Up" diff --git a/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml index b6f00ef6d1..8ec7689819 100644 --- a/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml @@ -22,7 +22,7 @@ <menu_item_call.on_click function="InspectObject.Sit"/> <menu_item_call.on_visible - function="Object.EnableGearSit" /> + function="Object.EnableSit"/> </menu_item_call> <menu_item_call label="Pay" diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml index 6523b0d491..41f2b28004 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notices.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml @@ -76,19 +76,22 @@ Maximum 200 per group daily follows="top|left" height="23" image_overlay="AddItem_Off" + image_overlay_alignment="left" + imgoverlay_label_space="-10" + label="New Notice" layout="topleft" left="5" name="create_new_notice" tool_tip="Create a new notice" - top_delta="-3" - width="23" /> + top_delta="0" + width="93" /> <button follows="top|left" height="23" image_overlay="Refresh_Off" layout="topleft" name="refresh_notices" - left_pad="230" + left="260" tool_tip="Refresh list of notices" top_delta="0" width="23" /> @@ -113,7 +116,7 @@ Maximum 200 per group daily mouse_opaque="false" name="lbl" text_color="EmphasisColor" - top="0" + top="5" width="200"> Create a Notice </text> @@ -270,7 +273,7 @@ Maximum 200 per group daily mouse_opaque="false" name="lbl" text_color="EmphasisColor" - top_pad="0" + top_pad="5" width="265"> Archived Notice </text> diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 0eb5c47f85..18a2f37ba2 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -50,6 +50,10 @@ Select multiple Members by holding the Ctrl key and clicking on their names. </panel.string> <panel.string + name="donation_area"> + [AREA] m² + </panel.string> + <panel.string name="power_folder_icon" translate="false"> Inv_FolderClosed </panel.string> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index e5bd549036..a0c67e3612 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -278,6 +278,7 @@ <!-- world map --> <string name="texture_loading">Loading...</string> <string name="worldmap_offline">Offline</string> + <string name="worldmap_item_tooltip_format">[AREA] m² L$[PRICE]</string> <string name="worldmap_results_none_found">None found.</string> <!-- animations uploading status codes --> @@ -2102,6 +2103,7 @@ Clears (deletes) the media and all params from the given face. <string name="SummaryForTheWeek" value="Summary for this week, beginning on " /> <string name="NextStipendDay" value="The next stipend day is " /> <string name="GroupIndividualShare" value=" Group Individual Share" /> + <string name="GroupColumn" value=" Group" /> <string name="Balance">Balance</string> <string name="Credits">Credits</string> <string name="Debits">Debits</string> @@ -3141,6 +3143,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="group_role_everyone">Everyone</string> <string name="group_role_officers">Officers</string> <string name="group_role_owners">Owners</string> + <string name="group_member_status_online">Online</string> <string name="uploading_abuse_report">Uploading... @@ -3165,6 +3168,7 @@ Abuse Report</string> <string name="Invalid Wearable">Invalid Wearable</string> <string name="New Gesture">New Gesture</string> <string name="New Script">New Script</string> + <string name="New Note">New Note</string> <string name="New Folder">New Folder</string> <string name="Contents">Contents</string> <string name="Gesture">Gesture</string> diff --git a/indra/newview/skins/default/xui/fr/floater_water.xml b/indra/newview/skins/default/xui/fr/floater_water.xml index 96723b0fe6..7d1e3cd65c 100644 --- a/indra/newview/skins/default/xui/fr/floater_water.xml +++ b/indra/newview/skins/default/xui/fr/floater_water.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <floater name="Water Floater" title="ÉDITEUR D'EAU AVANCÉ"> <floater.string name="WLDefaultWaterNames"> - Default:Glassy:Pond:Murky:Second Plague:SNAKE!!!:Valdez + Valeur par défaut:Transparente:Bassin:Trouble:Première plaie:SERPENT !!!:Valdez </floater.string> <text name="KeyFramePresetsText" width="120"> Préréglages : diff --git a/indra/newview/skins/default/xui/fr/floater_windlight_options.xml b/indra/newview/skins/default/xui/fr/floater_windlight_options.xml index 74f1697449..657e5f5051 100644 --- a/indra/newview/skins/default/xui/fr/floater_windlight_options.xml +++ b/indra/newview/skins/default/xui/fr/floater_windlight_options.xml @@ -184,6 +184,6 @@ </panel> </tab_container> <string name="WLDefaultSkyNames"> - A-12AM:A-12PM:A-3AM:A-3PM:A-4.30PM:A-6AM:A-6PM:A-9AM:A-9PM:Barcelona:Blizzard:Blue Midday:Coastal Afternoon:Coastal Sunset:Default:Desert Sunset:Fine Day:Fluffy Big Clouds:Foggy:Funky Funky:Funky Funky Funky:Gelatto:Ghost:Incongruent Truths:Midday 1:Midday 2:Midday 3:Midday 4:Night:Pirate:Purple:Sailor's Delight:Sheer Sensuality + A-Minuit:A-Midi:A-3h:A-15h:A-16h30:A-6h:A-18h:A-9h:A-21h:Barcelone:Blizzard:Bleu mi-journée:Après-midi sur la côte:Coucher de soleil (côte):Valeur par défaut:Coucher de soleil (désert):Belle journée:Gros nuages floconneux:Brumeux:Funky Funky:Funky Funky Funky:Gelatto:Fantôme:Vérités incohérentes:Mi-journée 1:Mi-journée 2:Mi-journée 3:Mi-journée 4:Nuit:Pirate:Mauve:Rêve de navigateur:Sensualité pure </string> </floater> diff --git a/indra/newview/skins/default/xui/fr/panel_nearby_media.xml b/indra/newview/skins/default/xui/fr/panel_nearby_media.xml index 978ca86d62..1a6101830b 100644 --- a/indra/newview/skins/default/xui/fr/panel_nearby_media.xml +++ b/indra/newview/skins/default/xui/fr/panel_nearby_media.xml @@ -27,7 +27,7 @@ Médias proches </text> <text name="show_text"> - Afficher : + Voir : </text> <combo_box name="show_combo"> <combo_box.item label="Tout" name="All"/> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 1c29feec5f..347a5e8ab8 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -226,6 +226,16 @@ S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& resp return response.asInteger(); } +//----------------------------------------------------------------------------- +#include "../llmachineid.h" +unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {77,21,46,31,89,2}; + +S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) +{ + memcpy(unique_id, gMACAddress, len); + return 1; +} +//----------------------------------------------------------------------------- // misc std::string xml_escape_string(const std::string& in) { diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp index 2884231299..01c750487e 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.cpp +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -145,7 +145,7 @@ void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) TCHAR header[MAX_STRING]; std::string final; GetWindowText(hWnd, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str()); + final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); ConvertLPCSTRToLPWSTR(final.c_str(), header); SetWindowText(hWnd, header); } @@ -158,7 +158,7 @@ void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) TCHAR header[MAX_STRING]; std::string final; GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str()); + final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); ConvertLPCSTRToLPWSTR(final.c_str(), header); SetDlgItemText(hWnd, nIDDlgItem, header); } @@ -201,7 +201,7 @@ bool handle_button_click(WORD button_id) wbuffer, // pointer to buffer for text 20000 // maximum size of string ); - std::string user_text(ll_convert_wide_to_string(wbuffer)); + std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP)); // Activate and show the window. ShowWindow(gHwndProgress, SW_SHOW); // Try doing this second to make the progress window go frontmost. |