diff options
84 files changed, 1151 insertions, 231 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index 79ff7161f6..549adaaef7 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -362,6 +362,7 @@ Cinder Roxley STORM-2053 STORM-2113 STORM-2127 + STORM-2144 Clara Young Coaldust Numbers VWR-1095 @@ -821,6 +822,7 @@ Kitty Barnett MAINT-6153 MAINT-6154 MAINT-6568 + STORM-2149 Kolor Fall Komiko Okamoto Korvel Noh @@ -1302,6 +1304,7 @@ Sovereign Engineer MAINT-6218 MAINT-6913 STORM-2143 + STORM-2148 MAINT-7343 SpacedOut Frye VWR-34 diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 81ba8631c6..3a219eb998 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2091,7 +2091,18 @@ std::string zip_llsd(LLSD& data) } have = CHUNK-strm.avail_out; - output = (U8*) realloc(output, cur_size+have); + U8* new_output = (U8*) realloc(output, cur_size+have); + if (new_output == NULL) + { + LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + deflateEnd(&strm); + if (output) + { + free(output); + } + return std::string(); + } + output = new_output; memcpy(output+cur_size, out, have); cur_size += have; } @@ -2174,7 +2185,19 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*)realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete[] in; + return false; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; @@ -2266,7 +2289,20 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*) realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete[] in; + valid = false; + return NULL; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 2255e638c2..abe5fda603 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1325,6 +1325,10 @@ void LLStringUtilBase<T>::removeCRLF(string_type& string) template<class T> void LLStringUtilBase<T>::removeWindowsCR(string_type& string) { + if (string.empty()) + { + return; + } const T LF = 10; const T CR = 13; diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index a299602d79..a4823ed859 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -124,12 +124,12 @@ bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) // Temporary buffer to hold the encoded image. Note: the final image // size should be much smaller due to compression. - U32 bufferSize = getWidth() * getHeight() * getComponents() + 1024; + U32 bufferSize = getWidth() * getHeight() * getComponents() + 8192; U8* tmpWriteBuffer = new U8[ bufferSize ]; // Delegate actual encoding work to wrapper LLPngWrapper pngWrapper; - if (! pngWrapper.writePng(raw_image, tmpWriteBuffer)) + if (!pngWrapper.writePng(raw_image, tmpWriteBuffer, bufferSize)) { setLastError(pngWrapper.getErrorMessage()); delete[] tmpWriteBuffer; diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index da289ea889..eb70b78a36 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -112,6 +112,11 @@ void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_siz void LLPngWrapper::writeDataCallback(png_structp png_ptr, png_bytep src, png_size_t length) { PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr); + if (dataInfo->mOffset + length > dataInfo->mDataSize) + { + png_error(png_ptr, "Data write error. Requested data size exceeds available data size."); + return; + } U8 *dest = &dataInfo->mData[dataInfo->mOffset]; memcpy(dest, src, length); dataInfo->mOffset += static_cast<U32>(length); @@ -272,7 +277,7 @@ void LLPngWrapper::updateMetaData() // Method to write raw image into PNG at dest. The raw scanline begins // at the bottom of the image per SecondLife conventions. -BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest) +BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest, size_t destSize) { try { @@ -313,6 +318,7 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest) PngDataInfo dataPtr; dataPtr.mData = dest; dataPtr.mOffset = 0; + dataPtr.mDataSize = destSize; png_set_write_fn(mWritePngPtr, &dataPtr, &writeDataCallback, &writeFlush); // Setup image params diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 27d7df3bef..8d42317b0f 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -45,7 +45,7 @@ public: BOOL isValidPng(U8* src); BOOL readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop = NULL); - BOOL writePng(const LLImageRaw* rawImage, U8* dst); + BOOL writePng(const LLImageRaw* rawImage, U8* dst, size_t destSize); U32 getFinalSize(); const std::string& getErrorMessage(); diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 406afadd2f..4e0c53c37e 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -499,9 +499,10 @@ BOOL LLTemplateMessageReader::decodeTemplate( } else { - LL_WARNS() << "Message #" << std::hex << num << std::dec - << " received but not registered!" << LL_ENDL; - gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); + // MAINT-7482 - make viewer more tolerant of unknown messages. + LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec + << " received but not registered!" << LL_ENDL; + //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); return(FALSE); } diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index f1b6fe0a12..680017204c 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -224,7 +224,14 @@ void LLPluginClassMedia::idle(void) void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); // clear texture memory to avoid random screen visual fuzz from uninitialized texture data - memset( addr, 0x00, newsize ); + if (addr) + { + memset( addr, 0x00, newsize ); + } + else + { + LL_WARNS("Plugin") << "Failed to get previously created shared memory address: " << mTextureSharedMemoryName << " size: " << mTextureSharedMemorySize << LL_ENDL; + } // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, // so it may not be worthwhile. diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index f8ef5289db..eaf1284237 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -823,6 +823,11 @@ BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent) void LLAccordionCtrlTab::showAndFocusHeader() { + if (!mHeader) + { + return; + } + mHeader->setFocus(true); mHeader->setSelected(mSelectionEnabled); diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index f9664e0658..895753aeae 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -102,6 +102,18 @@ void LLCloseAllFoldersFunctor::doFolder(LLFolderViewFolder* folder) void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) { } +//--------------------------------------------------------------------------- + +void LLAllDescendentsPassedFilter::doFolder(LLFolderViewFolder* folder) +{ + mAllDescendentsPassedFilter &= (folder) && (folder->passedFilter()) && (folder->descendantsPassedFilter()); +} + +void LLAllDescendentsPassedFilter::doItem(LLFolderViewItem* item) +{ + mAllDescendentsPassedFilter &= (item) && (item->passedFilter()); +} + ///---------------------------------------------------------------------------- /// Class LLFolderViewScrollContainer ///---------------------------------------------------------------------------- diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index b5deefd653..2926e160d0 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -400,6 +400,18 @@ public: virtual void doItem(LLFolderViewItem* item); }; +class LLAllDescendentsPassedFilter : public LLFolderViewFunctor +{ +public: + LLAllDescendentsPassedFilter() : mAllDescendentsPassedFilter(true) {} + /*virtual*/ ~LLAllDescendentsPassedFilter() {} + /*virtual*/ void doFolder(LLFolderViewFolder* folder); + /*virtual*/ void doItem(LLFolderViewItem* item); + bool allDescendentsPassedFilter() const { return mAllDescendentsPassedFilter; } +protected: + bool mAllDescendentsPassedFilter; +}; + // Flags for buildContextMenu() const U32 SUPPRESS_OPEN_ITEM = 0x1; const U32 FIRST_SELECTED_ITEM = 0x2; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 3d618548c4..0510e472c5 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1176,6 +1176,11 @@ BOOL LLFolderViewFolder::needsArrange() return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); } +bool LLFolderViewFolder::descendantsPassedFilter(S32 filter_generation) +{ + return getViewModelItem()->descendantsPassedFilter(filter_generation); +} + // Passes selection information on to children and record selection // information if necessary. BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem, diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 022f814bbc..0d42f726fa 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3331,6 +3331,7 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) if (getHighlightedItem()) { clearHoverItem(); + LLMenuGL::setKeyboardMode(FALSE); } else { @@ -3777,10 +3778,10 @@ BOOL LLMenuHolderGL::hideMenus() { return FALSE; } + LLMenuGL::setKeyboardMode(FALSE); BOOL menu_visible = hasVisibleMenu(); if (menu_visible) { - LLMenuGL::setKeyboardMode(FALSE); // clicked off of menu, hide them all for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 604092d536..d40347de13 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -426,6 +426,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mLogToChat(p.log_to_chat), mLogToIM(p.log_to_im), mShowToast(p.show_toast), + mFadeToast(p.fade_toast), mSoundName("") { if (p.sound.isProvided() @@ -942,6 +943,11 @@ bool LLNotification::canShowToast() const return mTemplatep->mShowToast; } +bool LLNotification::canFadeToast() const +{ + return mTemplatep->mFadeToast; +} + bool LLNotification::hasFormElements() const { return mTemplatep->mForm->getNumElements() != 0; @@ -1792,6 +1798,12 @@ bool LLNotifications::getIgnoreAllNotifications() { return mIgnoreAllNotifications; } + +bool LLNotifications::getIgnored(const std::string& name) +{ + LLNotificationTemplatePtr templatep = getTemplate(name); + return (mIgnoreAllNotifications) || ( (templatep->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) && (templatep->mForm->getIgnored()) ); +} bool LLNotifications::isVisibleByRules(LLNotificationPtr n) { diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 024332ee65..a7a5490432 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -558,6 +558,7 @@ public: bool canLogToChat() const; bool canLogToIM() const; bool canShowToast() const; + bool canFadeToast() const; bool hasFormElements() const; void playSound(); @@ -963,6 +964,8 @@ public: void setIgnoreAllNotifications(bool ignore); bool getIgnoreAllNotifications(); + bool getIgnored(const std::string& name); + bool isVisibleByRules(LLNotificationPtr pNotification); private: diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index bed29254d8..20cbc89ede 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -177,6 +177,7 @@ struct LLNotificationTemplate Optional<bool> persist, log_to_im, show_toast, + fade_toast, log_to_chat, force_urls_external; Optional<std::string> functor, @@ -199,6 +200,7 @@ struct LLNotificationTemplate Params() : name("name"), persist("persist", false), + fade_toast("fade_toast", true), log_to_im("log_to_im", false), show_toast("show_toast", true), log_to_chat("log_to_chat", true), @@ -316,6 +318,7 @@ struct LLNotificationTemplate bool mLogToChat; bool mLogToIM; bool mShowToast; + bool mFadeToast; }; #endif //LL_LLNOTIFICATION_TEMPLATE_H diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 0afa8d43f1..7c1f4a4dca 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -345,6 +345,21 @@ S32 LLScrollListCtrl::getItemCount() const return mItemList.size(); } +BOOL LLScrollListCtrl::hasSelectedItem() const +{ + item_list::iterator iter; + for (iter = mItemList.begin(); iter < mItemList.end(); ) + { + LLScrollListItem* itemp = *iter; + if (itemp && itemp->getSelected()) + { + return TRUE; + } + iter++; + } + return FALSE; +} + // virtual LLScrolListInterface function (was deleteAllItems) void LLScrollListCtrl::clearRows() { diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 8343750a54..699a8744e1 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -201,6 +201,8 @@ public: virtual BOOL isSelected(const LLSD& value) const; + BOOL hasSelectedItem() const; + BOOL handleClick(S32 x, S32 y, MASK mask); BOOL selectFirstItem(); BOOL selectNthItem( S32 index ); diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index d49e216898..f6831c6d5e 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -130,6 +130,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p) params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); + mEditor->setFocusLostCallback( boost::bind(&LLSpinCtrl::onEditorLostFocus, _1, this )); if (p.allow_digits_only) { mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); @@ -239,6 +240,31 @@ void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) self->onFocusReceived(); } +// static +void LLSpinCtrl::onEditorLostFocus( LLFocusableElement* caller, void *userdata ) +{ + LLSpinCtrl* self = (LLSpinCtrl*) userdata; + llassert( caller == self->mEditor ); + + self->onFocusLost(); + + std::string text = self->mEditor->getText(); + + LLLocale locale(LLLocale::USER_LOCALE); + F32 val = (F32)atof(text.c_str()); + + F32 saved_val = self->getValueF32(); + if (saved_val != val && !self->mEditor->isDirty()) + { + // Editor was focused when value update arrived, string + // in editor is different from one in spin control. + // Since editor is not dirty, it won't commit, so either + // attempt to commit value from editor or revert to a more + // recent value from spin control + self->updateEditor(); + } +} + void LLSpinCtrl::setValue(const LLSD& value ) { F32 v = (F32)value.asReal(); diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index e34add879d..cab99c35bd 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -93,6 +93,7 @@ public: void onEditorCommit(const LLSD& data); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); + static void onEditorLostFocus(LLFocusableElement* caller, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); void onUpBtn(const LLSD& data); diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp index 76296ff877..3eb64e69d9 100644 --- a/indra/llvfs/lldiriterator.cpp +++ b/indra/llvfs/lldiriterator.cpp @@ -51,7 +51,11 @@ private: LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) : mIsValid(false) { +#ifdef LL_WINDOWS // or BOOST_WINDOWS_API + fs::path dir_path(utf8str_to_utf16str(dirname)); +#else fs::path dir_path(dirname); +#endif bool is_dir = false; diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index e7afef63f8..d4790f9f29 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -35,6 +35,7 @@ #undef INITGUID #include <wbemidl.h> +#include <comdef.h> #include <boost/tokenizer.hpp> @@ -206,6 +207,160 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) return E_FAIL; } +//Getting the version of graphics controller driver via WMI +std::string LLDXHardware::getDriverVersionWMI() +{ + std::string mDriverVersion; + HRESULT hrCoInitialize = S_OK; + HRESULT hres; + hrCoInitialize = CoInitialize(0); + IWbemLocator *pLoc = NULL; + + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *)&pLoc); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hres << LL_ENDL; + return std::string(); // Program has failed. + } + + IWbemServices *pSvc = NULL; + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (e.g. Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hres << LL_ENDL; + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; + + // Set security levels on the proxy ------------------------- + hres = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + IEnumWbemClassObject* pEnumerator = NULL; + + // Get the data from the query + ULONG uReturn = 0; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_VideoController"), //Consider using Availability to filter out disabled controllers + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + while (pEnumerator) + { + IWbemClassObject *pclsObj = NULL; + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; // If quantity less then 1. + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"DriverVersion", 0, &vtProp, 0, 0); + + if (FAILED(hr)) + { + LL_WARNS("AppInit") << "Query for name property failed." << " Error code = 0x" << hr << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + // use characters in the returned driver version + BSTR driverVersion(vtProp.bstrVal); + + //convert BSTR to std::string + std::wstring ws(driverVersion, SysStringLen(driverVersion)); + std::string str(ws.begin(), ws.end()); + LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL; + + if (mDriverVersion.empty()) + { + mDriverVersion = str; + } + else if (mDriverVersion != str) + { + LL_WARNS("DriverVersion") << "Different versions of drivers. Version of second driver : " << str << LL_ENDL; + } + + VariantClear(&vtProp); + pclsObj->Release(); + } + + // Cleanup + // ======== + if (pSvc) + { + pSvc->Release(); + } + if (pLoc) + { + pLoc->Release(); + } + if (pEnumerator) + { + pEnumerator->Release(); + } + if (SUCCEEDED(hrCoInitialize)) + { + CoUninitialize(); + } + return mDriverVersion; +} + void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize) { HRESULT hr; diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index 61a32bf0fb..cf33db8b37 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -88,6 +88,8 @@ public: // vram_only TRUE does a "light" probe. BOOL getInfo(BOOL vram_only); + std::string getDriverVersionWMI(); + S32 getVRAM() const { return mVRAM; } LLSD getDisplayInfo(); diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi Binary files differindex 866accae99..2a868acc89 100644 --- a/indra/newview/installers/windows/lang_de.nsi +++ b/indra/newview/installers/windows/lang_de.nsi diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi Binary files differindex f4f0786332..1ecf254ffb 100644 --- a/indra/newview/installers/windows/lang_es.nsi +++ b/indra/newview/installers/windows/lang_es.nsi diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi Binary files differindex 1b5dbfc975..bec5835bed 100644 --- a/indra/newview/installers/windows/lang_fr.nsi +++ b/indra/newview/installers/windows/lang_fr.nsi diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi Binary files differindex a456e6e417..1d2e150525 100644 --- a/indra/newview/installers/windows/lang_it.nsi +++ b/indra/newview/installers/windows/lang_it.nsi diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi Binary files differindex 5b1c5f4ce9..1bd6526670 100644 --- a/indra/newview/installers/windows/lang_ja.nsi +++ b/indra/newview/installers/windows/lang_ja.nsi diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi Binary files differindex 9ef252d232..87032fec18 100644 --- a/indra/newview/installers/windows/lang_pt-br.nsi +++ b/indra/newview/installers/windows/lang_pt-br.nsi diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi Binary files differindex d7c728d3e2..019c66123c 100644 --- a/indra/newview/installers/windows/lang_ru.nsi +++ b/indra/newview/installers/windows/lang_ru.nsi diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi Binary files differindex 97c602f4fc..1c4e2c2f48 100644 --- a/indra/newview/installers/windows/lang_tr.nsi +++ b/indra/newview/installers/windows/lang_tr.nsi diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi Binary files differindex 39c005a683..355e01a333 100644 --- a/indra/newview/installers/windows/lang_zh.nsi +++ b/indra/newview/installers/windows/lang_zh.nsi diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 648212177b..ee49125711 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -394,6 +394,40 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents"); } + else if (status.getType() == 410) //GONE + { + // Item does not exist or was already deleted from server. + // parent folder is out of sync + if (type == REMOVECATEGORY) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(targetId); + if (cat) + { + LL_WARNS("Inventory") << "Purge failed for '" << cat->getName() + << "' local version:" << cat->getVersion() + << " since folder no longer exists at server. Descendent count: server == " << cat->getDescendentCount() + << ", viewer == " << cat->getViewerDescendentCount() + << LL_ENDL; + gInventory.fetchDescendentsOf(cat->getParentUUID()); + // Note: don't delete folder here - contained items will be deparented (or deleted) + // and since we are clearly out of sync we can't be sure we won't get rid of something we need. + // For example folder could have been moved or renamed with items intact, let it fetch first. + } + } + else if (type == REMOVEITEM) + { + LLViewerInventoryItem *item = gInventory.getItem(targetId); + if (item) + { + LL_WARNS("Inventory") << "Purge failed for '" << item->getName() + << "' since item no longer exists at server." << LL_ENDL; + gInventory.fetchDescendentsOf(item->getParentUUID()); + // since item not on the server and exists at viewer, so it needs an update at the least, + // so delete it, in worst case item will be refetched with new params. + gInventory.onObjectDeletedFromServer(targetId); + } + } + } LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL; LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; } @@ -970,7 +1004,16 @@ void AISUpdate::doUpdate() // inventory COF is maintained on the viewer through calls to // LLInventoryModel::accountForUpdate when a changing operation // is performed. This occasionally gets out of sync however. - cat->setVersion(version); + if (version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + cat->setVersion(version); + } + else + { + // We do not account for update if version is UNKNOWN, so we shouldn't rise version + // either or viewer will get stuck on descendants count -1, try to refetch folder instead + cat->fetch(); + } } } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index cfdc752db4..37340a42b6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3341,10 +3341,19 @@ LLSD LLAppViewer::getViewerInfo() const info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER)); #if LL_WINDOWS - LLSD driver_info = gDXHardware.getDisplayInfo(); - if (driver_info.has("DriverVersion")) + std::string drvinfo = gDXHardware.getDriverVersionWMI(); + if (!drvinfo.empty()) { - info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + info["GRAPHICS_DRIVER_VERSION"] = drvinfo; + } + else + { + LL_WARNS("Driver version")<< "Cannot get driver version from getDriverVersionWMI" << LL_ENDL; + LLSD driver_info = gDXHardware.getDisplayInfo(); + if (driver_info.has("DriverVersion")) + { + info["GRAPHICS_DRIVER_VERSION"] = driver_info["DriverVersion"]; + } } #endif diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 219d9da01f..8fe684ad79 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -1005,7 +1005,7 @@ void LLAvatarActions::toggleBlock(const LLUUID& id) } // static -void LLAvatarActions::toggleMuteVoice(const LLUUID& id) +void LLAvatarActions::toggleMute(const LLUUID& id, U32 flags) { LLAvatarName av_name; LLAvatarNameCache::get(id, &av_name); @@ -1016,15 +1016,21 @@ void LLAvatarActions::toggleMuteVoice(const LLUUID& id) LLMute mute(id, av_name.getUserName(), LLMute::AGENT); if (!is_muted) { - mute_list->add(mute, LLMute::flagVoiceChat); + mute_list->add(mute, flags); } else { - mute_list->remove(mute, LLMute::flagVoiceChat); + mute_list->remove(mute, flags); } } // static +void LLAvatarActions::toggleMuteVoice(const LLUUID& id) +{ + toggleMute(id, LLMute::flagVoiceChat); +} + +// static bool LLAvatarActions::canOfferTeleport(const LLUUID& id) { // First use LLAvatarTracker::isBuddy() diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 256d44d820..b56d5b0fb9 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -131,6 +131,11 @@ public: static void toggleBlock(const LLUUID& id); /** + * Mute/unmute avatar. + */ + static void toggleMute(const LLUUID& id, U32 flags); + + /** * Block/unblock the avatar voice. */ static void toggleMuteVoice(const LLUUID& id); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 9798ef3529..5748eeec47 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -38,10 +38,14 @@ #include "llpanel.h" #include "lluictrlfactory.h" #include "llscrollcontainer.h" -#include "llavatariconctrl.h" -#include "llcallingcard.h" //for LLAvatarTracker +#include "llagent.h" #include "llagentdata.h" #include "llavataractions.h" +#include "llavatariconctrl.h" +#include "llcallingcard.h" //for LLAvatarTracker +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llspeakers.h" //for LLIMSpeakerMgr #include "lltrans.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" @@ -49,7 +53,6 @@ #include "llstylemap.h" #include "llslurl.h" #include "lllayoutstack.h" -#include "llagent.h" #include "llnotificationsutil.h" #include "lltoastnotifypanel.h" #include "lltooltip.h" @@ -61,7 +64,6 @@ #include "llurlaction.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" -#include "llmutelist.h" static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history"); @@ -187,6 +189,161 @@ public: return false; } + void banGroupMember(const LLUUID& participant_uuid) + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return; + } + + gdatap->banMemberById(participant_uuid); + } + + bool canBanInGroup() + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return false; + } + + if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + + return false; + } + + bool canBanGroupMember(const LLUUID& participant_uuid) + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return false; + } + + if (gdatap->mPendingBanRequest) + { + return false; + } + + if (gAgentID == getAvatarId()) + { + //Don't ban self + return false; + } + + if (gdatap->isRoleMemberDataComplete()) + { + if (gdatap->mMembers.size()) + { + LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(participant_uuid); + if (mi != gdatap->mMembers.end()) + { + LLGroupMemberData* member_data = (*mi).second; + // Is the member an owner? + if (member_data && member_data->isInRole(gdatap->mOwnerRole)) + { + return false; + } + + if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + } + } + } + + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(participant_uuid).get(); + + if (speakerp + && gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + } + + return false; + } + + bool isGroupModerator() + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (!speaker_mgr) + { + LL_WARNS() << "Speaker manager is missing" << LL_ENDL; + return false; + } + + // Is session a group call/chat? + if(gAgent.isInGroup(mSessionID)) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(gAgentID).get(); + + // Is agent a moderator? + return speakerp && speakerp->mIsModerator; + } + + return false; + } + + bool canModerate(const std::string& userdata) + { + // only group moderators can perform actions related to this "enable callback" + if (!isGroupModerator() || gAgentID == getAvatarId()) + { + return false; + } + + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (!speaker_mgr) + { + return false; + } + + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (!speakerp) + { + return false; + } + + bool voice_channel = speakerp->isInVoiceChannel(); + + if ("can_moderate_voice" == userdata) + { + return voice_channel; + } + else if ("can_mute" == userdata) + { + return voice_channel && (speakerp->mStatus != LLSpeaker::STATUS_MUTED); + } + else if ("can_unmute" == userdata) + { + return speakerp->mStatus == LLSpeaker::STATUS_MUTED; + } + else if ("can_allow_text_chat" == userdata) + { + return true; + } + + return false; + } + void onAvatarIconContextMenuItemClicked(const LLSD& userdata) { std::string level = userdata.asString(); @@ -245,11 +402,36 @@ public: } else if(level == "block_unblock") { - mute(getAvatarId(), LLMute::flagVoiceChat); + LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagVoiceChat); } else if(level == "mute_unmute") { - mute(getAvatarId(), LLMute::flagTextChat); + LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagTextChat); + } + else if(level == "toggle_allow_text_chat") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + speaker_mgr->toggleAllowTextChat(getAvatarId()); + } + else if(level == "group_mute") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + speaker_mgr->moderateVoiceParticipant(getAvatarId(), false); + } + } + else if(level == "group_unmute") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + speaker_mgr->moderateVoiceParticipant(getAvatarId(), true); + } + } + else if(level == "ban_member") + { + banGroupMember(getAvatarId()); } } @@ -265,24 +447,69 @@ public: { return LLMuteList::getInstance()->isMuted(getAvatarId(), LLMute::flagTextChat); } + else if (level == "is_allowed_text_chat") + { + if (gAgent.isInGroup(mSessionID)) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + const LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()); + + if (NULL != speakerp) + { + return !speakerp->mModeratorMutedText; + } + } + return false; + } return false; } - void mute(const LLUUID& participant_id, U32 flags) + bool onAvatarIconContextMenuItemEnabled(const LLSD& userdata) { - BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags); - LLAvatarName av_name; - LLAvatarNameCache::get(participant_id, &av_name); - LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT); + std::string level = userdata.asString(); - if (!is_muted) + if (level == "can_allow_text_chat" || level == "can_mute" || level == "can_unmute") { - LLMuteList::getInstance()->add(mute, flags); + return canModerate(userdata); } - else + else if (level == "can_ban_member") { - LLMuteList::getInstance()->remove(mute, flags); + return canBanGroupMember(getAvatarId()); } + return false; + } + + bool onAvatarIconContextMenuItemVisible(const LLSD& userdata) + { + std::string level = userdata.asString(); + + if (level == "show_mute") + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (speakerp) + { + return speakerp->isInVoiceChannel() && speakerp->mStatus != LLSpeaker::STATUS_MUTED; + } + } + return false; + } + else if (level == "show_unmute") + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (speakerp) + { + return speakerp->mStatus == LLSpeaker::STATUS_MUTED; + } + } + return false; + } + return false; } BOOL postBuild() @@ -292,6 +519,8 @@ public: registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); + registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); + registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); @@ -567,9 +796,14 @@ protected: if(menu) { bool is_friend = LLAvatarActions::isFriend(mAvatarID); + bool is_group_session = gAgent.isInGroup(mSessionID); menu->setItemEnabled("Add Friend", !is_friend); menu->setItemEnabled("Remove Friend", is_friend); + menu->setItemVisible("Moderator Options Separator", is_group_session && isGroupModerator()); + menu->setItemVisible("Moderator Options", is_group_session && isGroupModerator()); + menu->setItemVisible("Group Ban Separator", is_group_session && canBanInGroup()); + menu->setItemVisible("BanMember", is_group_session && canBanInGroup()); if(gAgentID == mAvatarID) { diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 711a87dc99..d657f04457 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -407,6 +407,7 @@ void LLExpandableTextBox::collapseTextBox() setRect(mCollapsedRect); updateTextBoxRect(); + gViewerWindow->removePopup(this); } void LLExpandableTextBox::onFocusLost() @@ -434,8 +435,6 @@ void LLExpandableTextBox::reshape(S32 width, S32 height, BOOL called_from_parent mExpanded = false; LLUICtrl::reshape(width, height, called_from_parent); updateTextBoxRect(); - - gViewerWindow->removePopup(this); } void LLExpandableTextBox::setValue(const LLSD& value) diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index a7236d1778..7e92643b93 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -544,11 +544,18 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) send_agent_pause(); { // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! - success = GetSaveFileName(&mOFN); - if (success) + try { - std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); - mFiles.push_back(filename); + success = GetSaveFileName(&mOFN); + if (success) + { + std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); + mFiles.push_back(filename); + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); } gKeyboard->resetKeys(); } diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 3522932d03..333765f99f 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1150,11 +1150,11 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec } else if ("block_unblock" == command) { - toggleMute(userID, LLMute::flagVoiceChat); + LLAvatarActions::toggleMute(userID, LLMute::flagVoiceChat); } else if ("mute_unmute" == command) { - toggleMute(userID, LLMute::flagTextChat); + LLAvatarActions::toggleMute(userID, LLMute::flagTextChat); } else if ("selected" == command || "mute_all" == command || "unmute_all" == command) { @@ -2096,24 +2096,6 @@ void LLFloaterIMContainer::toggleAllowTextChat(const LLUUID& participant_uuid) } } -void LLFloaterIMContainer::toggleMute(const LLUUID& participant_id, U32 flags) -{ - BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags); - - LLAvatarName av_name; - LLAvatarNameCache::get(participant_id, &av_name); - LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT); - - if (!is_muted) - { - LLMuteList::getInstance()->add(mute, flags); - } - else - { - LLMuteList::getInstance()->remove(mute, flags); - } -} - void LLFloaterIMContainer::openNearbyChat() { // If there's only one conversation in the container and that conversation is the nearby chat diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 60cef83d9a..90fc0c2bdd 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -176,7 +176,6 @@ private: void moderateVoiceAllParticipants(bool unmute); void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); void toggleAllowTextChat(const LLUUID& participant_uuid); - void toggleMute(const LLUUID& participant_id, U32 flags); void banSelectedMember(const LLUUID& participant_uuid); void openNearbyChat(); bool isParticipantListExpanded(); diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 7895a5ff48..b2568abb83 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -87,6 +87,10 @@ static LLChatTypeTrigger sChatTypeTriggers[] = { { "/shout" , CHAT_TYPE_SHOUT} }; +bool cb_do_nothing() +{ + return false; +} LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd) : LLFloaterIMSessionTab(LLSD(LLUUID::null)), @@ -97,6 +101,12 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd) mIsP2PChat = false; mIsNearbyChat = true; mSpeakerMgr = LLLocalSpeakerMgr::getInstance(); + + // Required by LLFloaterIMSessionTab::mGearBtn + // But nearby floater has no 'per agent' menu items, + mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing)); + mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing)); + mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing)); } //static diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 2cd94c592a..3aee08482b 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -46,6 +46,10 @@ const F32 REFRESH_INTERVAL = 1.0f; +void cb_group_do_nothing() +{ +} + LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) : LLTransientDockableFloater(NULL, false, session_id), mIsP2PChat(false), @@ -82,6 +86,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2)); mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2)); mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing)); } LLFloaterIMSessionTab::~LLFloaterIMSessionTab() diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index c33dee5fb4..c330c2ae47 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2290,13 +2290,15 @@ BOOL LLPanelEstateInfo::postBuild() getChild<LLUICtrl>("parcel_access_override")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeAccessOverride, this)); + getChild<LLUICtrl>("externally_visible_radio")->setFocus(TRUE); + return LLPanelRegionInfo::postBuild(); } void LLPanelEstateInfo::refresh() { // Disable access restriction controls if they make no sense. - bool public_access = getChild<LLRadioGroup>("externally_visible_radio")->getSelectedIndex(); + bool public_access = ("estate_public_access" == getChild<LLUICtrl>("externally_visible_radio")->getValue().asString()); getChildView("Only Allow")->setEnabled(public_access); getChildView("limit_payment")->setEnabled(public_access); @@ -2317,7 +2319,7 @@ void LLPanelEstateInfo::refreshFromEstate() getChild<LLUICtrl>("estate_name")->setValue(estate_info.getName()); setOwnerName(LLSLURL("agent", estate_info.getOwnerID(), "inspect").getSLURLString()); - getChild<LLRadioGroup>("externally_visible_radio")->setSelectedIndex(estate_info.getIsExternallyVisible() ? 1 : 0); + getChild<LLUICtrl>("externally_visible_radio")->setValue(estate_info.getIsExternallyVisible() ? "estate_public_access" : "estate_restricted_access"); getChild<LLUICtrl>("voice_chat_check")->setValue(estate_info.getAllowVoiceChat()); getChild<LLUICtrl>("allow_direct_teleport")->setValue(estate_info.getAllowDirectTeleport()); getChild<LLUICtrl>("limit_payment")->setValue(estate_info.getDenyAnonymous()); @@ -2360,7 +2362,7 @@ bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, con // update model estate_info.setUseFixedSun(false); // we don't support fixed sun estates anymore - estate_info.setIsExternallyVisible(getChild<LLRadioGroup>("externally_visible_radio")->getSelectedIndex()); + estate_info.setIsExternallyVisible("estate_public_access" == getChild<LLUICtrl>("externally_visible_radio")->getValue().asString()); estate_info.setAllowDirectTeleport(getChild<LLUICtrl>("allow_direct_teleport")->getValue().asBoolean()); estate_info.setDenyAnonymous(getChild<LLUICtrl>("limit_payment")->getValue().asBoolean()); estate_info.setDenyAgeUnverified(getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean()); diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index b14b9b7578..2869256d09 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -638,20 +638,20 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) // HACK - highlight buttons for next click mRadioGroupMove->setVisible(move_visible); - if (!gGrabBtnSpin && - !gGrabBtnVertical && - !(mask == MASK_VERTICAL) && - !(mask == MASK_SPIN) ) + if (!(gGrabBtnSpin || + gGrabBtnVertical || + (mask == MASK_VERTICAL) || + (mask == MASK_SPIN))) { mRadioGroupMove->setValue("radio move"); } - else if (gGrabBtnVertical || - (mask == MASK_VERTICAL) ) + else if ((mask == MASK_VERTICAL) || + (gGrabBtnVertical && (mask != MASK_SPIN))) { mRadioGroupMove->setValue("radio lift"); } - else if (gGrabBtnSpin || - (mask == MASK_SPIN) ) + else if ((mask == MASK_SPIN) || + (gGrabBtnSpin && (mask != MASK_VERTICAL))) { mRadioGroupMove->setValue("radio spin"); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1b32fc9dfe..2751631a59 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3884,8 +3884,14 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array); + LLViewerInventoryCategory *trash = getCategory(); // Enable Empty menu item only when there is something to act upon. - if ((0 == cat_array->size() && 0 == item_array->size()) || is_recent_panel) + // Also don't enable menu if folder isn't fully fetched + if ((0 == cat_array->size() && 0 == item_array->size()) + || is_recent_panel + || !trash + || trash->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN + || trash->getDescendentCount() == LLViewerInventoryCategory::VERSION_UNKNOWN) { disabled_items.push_back(std::string("Empty Trash")); } @@ -4060,8 +4066,6 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); // BAP change once we're no longer treating regular categories as ensembles. - const bool is_ensemble = (type == LLFolderType::FT_NONE || - LLFolderType::lookupIsEnsembleType(type)); const bool is_agent_inventory = isAgentInventory(); // Only enable calling-card related options for non-system folders. @@ -4104,30 +4108,26 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& } items.push_back(std::string("Replace Outfit")); - - if (is_agent_inventory) + } + if (is_agent_inventory) + { + items.push_back(std::string("Folder Wearables Separator")); + items.push_back(std::string("Remove From Outfit")); + if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) { - items.push_back(std::string("Folder Wearables Separator")); - if (is_ensemble) - { - items.push_back(std::string("Wear As Ensemble")); - } - items.push_back(std::string("Remove From Outfit")); - if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) - { disabled_items.push_back(std::string("Remove From Outfit")); - } - } - if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) - { - disabled_items.push_back(std::string("Replace Outfit")); - } - if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) - { - disabled_items.push_back(std::string("Add To Outfit")); } - items.push_back(std::string("Outfit Separator")); } + if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) + { + disabled_items.push_back(std::string("Replace Outfit")); + } + if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) + { + disabled_items.push_back(std::string("Add To Outfit")); + } + items.push_back(std::string("Outfit Separator")); + } } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index bccc654fbf..90d6e9b8a8 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -92,6 +92,8 @@ BOOL LLInventoryState::sWearNewClothing = FALSE; LLUUID LLInventoryState::sWearNewClothingTransactionID; std::list<LLUUID> LLInventoryAction::sMarketplaceFolders; +const int LLInventoryAction::sConfirmOnDeleteItemsNumber = 5; + // Helper function : callback to update a folder after inventory action happened in the background void update_folder_cb(const LLUUID& dest_folder) { @@ -2295,9 +2297,51 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if ("delete" == action) { - LLSD args; - args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + static bool sDisplayedAtSession = false; + + bool has_folder_items = false; + for (std::set<LLFolderViewItem*>::iterator set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*set_iter)->getViewModelItem()); + if (viewModel && viewModel->hasChildren()) + { + has_folder_items = true; + break; + } + } + if (root->getSelectedCount() >= sConfirmOnDeleteItemsNumber || has_folder_items) + { + bool ignore = !(LLUI::sSettingGroups["ignores"]->getBOOL("DeleteItems")); + if (ignore) + { + if (!sDisplayedAtSession) + { + LLUI::sSettingGroups["ignores"]->setBOOL("DeleteItems", TRUE); + sDisplayedAtSession = true; + } + } + } + + LLAllDescendentsPassedFilter f; + for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) + { + if (LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*it)) + { + folder->applyFunctorRecursively(f); + } + } + + // Fall through to the generic confirmation if the user choose to ignore the specialized one + if ( (!f.allDescendentsPassedFilter()) && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) ) + { + LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } + else + { + LLSD args; + args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); + LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle())); + } // Note: marketplace listings will be updated in the callback if delete confirmed return; } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 649db4032d..d454d7e00b 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -460,6 +460,8 @@ struct LLInventoryAction static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root); static void removeItemFromDND(LLFolderView* root); + static const int sConfirmOnDeleteItemsNumber; + private: static void buildMarketplaceFolders(LLFolderView* root); static void updateMarketplaceFolders(); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e5fd126d53..dc75e09ad9 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -221,7 +221,11 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { const LLInventoryObject* obj = getObject(obj_id); - + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return NULL; + } // Search up the parent chain until we get to root or an acceptable folder. // This assumes there are no cycles in the tree else we'll get a hang. LLUUID parent_id = obj->getParentUUID(); @@ -458,12 +462,8 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } // Purge the emptied folder - // Note: we'd like to use purgeObject() but it doesn't cleanly eliminate the folder - // which leads to issues further down the road when the folder is found again - //purgeObject(folder_id); - // We remove the folder and empty the trash instead which seems to work - removeCategory(folder_id); - gInventory.emptyFolderType("", LLFolderType::FT_TRASH); + removeCategory(folder_id); + remove_inventory_category(folder_id, NULL); } } @@ -799,22 +799,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } -U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(id, cats, items, LLInventoryModel::INCLUDE_TRASH); - - U32 items_found = items.size() + cats.size(); - - for (U32 i = 0; i < cats.size() && items_found <= max_item_limit; ++i) - { - items_found += getDescendentsCountRecursive(cats[i]->getUUID(), max_item_limit - items_found); - } - - return items_found; -} - void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { const LLInventoryObject *obj = getObject(object_id); @@ -3321,9 +3305,12 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT LLSD args; if(LLFolderType::FT_TRASH == preferred_type) { - static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity"); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; const LLUUID trash_id = findCategoryUUIDForType(preferred_type); - args["COUNT"] = (S32)getDescendentsCountRecursive(trash_id, trash_max_capacity); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants + S32 item_count = items.size() + cats.size(); + args["COUNT"] = item_count; } LLNotificationsUtil::add(notification, args, LLSD(), boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); @@ -3433,9 +3420,20 @@ bool callback_preview_trash_folder(const LLSD& notification, const LLSD& respons void LLInventoryModel::checkTrashOverflow() { - static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity"); + static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); + + // Collect all descendants including those in subfolders. + // + // Note: Do we really need content of subfolders? + // This was made to prevent download of trash folder timeouting + // viewer and sub-folders are supposed to download independently. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (getDescendentsCountRecursive(trash_id, trash_max_capacity) >= trash_max_capacity) + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + S32 item_count = items.size() + cats.size(); + + if (item_count >= trash_max_capacity) { if (LLFloaterPreviewTrash::isVisible()) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c558c0803b..01e0ed7e9b 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -265,9 +265,6 @@ public: // Follow parent chain to the top. bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; -private: - U32 getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit); - //-------------------------------------------------------------------- // Find //-------------------------------------------------------------------- diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 4427f32de9..26d7a7a28a 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -350,6 +350,11 @@ void LLInventoryFetchDescendentsObserver::startFetch() if (!cat) continue; if (!isCategoryComplete(cat)) { + // CHECK IT: isCategoryComplete() checks both version and descendant count but + // fetch() only works for Unknown version and doesn't care about descentants, + // as result fetch won't start and folder will potentially get stuck as + // incomplete in observer. + // Likely either both should use only version or both should check descendants. cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4b117941a0..f9c91312ee 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1217,7 +1217,18 @@ void LLInventoryPanel::purgeSelectedItems() const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList(); if (inventory_selected.empty()) return; LLSD args; - args["COUNT"] = (S32)inventory_selected.size(); + S32 count = inventory_selected.size(); + for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end(); + it != end_it; + ++it) + { + LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID(); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + count += items.size() + cats.size(); + } + args["COUNT"] = count; LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(&LLInventoryPanel::callbackPurgeSelectedItems, this, _1, _2)); } diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 5b53a05274..bf1716e18c 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -48,6 +48,7 @@ #include <boost/tokenizer.hpp> #include <boost/bind.hpp> +#include <boost/algorithm/string/replace.hpp> #include "lldispatcher.h" #include "llxfermanager.h" @@ -180,9 +181,10 @@ LLMuteList::~LLMuteList() BOOL LLMuteList::isLinden(const std::string& name) const { + std::string username = boost::replace_all_copy(name, ".", " "); typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep(" "); - tokenizer tokens(name, sep); + tokenizer tokens(username, sep); tokenizer::iterator token_iter = tokens.begin(); if (token_iter == tokens.end()) return FALSE; @@ -190,7 +192,8 @@ BOOL LLMuteList::isLinden(const std::string& name) const if (token_iter == tokens.end()) return FALSE; std::string last_name = *token_iter; - return last_name == "Linden"; + LLStringUtil::toLower(last_name); + return last_name == "linden"; } static LLVOAvatar* find_avatar(const LLUUID& id) diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 7a183cb298..52c5234137 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -322,6 +322,8 @@ public: */ static std::string getSubstitutionName(const LLNotificationPtr& notification); + static std::string getSubstitutionOriginalName(const LLNotificationPtr& notification); + /** * Adds notification panel to the IM floater. */ diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 4a3923ef6e..6a58196760 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -242,6 +242,20 @@ std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notifica } // static +std::string LLHandlerUtil::getSubstitutionOriginalName(const LLNotificationPtr& notification) +{ + if(notification->getSubstitutions().has("ORIGINAL_NAME")) + { + std::string name = notification->getSubstitutions()["ORIGINAL_NAME"]; + if(!name.empty()) + { + return name; + } + } + return LLHandlerUtil::getSubstitutionName(notification); +} + +// static void LLHandlerUtil::addNotifPanelToIM(const LLNotificationPtr& notification) { const std::string name = LLHandlerUtil::getSubstitutionName(notification); diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 63ab88da42..14d25d8158 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -131,6 +131,7 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) // we not save offer notifications to the syswell floater that should be added to the IM floater p.can_be_stored = !add_notif_to_im; p.force_show = notification->getOfferFromAgent(); + p.can_fade = notification->canFadeToast(); LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get()); if(channel) diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 7acb2f9e90..fef0631fa6 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -77,6 +77,7 @@ void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notifica p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1); + p.can_fade = notification->canFadeToast(); if(gAgent.isDoNotDisturb()) { p.force_show = notification->getName() == "SystemMessage" diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 596327e8f1..a6ef130cd0 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -86,7 +86,7 @@ bool LLTipHandler::processNotification(const LLNotificationPtr& notification) } std::string session_name = notification->getPayload()["SESSION_NAME"]; - const std::string name = notification->getSubstitutions()["NAME"]; + const std::string name = LLHandlerUtil::getSubstitutionOriginalName(notification); if (session_name.empty()) { session_name = name; diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 0e6f5b8924..05be4b5aee 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -164,6 +164,8 @@ public: virtual void setupCtrls (LLPanel* parent) {}; + virtual void onFilterChanged() { } + protected: LLUUID mGroupID; BOOL mAllowEdit; diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 8440e9ee50..66a0a1d4ad 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -494,6 +494,7 @@ void LLPanelGroupSubTab::setSearchFilter(const std::string& filter) mSearchFilter = filter; LLStringUtil::toLower(mSearchFilter); update(GC_ALL); + onFilterChanged(); } void LLPanelGroupSubTab::activate() @@ -2471,12 +2472,7 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) ////////////////////////////////////////////////////////////////////////// - LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(role_id); - U64 current_role_powers = GP_NO_POWERS; - if (rit != gdatap->mRoles.end()) - { - current_role_powers = ((*rit).second->getRoleData().mRolePowers); - } + U64 current_role_powers = gdatap->getRolePowers(role_id); if(isEnablingAbility) { @@ -2775,6 +2771,16 @@ void LLPanelGroupActionsSubTab::activate() LLPanelGroupSubTab::activate(); update(GC_ALL); + mActionDescription->clear(); + mActionList->deselectAllItems(); + mActionList->deleteAllItems(); + buildActionsList(mActionList, + GP_ALL_POWERS, + GP_ALL_POWERS, + NULL, + FALSE, + TRUE, + FALSE); } void LLPanelGroupActionsSubTab::deactivate() @@ -2803,19 +2809,31 @@ void LLPanelGroupActionsSubTab::update(LLGroupChange gc) if (mGroupID.isNull()) return; - mActionList->deselectAllItems(); mActionMembers->deleteAllItems(); mActionRoles->deleteAllItems(); - mActionDescription->clear(); + if(mActionList->hasSelectedItem()) + { + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (gdatap && gdatap->isMemberDataComplete() && gdatap->isRoleDataComplete()) + { + handleActionSelect(); + } + } +} + +void LLPanelGroupActionsSubTab::onFilterChanged() +{ + mActionDescription->clear(); + mActionList->deselectAllItems(); mActionList->deleteAllItems(); buildActionsList(mActionList, - GP_ALL_POWERS, - GP_ALL_POWERS, - NULL, - FALSE, - TRUE, - FALSE); + GP_ALL_POWERS, + GP_ALL_POWERS, + NULL, + FALSE, + TRUE, + FALSE); } void LLPanelGroupActionsSubTab::handleActionSelect() diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 9a696124a8..1d1d69e0ae 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -311,6 +311,7 @@ public: virtual bool needsApply(std::string& mesg); virtual bool apply(std::string& mesg); virtual void update(LLGroupChange gc); + virtual void onFilterChanged(); void handleActionSelect(); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 3db9500de0..dd75ae9c06 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -1287,13 +1287,13 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) { const LLUUID &trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(trash_id); - return children != LLInventoryModel::CHILDREN_NO; + return children != LLInventoryModel::CHILDREN_NO && gInventory.isCategoryComplete(trash_id); } if (command_name == "empty_lostnfound") { const LLUUID &trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(trash_id); - return children != LLInventoryModel::CHILDREN_NO; + return children != LLInventoryModel::CHILDREN_NO && gInventory.isCategoryComplete(trash_id); } return TRUE; diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 3f6bdde127..5973b08183 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1285,7 +1285,7 @@ void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type showWearablesListView(); //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE - applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type)); + applyListViewFilter(static_cast<EListViewItemType>(LVIT_SHAPE + type)); } static void update_status_widget_rect(LLView * widget, S32 right_border) @@ -1305,8 +1305,10 @@ void LLPanelOutfitEdit::onOutfitChanging(bool started) S32 delta = started ? indicator_delta : 0; S32 right_border = status_panel->getRect().getWidth() - delta; - update_status_widget_rect(mCurrentOutfitName, right_border); - update_status_widget_rect(mStatus, right_border); + if (mCurrentOutfitName) + update_status_widget_rect(mCurrentOutfitName, right_border); + if (mStatus) + update_status_widget_rect(mStatus, right_border); indicator->setVisible(started); } diff --git a/indra/newview/llpanelsnapshotlocal.cpp b/indra/newview/llpanelsnapshotlocal.cpp index 51ec964ace..77378f8092 100644 --- a/indra/newview/llpanelsnapshotlocal.cpp +++ b/indra/newview/llpanelsnapshotlocal.cpp @@ -172,6 +172,7 @@ void LLPanelSnapshotLocal::onSaveFlyoutCommit(LLUICtrl* ctrl) } else { + cancel(); floater->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "local"))); } } diff --git a/indra/newview/llplacesinventorybridge.cpp b/indra/newview/llplacesinventorybridge.cpp index 55cb7d616b..471e1c24f3 100644 --- a/indra/newview/llplacesinventorybridge.cpp +++ b/indra/newview/llplacesinventorybridge.cpp @@ -62,7 +62,7 @@ void LLPlacesLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemInTrash()) { items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) + if (!isItemRemovable() || (gInventory.getCategory(mUUID) && !gInventory.isCategoryComplete(mUUID))) { disabled_items.push_back(std::string("Purge Item")); } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 645a77e42a..12bcd89cb0 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -52,6 +52,8 @@ #include "llviewerwindow.h" #include "lllineeditor.h" +#include <boost/lexical_cast.hpp> + const S32 CLIENT_RECT_VPAD = 4; const F32 SECONDS_TO_SHOW_FILE_SAVED_MSG = 8.f; @@ -98,6 +100,29 @@ LLPreviewTexture::~LLPreviewTexture() } } +void LLPreviewTexture::populateRatioList() +{ + // Fill in ratios list with common aspect ratio values + mRatiosList.clear(); + mRatiosList.push_back(LLTrans::getString("Unconstrained")); + mRatiosList.push_back("1:1"); + mRatiosList.push_back("4:3"); + mRatiosList.push_back("10:7"); + mRatiosList.push_back("3:2"); + mRatiosList.push_back("16:10"); + mRatiosList.push_back("16:9"); + mRatiosList.push_back("2:1"); + + // Now fill combo box with provided list + LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); + combo->removeall(); + + for (std::vector<std::string>::const_iterator it = mRatiosList.begin(); it != mRatiosList.end(); ++it) + { + combo->add(*it); + } +} + // virtual BOOL LLPreviewTexture::postBuild() { @@ -138,27 +163,12 @@ BOOL LLPreviewTexture::postBuild() } } - // Fill in ratios list with common aspect ratio values - mRatiosList.clear(); - mRatiosList.push_back(LLTrans::getString("Unconstrained")); - mRatiosList.push_back("1:1"); - mRatiosList.push_back("4:3"); - mRatiosList.push_back("10:7"); - mRatiosList.push_back("3:2"); - mRatiosList.push_back("16:10"); - mRatiosList.push_back("16:9"); - mRatiosList.push_back("2:1"); - - // Now fill combo box with provided list - LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); - combo->removeall(); - - for (std::vector<std::string>::const_iterator it = mRatiosList.begin(); it != mRatiosList.end(); ++it) - { - combo->add(*it); - } + // Fill in ratios list and combo box with common aspect ratio values + populateRatioList(); childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this); + + LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); combo->setCurrentByIndex(0); return LLPreview::postBuild(); @@ -444,16 +454,25 @@ void LLPreviewTexture::updateDimensions() return; } - if (mAssetStatus != PREVIEW_ASSET_LOADED) + S32 img_width = mImage->getFullWidth(); + S32 img_height = mImage->getFullHeight(); + + if (mAssetStatus != PREVIEW_ASSET_LOADED + || mLastWidth != img_width + || mLastHeight != img_height) { mAssetStatus = PREVIEW_ASSET_LOADED; // Asset has been fully loaded, adjust aspect ratio adjustAspectRatio(); } - + + // Update the width/height display every time - getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth())); - getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight())); + getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", img_width)); + getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", img_height)); + + mLastHeight = img_height; + mLastWidth = img_width; // Reshape the floater only when required if (mUpdateDimensions) @@ -579,7 +598,12 @@ void LLPreviewTexture::adjustAspectRatio() std::vector<std::string>::const_iterator found = std::find(mRatiosList.begin(), mRatiosList.end(), ratio.str()); if (found == mRatiosList.end()) { - combo->setCurrentByIndex(0); + // No existing ratio found, create an element that will show image at original ratio + populateRatioList(); // makes sure previous custom ratio is cleared + std::string ratio = boost::lexical_cast<std::string>(num)+":" + boost::lexical_cast<std::string>(denom); + mRatiosList.push_back(ratio); + combo->add(ratio); + combo->setCurrentByIndex(mRatiosList.size()- 1); } else { @@ -587,6 +611,15 @@ void LLPreviewTexture::adjustAspectRatio() } } } + else + { + // Aspect ratio was set to unconstrained or was clamped + LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio"); + if (combo) + { + combo->setCurrentByIndex(0); //unconstrained + } + } mUpdateDimensions = TRUE; } diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index b104a91c75..c156c48d0c 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -67,6 +67,7 @@ public: /*virtual*/ void setObjectID(const LLUUID& object_id); protected: void init(); + void populateRatioList(); /* virtual */ BOOL postBuild(); bool setAspectRatio(const F32 width, const F32 height); static void onAspectRatioCommit(LLUICtrl*,void* userdata); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 58e48480c1..ee8b2d79c0 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -45,6 +45,7 @@ #include "llimagepng.h" #include "lllandmarkactions.h" #include "lllocalcliprect.h" +#include "llresmgr.h" #include "llnotificationsutil.h" #include "llslurl.h" #include "llsnapshotlivepreview.h" @@ -56,6 +57,7 @@ #include "llvfs.h" #include "llwindow.h" #include "llworld.h" +#include <boost/filesystem.hpp> const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f; @@ -1069,7 +1071,7 @@ BOOL LLSnapshotLivePreview::saveLocal() getFormattedImage(); // Save the formatted image - BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage); + BOOL success = saveLocal(mFormattedImage); if(success) { @@ -1078,3 +1080,38 @@ BOOL LLSnapshotLivePreview::saveLocal() return success; } +//Check if failed due to insufficient memory +BOOL LLSnapshotLivePreview::saveLocal(LLPointer<LLImageFormatted> mFormattedImage) +{ + BOOL insufficient_memory; + BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage, FALSE, insufficient_memory); + + if (insufficient_memory) + { + std::string lastSnapshotDir = LLViewerWindow::getLastSnapshotDir(); + +#ifdef LL_WINDOWS + boost::filesystem::path b_path(utf8str_to_utf16str(lastSnapshotDir)); +#else + boost::filesystem::path b_path(lastSnapshotDir); +#endif + boost::filesystem::space_info b_space = boost::filesystem::space(b_path); + if (b_space.free < mFormattedImage->getDataSize()) + { + LLSD args; + args["PATH"] = lastSnapshotDir; + + std::string needM_bytes_string; + LLResMgr::getInstance()->getIntegerString(needM_bytes_string, (mFormattedImage->getDataSize()) >> 10); + args["NEED_MEMORY"] = needM_bytes_string; + + std::string freeM_bytes_string; + LLResMgr::getInstance()->getIntegerString(freeM_bytes_string, (b_space.free) >> 10); + args["FREE_MEMORY"] = freeM_bytes_string; + + LLNotificationsUtil::add("SnapshotToComputerFailed", args); + return false; + } + } + return success; +} diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h index b689c50320..4ea8d25a5a 100644 --- a/indra/newview/llsnapshotlivepreview.h +++ b/indra/newview/llsnapshotlivepreview.h @@ -41,6 +41,7 @@ class LLSnapshotLivePreview : public LLView LOG_CLASS(LLSnapshotLivePreview); public: + static BOOL saveLocal(LLPointer<LLImageFormatted>); struct Params : public LLInitParam::Block<Params, LLView::Params> { Params() diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 33b6352bf5..1a480b1838 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2268,13 +2268,15 @@ void login_callback(S32 option, void *userdata) */ void show_release_notes_if_required() { - if (LLVersionInfo::getChannelAndVersion() != gLastRunVersion + static bool release_notes_shown = false; + if (!release_notes_shown && (LLVersionInfo::getChannelAndVersion() != gLastRunVersion) && LLVersionInfo::getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { LLSD info(LLAppViewer::instance()->getViewerInfo()); LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + release_notes_shown = true; } } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 49436ee406..bd68d8c999 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1450,13 +1450,20 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, // accessor that looks at permissions, copyability, and names of // inventory items to determine if a drop would be ok. -EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item) +EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item, EDragAndDropType type) { // check the basics if (!item || !obj) return ACCEPT_NO; // HACK: downcast LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item; - if (!vitem->isFinished()) return ACCEPT_NO; + if (!vitem->isFinished() && (type != DAD_CATEGORY)) + { + // Note: for DAD_CATEGORY we assume that folder version check passed and folder + // is complete, meaning that items inside are up to date. + // (isFinished() == false) at the moment shows that item was loaded from cache. + // Library or agent inventory only. + return ACCEPT_NO; + } if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links // deny attempts to drop from an object onto itself. This is to @@ -2296,7 +2303,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( (*item_iter) = item; } */ - rv = willObjectAcceptInventory(root_object, item); + rv = willObjectAcceptInventory(root_object, item, DAD_CATEGORY); if (rv < ACCEPT_YES_COPY_SINGLE) { LL_DEBUGS() << "Object will not accept " << item->getUUID() << LL_ENDL; diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 766046785b..2d99de2244 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -224,7 +224,7 @@ protected: // accessor that looks at permissions, copyability, and names of // inventory items to determine if a drop would be ok. - static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item); + static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item, EDragAndDropType type = DAD_NONE); public: // helper functions diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 5623036b91..f3e661e71a 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -478,38 +478,52 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask) } //-------------------------------------------------- + // Determine target mode + //-------------------------------------------------- + bool vertical_dragging = false; + bool spin_grabbing = false; + if ((mask == MASK_VERTICAL) + || (gGrabBtnVertical && (mask != MASK_SPIN))) + { + vertical_dragging = TRUE; + } + else if ((mask == MASK_SPIN) + || (gGrabBtnSpin && (mask != MASK_VERTICAL))) + { + spin_grabbing = TRUE; + } + + //-------------------------------------------------- // Toggle spinning //-------------------------------------------------- - if (mSpinGrabbing && !(mask == MASK_SPIN) && !gGrabBtnSpin) + if (mSpinGrabbing && !spin_grabbing) { - // user released ALT key, stop spinning + // user released or switched mask key(s), stop spinning stopSpin(); } - else if (!mSpinGrabbing && (mask == MASK_SPIN) ) + else if (!mSpinGrabbing && spin_grabbing) { - // user pressed ALT key, start spinning + // user pressed mask key(s), start spinning startSpin(); } + mSpinGrabbing = spin_grabbing; //-------------------------------------------------- // Toggle vertical dragging //-------------------------------------------------- - if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical) + if (mVerticalDragging && !vertical_dragging) { // ...switch to horizontal dragging - mVerticalDragging = FALSE; - mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, objectp); mDragStartFromCamera = mDragStartPointGlobal - gAgentCamera.getCameraPositionGlobal(); } - else if (!mVerticalDragging && (mask == MASK_VERTICAL) ) + else if (!mVerticalDragging && vertical_dragging) { // ...switch to vertical dragging - mVerticalDragging = TRUE; - mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, objectp); mDragStartFromCamera = mDragStartPointGlobal - gAgentCamera.getCameraPositionGlobal(); } + mVerticalDragging = vertical_dragging; const F32 RADIANS_PER_PIXEL_X = 0.01f; const F32 RADIANS_PER_PIXEL_Y = 0.01f; @@ -755,12 +769,13 @@ void LLToolGrabBase::handleHoverNonPhysical(S32 x, S32 y, MASK mask) //-------------------------------------------------- // Toggle vertical dragging //-------------------------------------------------- - if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical) + if (!(mask == MASK_VERTICAL) && !gGrabBtnVertical) { mVerticalDragging = FALSE; } - else if (!mVerticalDragging && (mask == MASK_VERTICAL) ) + else if ((gGrabBtnVertical && (mask != MASK_SPIN)) + || (mask == MASK_VERTICAL)) { mVerticalDragging = TRUE; } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index bf79a0595c..da6b18bb77 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1463,6 +1463,10 @@ void remove_inventory_category( LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id); if(obj) { + if (!gInventory.isCategoryComplete(cat_id)) + { + LL_WARNS() << "Removing (purging) incomplete category " << obj->getName() << LL_ENDL; + } if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) { LLNotificationsUtil::add("CannotRemoveProtectedCategories"); @@ -1540,6 +1544,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) { if (AISAPI::isAvailable()) { + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + LL_WARNS() << "Purging not fetched folder: " << cat->getName() << LL_ENDL; + } AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); AISAPI::PurgeDescendents(id, cr); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9f05ee61bd..01b0dd0077 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -3052,20 +3052,23 @@ void LLViewerMediaImpl::update() data = mMediaSource->getBitsData(); } - // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); - + if(data != NULL) { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); - placeholder_image->setSubImage( - data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), - x_pos, - y_pos, - width, - height); + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + { + LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + } } } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d46bb0199b..8d0c5af314 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -583,7 +583,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t formatted->enableOverSize() ; formatted->encode(raw, 0); formatted->disableOverSize() ; - gViewerWindow->saveImageNumbered(formatted); + LLSnapshotLivePreview::saveLocal(formatted); } return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 507087d1ae..06f868dc08 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1222,6 +1222,11 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam const LLUUID& obj_id = (*obj_iter); if(!highlight_offered_object(obj_id)) { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) + { + gInventory.checkTrashOverflow(); + } continue; } @@ -2836,6 +2841,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_INVENTORY_ACCEPTED: { args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; + args["ORIGINAL_NAME"] = original_name; LLSD payload; payload["from_id"] = from_id; // Passing the "SESSION_NAME" to use it for IM notification logging diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 6abd6f7b64..cd8dd54fa6 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1462,9 +1462,17 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) } bool size_okay = true; - - U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel; - U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel; + + S32 discard_level = mRawDiscardLevel; + if (mRawDiscardLevel < 0) + { + LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; + discard_level = 0; + } + + U32 raw_width = mRawImage->getWidth() << discard_level; + U32 raw_height = mRawImage->getHeight() << discard_level; + if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) { LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; @@ -2081,7 +2089,9 @@ bool LLViewerFetchedTexture::updateFetch() { make_request = false; } - else if(mCachedRawImage.notNull() && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) + else if(mCachedRawImage.notNull() // can be empty + && mCachedRawImageReady + && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) { make_request = false; switchToCachedImage(); //use the cached raw data first diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2d3b48bab3..a2c5fa2630 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -33,6 +33,7 @@ #include <iostream> #include <fstream> #include <algorithm> +#include <boost/filesystem.hpp> #include <boost/lambda/core.hpp> #include <boost/regex.hpp> @@ -4353,8 +4354,10 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picker) +BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picker, BOOL& insufficient_memory) { + insufficient_memory = FALSE; + if (!image) { LL_WARNS() << "No image to save" << LL_ENDL; @@ -4398,6 +4401,17 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picke LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); } +// Check if there is enough free space to save snapshot +#ifdef LL_WINDOWS + boost::filesystem::space_info b_space = boost::filesystem::space(utf8str_to_utf16str(sSnapshotDir)); +#else + boost::filesystem::space_info b_space = boost::filesystem::space(sSnapshotDir); +#endif + if (b_space.free < image->getDataSize()) + { + insufficient_memory = TRUE; + return FALSE; + } // Look for an unused file name std::string filepath; S32 i = 1; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index a134dfaaa9..38178fa910 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -352,7 +352,7 @@ public: BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } void resetSnapshotLoc() const { sSnapshotDir.clear(); } - BOOL saveImageNumbered(LLImageFormatted *image, bool force_picker = false); + BOOL saveImageNumbered(LLImageFormatted *image, BOOL force_picker, BOOL& insufficient_memory); // Reset the directory where snapshots are saved. // Client will open directory picker on next snapshot save. @@ -419,6 +419,7 @@ public: bool getSystemUIScaleFactorChanged() { return mSystemUIScaleFactorChanged; } static void showSystemUIScaleFactorChanged(); + static std::string getLastSnapshotDir() { return sSnapshotDir; } private: bool shouldShowToolTipFor(LLMouseHandler *mh); diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml index 410caa7290..05ab4d35a0 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu +<toggleable_menu height="101" layout="topleft" left="100" @@ -109,5 +109,43 @@ name="Mute Text"> <on_click function="AvatarIcon.Action" parameter="mute_unmute" /> <on_check function="AvatarIcon.Check" parameter="is_muted" /> - </menu_item_check> -</menu> + </menu_item_check> + <menu_item_separator layout="topleft" name="Moderator Options Separator"/> + <context_menu + label="Moderator Options" + layout="topleft" + name="Moderator Options"> + <menu_item_check + label="Allow text chat" + layout="topleft" + name="AllowTextChat"> + <on_check function="AvatarIcon.Check" parameter="is_allowed_text_chat" /> + <on_click function="AvatarIcon.Action" parameter="toggle_allow_text_chat" /> + <on_enable function="AvatarIcon.Enable" parameter="can_allow_text_chat" /> + </menu_item_check> + <menu_item_call + label="Mute this participant" + layout="topleft" + name="ModerateVoiceMuteSelected"> + <on_click function="AvatarIcon.Action" parameter="group_mute" /> + <on_enable function="AvatarIcon.Enable" parameter="can_mute" /> + <on_visible function="AvatarIcon.Visible" parameter="show_mute" /> + </menu_item_call> + <menu_item_call + label="Unmute this participant" + layout="topleft" + name="ModerateVoiceUnMuteSelected"> + <on_click function="AvatarIcon.Action" parameter="group_unmute" /> + <on_enable function="AvatarIcon.Enable" parameter="can_unmute" /> + <on_visible function="AvatarIcon.Visible" parameter="show_unmute" /> + </menu_item_call> + </context_menu> + <menu_item_separator layout="topleft" name="Group Ban Separator"/> + <menu_item_call + label="Ban member" + layout="topleft" + name="BanMember"> + <on_click function="AvatarIcon.Action" parameter="ban_member" /> + <on_enable function="AvatarIcon.Enable" parameter="can_ban_member" /> + </menu_item_call> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 13c2bca444..71b0edb572 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -869,7 +869,7 @@ Do you wish to proceed? icon="alertmodal.tga" name="JoinGroupNoCost" type="alertmodal"> -You are joining group [NAME]. +You are joining group <nolink>[NAME]</nolink>. Do you wish to proceed? <tag>group</tag> <tag>confirm</tag> @@ -960,7 +960,7 @@ Sorry, trial users can't join groups. icon="alertmodal.tga" name="JoinGroupMaxGroups" type="alertmodal"> -You cannot join '[group_name]': +You cannot join '<nolink>[group_name]</nolink>': You are already a member of [group_count] groups, the maximum number allowed is [max_groups] <tag>success</tag> <tag>group_id</tag> @@ -976,7 +976,7 @@ You are already a member of [group_count] groups, the maximum number allowed is icon="alertmodal.tga" name="JoinGroupClosedEnrollment" type="alertmodal"> -You cannot join '[group_name]': +You cannot join '<nolink>[group_name]</nolink>': The group no longer has open enrollment. <tag>group_id</tag> <tag>success</tag> @@ -1065,7 +1065,7 @@ Your selling price will be L$[SALE_PRICE] and will be authorized for sale to [NA icon="alertmodal.tga" name="ReturnObjectsDeededToGroup" type="alertmodal"> -Are you sure you want to return all objects shared with the group '[NAME]' on this parcel of land back to their previous owner's inventory? +Are you sure you want to return all objects shared with the group '<nolink>[NAME]</nolink>' on this parcel of land back to their previous owner's inventory? *WARNING* This will delete the non-transferable objects deeded to the group! @@ -1168,7 +1168,7 @@ Are you sure you want to disable all objects in this region? icon="alertmodal.tga" name="ReturnObjectsNotOwnedByGroup" type="alertmodal"> -Return the objects on this parcel of land that are NOT shared with the group [NAME] back to their owners? +Return the objects on this parcel of land that are NOT shared with the group <nolink>[NAME]</nolink> back to their owners? Objects: [N] <tag>confirm</tag> @@ -1956,7 +1956,7 @@ Eject [AVATAR_NAME] from your land? name="EjectAvatarFromGroup" persist="true" type="notify"> -You ejected [AVATAR_NAME] from group [GROUP_NAME] +You ejected [AVATAR_NAME] from group <nolink>[GROUP_NAME]</nolink> <tag>group</tag> </notification> @@ -3331,7 +3331,7 @@ Please select a smaller area and try again. By deeding this parcel, the group will be required to have and maintain sufficient land use credits. The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members. -Deed this [AREA] m² of land to the group '[GROUP_NAME]'? +Deed this [AREA] m² of land to the group '<nolink>[GROUP_NAME]</nolink>'? <tag>group</tag> <tag>confirm</tag> <usetemplate @@ -3348,7 +3348,7 @@ By deeding this parcel, the group will be required to have and maintain sufficie The deed will include a simultaneous land contribution to the group from '[NAME]'. The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members. -Deed this [AREA] m² of land to the group '[GROUP_NAME]'? +Deed this [AREA] m² of land to the group '<nolink>[GROUP_NAME]</nolink>'? <tag>group</tag> <tag>confirm</tag> <usetemplate @@ -4324,7 +4324,7 @@ Leave Group? icon="notify.tga" name="GroupDepart" type="notify"> -You have left the group '[group_name]'. +You have left the group '<nolink>[group_name]</nolink>'. <tag>group</tag> </notification> @@ -6010,6 +6010,22 @@ You cannot undo this action. notext="Cancel" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="DeleteFilteredItems" + type="alertmodal"> + <unique/> + Your inventory is currently filtered and not all of the items you're about to delete are currently visible. + +Are you sure you want to delete them? + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm before deleting filtered items" + name="okcancelignore" + notext="Cancel" + yestext="OK"/> + </notification> <notification icon="alertmodal.tga" @@ -7039,7 +7055,7 @@ The objects on the selected parcel of land owned by the Resident '[NAME]&ap name="GroupObjectsReturned" persist="true" type="notify"> -The objects on the selected parcel of land shared with the group [GROUPNAME] have been returned back to their owner's inventory. +The objects on the selected parcel of land shared with the group <nolink>[GROUPNAME]</nolink> have been returned back to their owner's inventory. Transferable deeded objects have been returned to their previous owners. Non-transferable objects that are deeded to the group have been deleted. <tag>group</tag> @@ -7527,6 +7543,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th name="TeleportOffered" log_to_im="true" log_to_chat="false" + fade_toast="false" type="offer" sound="UISndNewIncomingIMSession"> [NAME_SLURL] has offered to teleport you to their location: @@ -7602,6 +7619,7 @@ However, this region contains content accessible to adults only. icon="notify.tga" name="TeleportRequest" log_to_im="true" + fade_toast="false" type="offer"> [NAME_SLURL] is requesting to be teleported to your location. [MESSAGE] @@ -7958,6 +7976,7 @@ Other Key Experiences may be available. icon="notify.tga" name="ScriptQuestionExperience" persist="false" + fade_toast="false" type="notify"> '<nolink>[OBJECTNAME]</nolink>', an object owned by '[NAME]', requests your participation in the [GRID_WIDE] experience: @@ -8067,7 +8086,7 @@ To grant this permission please update your viewer to the latest version from [D show_toast="false" type="notify"> <tag>group</tag> -[GROUPNAME]'s '<nolink>[TITLE]</nolink>' +<nolink>[GROUPNAME]</nolink>'s '<nolink>[TITLE]</nolink>' [MESSAGE] <form name="form"> <button @@ -8198,7 +8217,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block icon="notify.tga" name="VoiceInviteGroup" type="notify"> -[NAME] has joined a Voice Chat call with the group [GROUP]. +[NAME] has joined a Voice Chat call with the group <nolink>[GROUP]</nolink>. Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller. <tag>group</tag> <tag>confirm</tag> @@ -8530,6 +8549,11 @@ Appearance has been saved to XML to [PATH] Failed to save appearance to XML. </notification> + <notification icon="notifytip.tga" + name="SnapshotToComputerFailed" type="notifytip"> +Failed to save snapshot to [PATH]: Disk is full. [NEED_MEMORY]KB is required but only [FREE_MEMORY]KB is free. + </notification> + <notification icon="notifytip.tga" name="PresetNotSaved" diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml index 4d20ecb9b6..8d058b0b53 100644 --- a/indra/newview/skins/default/xui/en/role_actions.xml +++ b/indra/newview/skins/default/xui/en/role_actions.xml @@ -105,6 +105,9 @@ <action description="Always allow 'Create Objects'" longdescription="Members in a Role with this Ability can create objects on a group-owned parcel, even if it's turned off in About Land > Options tab." name="land allow create" value="25" /> + <action description="Ignore landing point" + longdescription="Members in a Role with this Ability can direct teleport to a group-owned parcel, even if a landing point is set in About Land > Options tab." + name="land allow direct teleport" value="26" /> <action description="Allow 'Set Home to Here' on group land" longdescription="Members in a Role with this Ability can use World menu > Landmarks > Set Home to Here on a parcel deeded to this group." name="land allow set home" value="28" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index c9be141427..439560031e 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -150,8 +150,7 @@ support@secondlife.com.</string> <string name="LoginFailedAcountSuspended">Your account is not accessible until [TIME] Pacific Time.</string> <string name="LoginFailedAccountDisabled">We are unable to complete your request at this time. -Please contact Second Life support for assistance at http://secondlife.com/support. -If you are unable to change your password, please call (866) 476-9763.</string> +Please contact Second Life support for assistance at http://support.secondlife.com.</string> <string name="LoginFailedTransformError">Data inconsistency found during login. Please contact support@secondlife.com.</string> <string name="LoginFailedAccountMaintenance">Your account is undergoing minor maintenance. |