diff options
172 files changed, 2173 insertions, 934 deletions
@@ -508,3 +508,4 @@ d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release 3a62616f3dd8bd512fcdfd29ef033b2505b11213 3.8.2-release 60572f718879f786f6bc8b5c9373ebebf4693078 3.8.3-release 27e3cf444c4cc645884960a61325a9ee0e9a2d0f 3.8.4-release +e821ef17c6edea4a59997719d8ba416d8c16e143 3.8.5-release diff --git a/doc/contributions.txt b/doc/contributions.txt index 211d4fcf08..7493e96c39 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -185,6 +185,7 @@ Ansariel Hiller BUG-3764 STORM-1984 STORM-1979 + MAINT-5533 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ae11988df8..3a8eabac09 100755 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -2176,8 +2176,7 @@ void* ll_aligned_malloc_fallback( size_t size, int align ) SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); - unsigned int for_alloc = sysinfo.dwPageSize; - while(for_alloc < size) for_alloc += sysinfo.dwPageSize; + unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize; void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); if(NULL == p) { diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d3a9bbc4ae..0fb257aab1 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -98,7 +98,7 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library - // change preprocessro code to: #if 1 && defined(LL_WINDOWS) + // change preprocessor code to: #if 1 && defined(LL_WINDOWS) #if 0 && defined(LL_WINDOWS) void* ll_aligned_malloc_fallback( size_t size, int align ); diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index d98bc297e5..82d0dc8b4b 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -238,12 +238,12 @@ void LLUriParser::glueSecond(std::string& uri) const { uri += '?'; uri += mQuery; + } - if (mFragment.size()) - { - uri += '#'; - uri += mFragment; - } + if (mFragment.size()) + { + uri += '#'; + uri += mFragment; } } diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 8573fe0d91..a2ce2fee86 100755 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -443,6 +443,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src ) mBitfieldMask[2] = 0x000000FF; } + if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } S32 src_row_span = getWidth() * 4; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 @@ -476,6 +480,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src ) S32 src_row_span = getWidth() * 1; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } + for( S32 row = 0; row < getHeight(); row++ ) { for( S32 col = 0; col < getWidth(); col++ ) @@ -501,6 +510,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) S32 src_row_span = getWidth() * 3; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } + for( S32 row = 0; row < getHeight(); row++ ) { for( S32 col = 0; col < getWidth(); col++ ) diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 4eb8dc7440..d0ae105ba7 100755 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu // Origin is the bottom left U8* dst = raw_image->getData(); U8* src = getData() + mDataOffset; + S32 pixels = getWidth() * getHeight(); + + if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } if (getComponents() == 4) { diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 4703e6cf1a..8608e45a91 100755 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2536,6 +2536,8 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) U32 cur_influence = 0; LLVector4 wght(0,0,0,0); + U32 joints[4] = {0,0,0,0}; + LLVector4 joints_with_weights(0,0,0,0); while (joint != END_INFLUENCES && idx < weights.size()) { @@ -2543,7 +2545,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) influence |= ((U16) weights[idx++] << 8); F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); - wght.mV[cur_influence++] = (F32) joint + w; + wght.mV[cur_influence] = w; + joints[cur_influence] = joint; + cur_influence++; if (cur_influence >= 4) { @@ -2554,8 +2558,16 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) joint = weights[idx++]; } } - - face.mWeights[cur_vertex].loadua(wght.mV); + F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; + if (wsum <= 0.f) + { + wght = LLVector4(0.99999f,0.f,0.f,0.f); + } + for (U32 k=0; k<4; k++) + { + joints_with_weights[k] = (F32) joints[k] + wght[k]; + } + face.mWeights[cur_vertex].loadua(joints_with_weights.mV); cur_vertex++; } @@ -5584,7 +5596,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) { resizeVertices(num_vertices+1); - if (!partial_build) + //if (!partial_build) { resizeIndices(num_indices+3); } @@ -5592,7 +5604,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) else { resizeVertices(num_vertices); - if (!partial_build) + //if (!partial_build) { resizeIndices(num_indices); } @@ -5714,10 +5726,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) LL_CHECK_MEMORY - if (partial_build) - { - return TRUE; - } + //if (partial_build) + //{ + // return TRUE; + //} if (mTypeMask & HOLLOW_MASK) { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 625f7cff02..1da2d0c6b1 100755 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -190,8 +190,12 @@ const U8 LL_SCULPT_TYPE_MESH = 5; const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; +// for value checks, assign new value after adding new types +const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; + const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; +const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; const S32 LL_SCULPT_MESH_MAX_FACES = 8; diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 52626b0302..4bfd0de81e 100755 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -146,6 +146,8 @@ void LLPluginClassMedia::reset() mClickTarget.clear(); mClickUUID.clear(); mStatusCode = 0; + + mClickEnforceTarget = false; // media_time class mCurrentTime = 0.0f; @@ -1358,6 +1360,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path) sendMessage(message); } +void LLPluginClassMedia::setOverrideClickTarget(const std::string &target) +{ + mClickEnforceTarget = true; + mOverrideClickTarget = target; +} + void LLPluginClassMedia::crashPlugin() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 5fe8254331..96d577f43c 100755 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -249,6 +249,13 @@ public: // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE std::string getClickUUID() const { return mClickUUID; }; + // mClickTarget is received from message and governs how link will be opened + // use this to enforce your own way of opening links inside plugins + void setOverrideClickTarget(const std::string &target); + void resetOverrideClickTarget() { mClickEnforceTarget = false; }; + bool isOverrideClickTarget() const { return mClickEnforceTarget; } + std::string getOverrideClickTarget() const { return mOverrideClickTarget; }; + // These are valid during MEDIA_EVENT_DEBUG_MESSAGE std::string getDebugMessageText() const { return mDebugMessageText; }; std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; @@ -404,6 +411,8 @@ protected: std::string mClickNavType; std::string mClickTarget; std::string mClickUUID; + bool mClickEnforceTarget; + std::string mOverrideClickTarget; std::string mDebugMessageText; std::string mDebugMessageLevel; S32 mGeometryX; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 29747cb09c..9eff74f1e8 100755 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -317,9 +317,9 @@ S32 LLPrimitive::setTEMaterialID(const U8 index, const LLMaterialID& pMaterialID return mTextureList.setMaterialID(index, pMaterialID); } -S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) +S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer) { - return mTextureList.setMaterialParams(index, pMaterialParams); + return mTextureList.setMaterialParams(index, pMaterialParams, isInitFromServer); } LLMaterialPtr LLPrimitive::getTEMaterialParams(const U8 index) @@ -1869,9 +1869,12 @@ BOOL LLSculptParams::pack(LLDataPacker &dp) const BOOL LLSculptParams::unpack(LLDataPacker &dp) { - dp.unpackUUID(mSculptTexture, "texture"); - dp.unpackU8(mSculptType, "type"); - + U8 type; + LLUUID id; + dp.unpackUUID(id, "texture"); + dp.unpackU8(type, "type"); + + setSculptTexture(id, type); return TRUE; } @@ -1896,8 +1899,7 @@ bool LLSculptParams::operator==(const LLNetworkData& data) const void LLSculptParams::copy(const LLNetworkData& data) { const LLSculptParams *param = (LLSculptParams*)&data; - mSculptTexture = param->mSculptTexture; - mSculptType = param->mSculptType; + setSculptTexture(param->mSculptTexture, param->mSculptType); } @@ -1915,20 +1917,38 @@ LLSD LLSculptParams::asLLSD() const bool LLSculptParams::fromLLSD(LLSD& sd) { const char *w; - w = "texture"; + U8 type; + w = "type"; if (sd.has(w)) { - setSculptTexture( sd[w] ); - } else goto fail; - w = "type"; + type = sd[w].asInteger(); + } + else return false; + + w = "texture"; if (sd.has(w)) { - setSculptType( (U8)sd[w].asInteger() ); - } else goto fail; - + setSculptTexture(sd[w], type); + } + else return false; + return true; - fail: - return false; +} + +void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type) +{ + U8 type = sculpt_type & LL_SCULPT_TYPE_MASK; + U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK; + if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX) + { + mSculptTexture.set(SCULPT_DEFAULT_TEXTURE); + mSculptType = LL_SCULPT_TYPE_SPHERE; + } + else + { + mSculptTexture = texture_id; + mSculptType = sculpt_type; + } } //============================================================================ diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 1bf83e36b4..54870fbb10 100755 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -259,9 +259,8 @@ public: operator LLSD() const { return asLLSD(); } bool fromLLSD(LLSD& sd); - void setSculptTexture(const LLUUID& id) { mSculptTexture = id; } + void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type); LLUUID getSculptTexture() const { return mSculptTexture; } - void setSculptType(U8 type) { mSculptType = type; } U8 getSculptType() const { return mSculptType; } }; @@ -385,7 +384,7 @@ public: virtual S32 setTEMediaFlags(const U8 te, const U8 flags); virtual S32 setTEGlow(const U8 te, const F32 glow); virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); - virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams); + virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer); virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed virtual void setTESelected(const U8 te, bool sel); diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index f4f08248b8..6aae2f97c6 100755 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -368,11 +368,18 @@ S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMateri return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) +S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer) { if (index < mEntryList.size()) { - return mEntryList[index]->setMaterialParams(pMaterialParams); + if (!isInitFromServer && mEntryList[index]->isMatParamsInitFromServer()) + { + return TEM_CHANGE_NONE; + } + else + { + return mEntryList[index]->setMaterialParams(pMaterialParams); + } } return TEM_CHANGE_NONE; } diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index 49c636e40f..63e6372405 100755 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -105,7 +105,7 @@ public: S32 setMediaFlags(const U8 index, const U8 media_flags); S32 setGlow(const U8 index, const F32 glow); S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID); - S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams); + S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer); LLMaterialPtr getMaterialParams(const U8 index); diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 284dfc15f4..6020031099 100755 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -63,6 +63,7 @@ LLTextureEntry::LLTextureEntry() : mMediaEntry(NULL) , mSelected(false) , mMaterialUpdatePending(false) + , mInitMatParamsFromServer(false) { init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } @@ -71,6 +72,7 @@ LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) : mMediaEntry(NULL) , mSelected(false) , mMaterialUpdatePending(false) + , mInitMatParamsFromServer(false) { init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } @@ -79,6 +81,7 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) : mMediaEntry(NULL) , mSelected(false) , mMaterialUpdatePending(false) + , mInitMatParamsFromServer(false) { mID = rhs.mID; mScaleS = rhs.mScaleS; @@ -562,6 +565,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams) mMaterialUpdatePending = true; } mMaterial = pMaterialParams; + this->mInitMatParamsFromServer = TRUE; return TEM_CHANGE_TEXTURE; } diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index a40c3988f2..81e2e8a5a2 100755 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -160,6 +160,8 @@ public: const LLMaterialID& getMaterialID() const { return mMaterialID; }; const LLMaterialPtr getMaterialParams() const { return mMaterial; }; + bool isMatParamsInitFromServer() const { return mInitMatParamsFromServer; }; + // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL. // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData() // to NOT return NULL. @@ -217,6 +219,8 @@ protected: bool mMaterialUpdatePending; LLMaterialID mMaterialID; LLMaterialPtr mMaterial; + bool mInitMatParamsFromServer; // Flag to identification when material paramas initialized from + // Note the media data is not sent via the same message structure as the rest of the TE LLMediaEntry* mMediaEntry; // The media data for the face diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 3396213f1c..c937d190c6 100755 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -153,7 +153,7 @@ void LLDockableFloater::setVisible(BOOL visible) mDockControl.get()->repositionDockable(); } - if (visible) + if (visible && !isMinimized()) { LLFloater::setFrontmost(getAutoFocus()); } diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 81a0204bc5..3def0386e1 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -129,6 +129,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mSelectPending(FALSE), mLabelStyle( LLFontGL::NORMAL ), mHasVisibleChildren(FALSE), + mIsFolderComplete(true), mLocalIndentation(p.folder_indentation), mIndentation(0), mItemHeight(p.item_height), @@ -674,7 +675,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L // const S32 TOP_PAD = default_params.item_top_pad; - if (hasVisibleChildren()) + if (hasVisibleChildren() || !isFolderComplete()) { LLUIImage* arrow_image = default_params.folder_arrow_image; gl_draw_scaled_rotated_image( @@ -934,6 +935,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): mLastArrangeGeneration( -1 ), mLastCalculatedWidth(0) { + // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it. + mIsFolderComplete = false; } void LLFolderViewFolder::updateLabelRotation() @@ -1016,6 +1019,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) mHasVisibleChildren = found; } + if (!mIsFolderComplete) + { + mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); + } + + // calculate height as a single item (without any children), and reshapes rectangle to match LLFolderViewItem::arrange( width, height ); @@ -1463,31 +1472,37 @@ void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection) LLFolderView* root = getRoot(); - for (std::vector<LLFolderViewItem*>::iterator it = items_to_select_forward.begin(), end_it = items_to_select_forward.end(); + BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected + + // array always go from 'will be selected' to ' will be unselected', iterate + // in opposite direction to simplify identification of 'point of origin' in + // case it is in the list we are working with + for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend(); it != end_it; ++it) { LLFolderViewItem* item = *it; - if (item->isSelected()) + BOOL selected = item->isSelected(); + if (!selection_reverse && selected) { - root->removeFromSelectionList(item); + // it is our 'point of origin' where we shift/expand from + // don't deselect it + selection_reverse = TRUE; } else { - item->selectItem(); + root->changeSelection(item, !selected); } - root->addToSelectionList(item); } - if (new_selection->isSelected()) + if (selection_reverse) { - root->removeFromSelectionList(new_selection); + // at some point we reversed selection, first element should be deselected + root->changeSelection(last_selected_item_from_cur, FALSE); } - else - { - new_selection->selectItem(); - } - root->addToSelectionList(new_selection); + + // element we expand to should always be selected + root->changeSelection(new_selection, TRUE); } @@ -1677,7 +1692,9 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r mIsOpen = openitem; if(!was_open && openitem) { - getViewModelItem()->openItem(); + getViewModelItem()->openItem(); + // openItem() will request content, it won't be incomplete + mIsFolderComplete = true; } else if(was_open && !openitem) { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index ed4496cfaa..0322c8836d 100755 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -115,6 +115,7 @@ protected: F32 mControlLabelRotation; LLFolderView* mRoot; bool mHasVisibleChildren, + mIsFolderComplete, // indicates that some children were not loaded/added yet mIsCurSelection, mDragAndDropTarget, mIsMouseOverTitle, @@ -212,6 +213,9 @@ public: BOOL hasVisibleChildren() { return mHasVisibleChildren; } + // true if object can't have children + BOOL isFolderComplete() { return mIsFolderComplete; } + // Call through to the viewed object and return true if it can be // removed. Returns true if it's removed. //virtual BOOL removeRecursively(BOOL single_item); diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index d60e36183b..a395af537a 100755 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -122,6 +122,7 @@ public: virtual void filter() = 0; virtual bool contentsReady() = 0; + virtual bool isFolderComplete(class LLFolderViewFolder*) = 0; virtual void setFolderView(LLFolderView* folder_view) = 0; virtual LLFolderViewFilter& getFilter() = 0; virtual const LLFolderViewFilter& getFilter() const = 0; @@ -444,6 +445,7 @@ public: // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, // this method needs to be overloaded and return the relevant fetch status. virtual bool contentsReady() { return true; } + virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } struct ViewModelCompare { diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7cdbcb0621..848367f8a8 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -225,7 +225,6 @@ BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask) { - setHover(TRUE); getWindow()->setCursor(UI_CURSOR_ARROW); return TRUE; } @@ -236,6 +235,18 @@ BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask) return LLUICtrl::handleRightMouseDown(x,y,mask); } +void LLMenuItemGL::onMouseEnter(S32 x, S32 y, MASK mask) +{ + setHover(TRUE); + LLUICtrl::onMouseEnter(x,y,mask); +} + +void LLMenuItemGL::onMouseLeave(S32 x, S32 y, MASK mask) +{ + setHover(FALSE); + LLUICtrl::onMouseLeave(x,y,mask); +} + //virtual BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) { @@ -533,9 +544,6 @@ void LLMenuItemGL::draw( void ) gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1); } } - - // clear got hover every frame - setHover(FALSE); } BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& text ) @@ -1043,7 +1051,7 @@ void LLMenuItemBranchGL::onCommit( void ) // keyboard navigation automatically propagates highlight to sub-menu // to facilitate fast menu control via jump keys - if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem()) + if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem()) { getBranch()->highlightNextItem(NULL); } @@ -1456,7 +1464,16 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask ) { // switch to mouse control mode LLMenuGL::setKeyboardMode(FALSE); - onCommit(); + + if (getVisible() && isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + else + { + onCommit(); + } + make_ui_sound("UISndClick"); return TRUE; } @@ -1588,10 +1605,6 @@ void LLMenuItemBranchDownGL::draw( void ) gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS); } } - - // reset every frame so that we only show highlight - // when we get hover events on that frame - setHover(FALSE); } @@ -3381,6 +3394,11 @@ BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask) return LLMenuGL::handleMouseDown(x, y, mask); } +BOOL LLMenuBarGL::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + return LLMenuGL::handleMouseDown(x, y, mask); +} + void LLMenuBarGL::draw() { LLMenuItemGL* itemp = getHighlightedItem(); @@ -3625,8 +3643,24 @@ BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; if (!handled) { - // clicked off of menu, hide them all - hideMenus(); + LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu(); + LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL; + if (parent_menu && parent_menu->getVisible()) + { + // don't hide menu if parent was hit + LLRect parent_rect; + parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this); + if (!parent_rect.pointInRect(x, y)) + { + // clicked off of menu and parent, hide them all + hideMenus(); + } + } + else + { + // no visible parent, clicked off of menu, hide them all + hideMenus(); + } } return handled; } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index ae9b169691..628dedb906 100755 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -158,6 +158,10 @@ public: virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual void draw( void ); BOOL getHover() const { return mGotHover; } @@ -753,6 +757,7 @@ public: /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleJumpKey(KEY key); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ void draw(); /*virtual*/ BOOL jumpKeysActive(); diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index ea96fc573d..1fdd05a11c 100755 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llsearcheditor.h" +#include "llkeyboard.h" LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) : LLUICtrl(p), @@ -166,4 +167,16 @@ void LLSearchEditor::handleKeystroke() { mKeystrokeCallback(this, getValue()); } + + KEY key = gKeyboard->currentKey(); + if (key == KEY_LEFT || + key == KEY_RIGHT) + { + return; + } + + if (mTextChangedCallback) + { + mTextChangedCallback(this, getValue()); + } } diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index c2d7916938..3b12868225 100755 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -82,12 +82,14 @@ public: virtual void setFocus( BOOL b ); void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } + void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } protected: void onClearButtonClick(const LLSD& data); virtual void handleKeystroke(); commit_callback_t mKeystrokeCallback; + commit_callback_t mTextChangedCallback; LLLineEditor* mSearchEditor; LLButton* mSearchButton; LLButton* mClearButton; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 602a703450..bf660849c4 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -37,6 +37,7 @@ #include "lltextparser.h" #include "lltextutil.h" #include "lltooltip.h" +#include "lltrans.h" #include "lluictrl.h" #include "llurlaction.h" #include "llurlregistry.h" @@ -2060,27 +2061,33 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para // add icon before url if need LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); + if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) + { + setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); + } // output the styled Url appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); + bool tooltip_required = !match.getTooltip().empty(); + + // set the tooltip for the Url label + if (tooltip_required) + { + setLastSegmentToolTip(match.getTooltip()); + } - // show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries + // show query part of url with gray color only for LLUrlEntryHTTP url entries std::string label = match.getQuery(); if (label.size()) { link_params.color = LLColor4::grey; link_params.readonly_color = LLColor4::grey; appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); - } - - // set the tooltip for the Url label - if (! match.getTooltip().empty()) - { - segment_set_t::iterator it = getSegIterContaining(getLength()-1); - if (it != mSegments.end()) + + // set the tooltip for the query part of url + if (tooltip_required) { - LLTextSegmentPtr segment = *it; - segment->setToolTip(match.getTooltip()); + setLastSegmentToolTip(match.getTooltip()); } } @@ -2107,6 +2114,16 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } } +void LLTextBase::setLastSegmentToolTip(const std::string &tooltip) +{ + segment_set_t::iterator it = getSegIterContaining(getLength()-1); + if (it != mSegments.end()) + { + LLTextSegmentPtr segment = *it; + segment->setToolTip(tooltip); + } +} + static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text"); void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) @@ -3557,6 +3574,22 @@ S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin return 0; } +BOOL LLImageTextSegment::handleToolTip(S32 x, S32 y, MASK mask) +{ + if (!mTooltip.empty()) + { + LLToolTipMgr::instance().show(mTooltip); + return TRUE; + } + + return FALSE; +} + +void LLImageTextSegment::setToolTip(const std::string& tooltip) +{ + mTooltip = tooltip; +} + F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { if ( (start >= 0) && (end <= mEnd - mStart)) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index dfc10923f3..87809aa8fb 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -241,9 +241,15 @@ public: S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ void setToolTip(const std::string& tooltip); + private: class LLTextBase& mEditor; LLStyleConstSP mStyle; + +protected: + std::string mTooltip; }; typedef LLPointer<LLTextSegment> LLTextSegmentPtr; @@ -392,6 +398,8 @@ public: const std::string& getLabel() { return mLabel.getString(); } const LLWString& getWlabel() { return mLabel.getWString();} + void setLastSegmentToolTip(const std::string &tooltip); + /** * If label is set, draws text label (which is LLLabelTextSegment) * that is visible when no user text provided diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 72ff89f33c..18e43508df 100755 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -203,10 +203,10 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const { LLUriParser up(unescapeUrl(url)); - std::string query; + std::string label; up.extractParts(); - up.glueSecond(query); - + up.glueFirst(label); + std::string query = url.substr(label.size()); return query; } @@ -229,7 +229,7 @@ static std::string getStringAfterToken(const std::string str, const std::string LLUrlEntryHTTP::LLUrlEntryHTTP() : LLUrlEntryBase() { - mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", + mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?\\.[a-z](:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); @@ -287,46 +287,6 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const return getUrlFromWikiLink(string); } -// -// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com -// -LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol() - : LLUrlEntryBase() -{ - mPattern = boost::regex("(" - "\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR - "|" // or - "(?<!@)\\b[^[:space:]:@/>]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net - ")", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); -} - -std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb) -{ - return urlToLabelWithGreyQuery(url); -} - -std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const -{ - return urlToGreyQuery(url); -} - -std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const -{ - if (string.find("://") == std::string::npos) - { - return "http://" + escapeUrl(string); - } - return escapeUrl(string); -} - -std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const -{ - return unescapeUrl(url); -} - LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL() : LLUrlEntryBase() { @@ -489,7 +449,7 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const // LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() { - mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*", + mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*", boost::regex::perl|boost::regex::icase); mIcon = "Hand"; @@ -527,7 +487,7 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const // LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() { - mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)", + mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)", boost::regex::perl|boost::regex::icase); mIcon = "Hand"; @@ -1401,9 +1361,43 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url) return mIcon; } +// +// LLUrlEntryEmail Describes a generic mailto: Urls +// +LLUrlEntryEmail::LLUrlEntryEmail() + : LLUrlEntryBase() +{ + mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,6}", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_email.xml"; + mTooltip = LLTrans::getString("TooltipEmail"); +} + +std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + int pos = url.find("mailto:"); + + if (pos == std::string::npos) + { + return escapeUrl(url); + } + + std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8)); + return ret; +} + +std::string LLUrlEntryEmail::getUrl(const std::string &string) const +{ + if (string.find("mailto:") == std::string::npos) + { + return "mailto:" + escapeUrl(string); + } + return escapeUrl(string); +} + LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile() { - mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*", + mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/profile", boost::regex::perl|boost::regex::icase); mIcon = "Generic_Experience"; mMenuName = "menu_url_experience.xml"; diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index dd1f257a3d..413c20a657 100755 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -157,19 +157,6 @@ public: /*virtual*/ std::string getUrl(const std::string &string) const; }; -/// -/// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com -/// -class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase -{ -public: - LLUrlEntryHTTPNoProtocol(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getQuery(const std::string &url) const; - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getTooltip(const std::string &url) const; -}; - class LLUrlEntryInvalidSLURL : public LLUrlEntryBase { public: @@ -506,5 +493,16 @@ public: /*virtual*/ std::string getIcon(const std::string &url); }; +/// +/// LLUrlEntryEmail Describes a generic mailto: Urls +/// +class LLUrlEntryEmail : public LLUrlEntryBase +{ +public: + LLUrlEntryEmail(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; +}; + #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 2085505947..69eefa736c 100755 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -76,9 +76,7 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntrySL()); mUrlEntrySLLabel = new LLUrlEntrySLLabel(); registerUrl(mUrlEntrySLLabel); - // most common pattern is a URL without any protocol, - // e.g., "secondlife.com" - registerUrl(new LLUrlEntryHTTPNoProtocol()); + registerUrl(new LLUrlEntryEmail()); } LLUrlRegistry::~LLUrlRegistry() @@ -155,11 +153,9 @@ static bool stringHasUrl(const std::string &text) return (text.find("://") != std::string::npos || text.find("www.") != std::string::npos || text.find(".com") != std::string::npos || - text.find(".net") != std::string::npos || - text.find(".edu") != std::string::npos || - text.find(".org") != std::string::npos || text.find("<nolink>") != std::string::npos || - text.find("<icon") != std::string::npos); + text.find("<icon") != std::string::npos || + text.find("@") != std::string::npos); } bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) @@ -218,9 +214,40 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL // did we find a match? if so, return its details in the match object if (match_entry) { + + // Skip if link is an email with an empty username (starting with @). See MAINT-5371. + if (match_start > 0 && text.substr(match_start - 1, 1) == "@") + return false; + // fill in the LLUrlMatch object and return it std::string url = text.substr(match_start, match_end - match_start + 1); + LLUrlEntryBase *stripped_entry = NULL; + if(LLStringUtil::containsNonprintable(url)) + { + LLStringUtil::stripNonprintable(url); + + std::vector<LLUrlEntryBase *>::iterator iter; + for (iter = mUrlEntry.begin(); iter != mUrlEntry.end(); ++iter) + { + LLUrlEntryBase *url_entry = *iter; + U32 start = 0, end = 0; + if (matchRegex(url.c_str(), url_entry->getPattern(), start, end)) + { + if (mLLUrlEntryInvalidSLURL == *iter) + { + if(url_entry && url_entry->isSLURLvalid(url)) + { + continue; + } + } + stripped_entry = url_entry; + break; + } + } + } + + if (match_entry == mUrlEntryTrusted) { LLUriParser up(url); @@ -228,10 +255,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL url = up.normalizedUri(); } + std::string url_label = stripped_entry? stripped_entry->getLabel(url, cb) : match_entry->getLabel(url, cb); + std::string url_query = stripped_entry? stripped_entry->getQuery(url) : match_entry->getQuery(url); match.setValues(match_start, match_end, match_entry->getUrl(url), - match_entry->getLabel(url, cb), - match_entry->getQuery(url), + url_label, + url_query, match_entry->getTooltip(url), match_entry->getIcon(url), match_entry->getStyle(), diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index ba1cc436f9..544f50d15d 100755 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -653,79 +653,6 @@ namespace tut void object::test<11>() { // - // test LLUrlEntryHTTPNoProtocol - general URLs without a protocol - // - LLUrlEntryHTTPNoProtocol url; - - testRegex("naked .com URL", url, - "see google.com", - "http://google.com"); - - testRegex("naked .org URL", url, - "see en.wikipedia.org for details", - "http://en.wikipedia.org"); - - testRegex("naked .net URL", url, - "example.net", - "http://example.net"); - - testRegex("naked .edu URL (2 instances)", url, - "MIT web site is at web.mit.edu and also www.mit.edu", - "http://web.mit.edu"); - - testRegex("don't match e-mail addresses", url, - "test@lindenlab.com", - ""); - - testRegex(".com URL with path", url, - "see secondlife.com/status for grid status", - "http://secondlife.com/status"); - - testRegex(".com URL with port", url, - "secondlife.com:80", - "http://secondlife.com:80"); - - testRegex(".com URL with port and path", url, - "see secondlife.com:80/status", - "http://secondlife.com:80/status"); - - testRegex("www.*.com URL with port and path", url, - "see www.secondlife.com:80/status", - "http://www.secondlife.com:80/status"); - - testRegex("invalid .com URL [1]", url, - "..com", - ""); - - testRegex("invalid .com URL [2]", url, - "you.come", - ""); - - testRegex("invalid .com URL [3]", url, - "recommended", - ""); - - testRegex("invalid .edu URL", url, - "hi there scheduled maitenance has begun", - ""); - - testRegex("invalid .net URL", url, - "foo.netty", - ""); - - testRegex("XML tags around URL [1]", url, - "<foo>secondlife.com</foo>", - "http://secondlife.com"); - - testRegex("XML tags around URL [2]", url, - "<foo>secondlife.com/status?bar=1</foo>", - "http://secondlife.com/status?bar=1"); - } - - template<> template<> - void object::test<12>() - { - // // test LLUrlEntryNoLink - turn off hyperlinking // LLUrlEntryNoLink url; @@ -752,7 +679,7 @@ namespace tut } template<> template<> - void object::test<13>() + void object::test<12>() { // // test LLUrlEntryRegion - secondlife:///app/region/<location> URLs @@ -860,4 +787,101 @@ namespace tut "secondlife:///app/region/Product%20Engine", "Product Engine"); } + + template<> template<> + void object::test<13>() + { + // + // test LLUrlEntryemail - general emails + // + LLUrlEntryEmail url; + + // Regex tests. + testRegex("match e-mail addresses", url, + "test@lindenlab.com", + "mailto:test@lindenlab.com"); + + testRegex("match e-mail addresses with mailto: prefix", url, + "mailto:test@lindenlab.com", + "mailto:test@lindenlab.com"); + + testRegex("match e-mail addresses with different domains", url, + "test@foo.org.us", + "mailto:test@foo.org.us"); + + testRegex("match e-mail addresses with different domains", url, + "test@foo.bar", + "mailto:test@foo.bar"); + + testRegex("don't match incorrect e-mail addresses", url, + "test @foo.com", + ""); + + testRegex("don't match incorrect e-mail addresses", url, + "test@ foo.com", + ""); + } + + template<> template<> + void object::test<14>() + { + // + // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls + // + LLUrlEntrySecondlifeURL url; + + testRegex("match urls with protocol", url, + "this url should match http://lindenlab.com/products/second-life", + "http://lindenlab.com/products/second-life"); + + testRegex("match urls with protocol", url, + "search something https://marketplace.secondlife.com/products/search on marketplace and test the https", + "https://marketplace.secondlife.com/products/search"); + + testRegex("match urls with port", url, + "let's specify some port http://secondlife.com:888/status", + "http://secondlife.com:888/status"); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something www.marketplace.secondlife.com/products but no https prefix", + ""); + + testRegex("but with a protocol www is fine", url, + "so let's add a protocol http://www.marketplace.secondlife.com:8888/products", + "http://www.marketplace.secondlife.com:8888/products"); + + testRegex("don't match urls w/o protocol", url, + "and even no www something secondlife.com/status", + ""); + } + + template<> template<> + void object::test<15>() + { + // + // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls + // + + LLUrlEntrySimpleSecondlifeURL url; + + testRegex("match urls with a protocol", url, + "this url should match http://lindenlab.com", + "http://lindenlab.com"); + + testRegex("match urls with a protocol", url, + "search something https://marketplace.secondlife.com on marketplace and test the https", + "https://marketplace.secondlife.com"); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something www.marketplace.secondlife.com but no https prefix", + ""); + + testRegex("but with a protocol www is fine", url, + "so let's add a protocol http://www.marketplace.secondlife.com", + "http://www.marketplace.secondlife.com"); + + testRegex("don't match urls w/o protocol", url, + "and even no www something lindenlab.com", + ""); + } } diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 5720660034..1b24250618 100755 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -49,8 +49,8 @@ LLSplashScreen *gSplashScreenp = NULL; BOOL gDebugClicks = FALSE; BOOL gDebugWindowProc = FALSE; -const S32 gURLProtocolWhitelistCount = 4; -const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:" }; +const S32 gURLProtocolWhitelistCount = 5; +const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" }; // CP: added a handler list - this is what's used to open the protocol and is based on registry entry // only meaningful difference currently is that file: protocols are opened using http: diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index f02052ca6a..e6e8f27f53 100755 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -53,6 +53,7 @@ bool runMainLoop(); void initMainLoop(); void cleanupViewer(); void handleUrl(const char* url); +void dispatchUrl(std::string url); /* Defined in llwindowmacosx-objc.mm: */ int createNSApp(int argc, const char **argv); diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 0cbfaed0d9..2e14a9557d 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -3.8.5 +3.8.6 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 81da856d7e..2ca090b179 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14222,7 +14222,7 @@ <key>MaxFPS</key> <map> <key>Comment</key> - <string>Yield some time to the local host if we reach a threshold framerate.</string> + <string>OBSOLETE UNUSED setting.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl index 6cd38d8ef5..3060307b21 100755 --- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl @@ -37,8 +37,7 @@ mat4 getObjectSkinnedTransform() index = min(index, vec4(51.0)); index = max(index, vec4( 0.0)); - float scale = 1.0/(w.x+w.y+w.z+w.w); - w *= scale; + w *= 1.0/(w.x+w.y+w.z+w.w); int i1 = int(index.x); int i2 = int(index.y); diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index 595c11fae2..58fb01d200 100755 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -29,6 +29,7 @@ out vec4 frag_data[3]; #define frag_data gl_FragData #endif +uniform float minimum_alpha; uniform sampler2D diffuseMap; uniform sampler2D bumpMap; @@ -47,16 +48,23 @@ vec2 encode_normal(vec3 n) void main() { - vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb; - vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0; + vec4 col = texture2D(diffuseMap, vary_texcoord0.xy); + + if(col.a < minimum_alpha) + { + discard; + } + col *= vertex_color; + + vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0; - vec3 tnorm = vec3(dot(norm,vary_mat0), + vec3 tnorm = vec3(dot(norm,vary_mat0), dot(norm,vary_mat1), dot(norm,vary_mat2)); - frag_data[0] = vec4(col, 0.0); - frag_data[1] = vertex_color.aaaa; // spec - //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested - vec3 nvn = normalize(tnorm); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); + frag_data[0] = vec4(col.rgb, 0.0); + frag_data[1] = vertex_color.aaaa; // spec + //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested + vec3 nvn = normalize(tnorm); + frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0); } diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 95cdf90e99..b8677fd9e4 100755 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -165,7 +165,9 @@ lbl_configure_default_lang: StrCpy $LANGUAGE $0
# For silent installs, no language prompt, use default
- IfSilent lbl_return
+ IfSilent 0 +3
+ StrCpy $SKIP_AUTORUN "true"
+ Goto lbl_return
StrCmp $SKIP_DIALOGS "true" lbl_return
lbl_build_menu:
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3316f1e654..e33d34ebc7 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2829,7 +2829,7 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */ // This implementation should mirror LLAgentInfo::hasPowerInGroup BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const { - if (isGodlike()) + if (isGodlikeWithoutAdminMenuFakery()) return true; // GP_NO_POWERS can also mean no power is enough to grant an ability. diff --git a/indra/newview/llagentdata.cpp b/indra/newview/llagentdata.cpp index 5f6a082d75..d2c644a06f 100755 --- a/indra/newview/llagentdata.cpp +++ b/indra/newview/llagentdata.cpp @@ -31,3 +31,4 @@ LLUUID gAgentID; LLUUID gAgentSessionID; +std::string gAgentUsername; diff --git a/indra/newview/llagentdata.h b/indra/newview/llagentdata.h index 83d6a53d5e..efdd97f6c4 100755 --- a/indra/newview/llagentdata.h +++ b/indra/newview/llagentdata.h @@ -30,5 +30,6 @@ extern LLUUID gAgentID; extern LLUUID gAgentSessionID; +extern std::string gAgentUsername; #endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 025009d40b..d080dfb66e 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1887,6 +1887,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) { ++n_clothes; } + else if (item->getType() == LLAssetType::AT_BODYPART) + { + return isAgentAvatarValid(); + } else { LL_WARNS() << "Unexpected wearable type" << LL_ENDL; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 44c9f893b8..68e67a8ac3 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2747,10 +2747,12 @@ bool LLAppViewer::initConfiguration() // gWindowTitle = LLTrans::getString("APP_NAME"); #if LL_DEBUG - gWindowTitle += std::string(" [DEBUG] ") + gArgs; -#else - gWindowTitle += std::string(" ") + gArgs; + gWindowTitle += std::string(" [DEBUG]") #endif + if (!gArgs.empty()) + { + gWindowTitle += std::string(" ") + gArgs; + } LLStringUtil::truncate(gWindowTitle, 255); //RN: if we received a URL, hand it off to the existing instance. @@ -4885,6 +4887,7 @@ void LLAppViewer::idle() gIdleCallbacks.callFunctions(); gInventory.idleNotifyObservers(); + LLAvatarTracker::instance().idleNotifyObservers(); } // Metrics logging (LLViewerAssetStats, etc.) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 56154a2de3..09227806fd 100755 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -62,9 +62,10 @@ namespace // They are not used immediately by the app. int gArgC; char** gArgV; - LLAppViewerMacOSX* gViewerAppPtr; + LLAppViewerMacOSX* gViewerAppPtr = NULL; void (*gOldTerminateHandler)() = NULL; + std::string gHandleSLURL; } static void exceptionTerminateHandler() @@ -107,7 +108,11 @@ bool initViewer() { LL_WARNS() << "Application init failed." << LL_ENDL; } - + else if (!gHandleSLURL.empty()) + { + dispatchUrl(gHandleSLURL); + gHandleSLURL = ""; + } return ok; } @@ -393,22 +398,31 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute() void handleUrl(const char* url_utf8) { - if (url_utf8) + if (url_utf8 && gViewerAppPtr) { - std::string url = url_utf8; - // Safari 3.2 silently mangles secondlife:///app/ URLs into - // secondlife:/app/ (only one leading slash). - // Fix them up to meet the URL specification. JC - const std::string prefix = "secondlife:/app/"; - std::string test_prefix = url.substr(0, prefix.length()); - LLStringUtil::toLower(test_prefix); - if (test_prefix == prefix) - { - url.replace(0, prefix.length(), "secondlife:///app/"); - } - - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - LLURLDispatcher::dispatch(url, "", web, trusted_browser); + gHandleSLURL = ""; + dispatchUrl(url_utf8); } + else if (url_utf8) + { + gHandleSLURL = url_utf8; + } +} + +void dispatchUrl(std::string url) +{ + // Safari 3.2 silently mangles secondlife:///app/ URLs into + // secondlife:/app/ (only one leading slash). + // Fix them up to meet the URL specification. JC + const std::string prefix = "secondlife:/app/"; + std::string test_prefix = url.substr(0, prefix.length()); + LLStringUtil::toLower(test_prefix); + if (test_prefix == prefix) + { + url.replace(0, prefix.length(), "secondlife:///app/"); + } + + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + LLURLDispatcher::dispatch(url, "", web, trusted_browser); } diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index b6c5496c17..f79d1aa609 100755 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -97,7 +97,8 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id, LLAvatarTracker::LLAvatarTracker() : mTrackingData(NULL), mTrackedAgentValid(false), - mModifyMask(0x0) + mModifyMask(0x0), + mIsNotifyObservers(FALSE) { } @@ -272,7 +273,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds) << "]" << LL_ENDL; } } - notifyObservers(); + // do not notify observers here - list can be large so let it be done on idle. return new_buddy_count; } @@ -473,8 +474,25 @@ void LLAvatarTracker::removeObserver(LLFriendObserver* observer) mObservers.end()); } +void LLAvatarTracker::idleNotifyObservers() +{ + if (mModifyMask == LLFriendObserver::NONE && mChangedBuddyIDs.size() == 0) + { + return; + } + notifyObservers(); +} + void LLAvatarTracker::notifyObservers() { + if (mIsNotifyObservers) + { + // Don't allow multiple calls. + // new masks and ids will be processed later from idle. + return; + } + mIsNotifyObservers = TRUE; + observer_list_t observers(mObservers); observer_list_t::iterator it = observers.begin(); observer_list_t::iterator end = observers.end(); @@ -490,6 +508,7 @@ void LLAvatarTracker::notifyObservers() mModifyMask = LLFriendObserver::NONE; mChangedBuddyIDs.clear(); + mIsNotifyObservers = FALSE; } void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer) @@ -531,7 +550,7 @@ void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id) // store flag for change // and id of object change applies to void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent) -{ +{ mModifyMask |= mask; if (referent.notNull()) { diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 6e5fc01cd8..1f819a42fd 100755 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -143,6 +143,7 @@ public: // observers left behind. void addObserver(LLFriendObserver* observer); void removeObserver(LLFriendObserver* observer); + void idleNotifyObservers(); void notifyObservers(); // Observers interested in updates of a particular avatar. @@ -209,6 +210,8 @@ private: LLAvatarTracker(const LLAvatarTracker&); bool operator==(const LLAvatarTracker&); + BOOL mIsNotifyObservers; + public: // don't you dare create or delete this object LLAvatarTracker(); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index b81b95462e..dc0835eb1c 100755 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -376,6 +376,10 @@ public: || mSourceType == CHAT_SOURCE_SYSTEM) { mFrom = LLTrans::getString("SECOND_LIFE"); + if(!chat.mFromName.empty() && (mFrom != chat.mFromName)) + { + mFrom += " (" + chat.mFromName + ")"; + } user_name->setValue(mFrom); updateMinUserNameWidth(); } diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index b38d472156..62f08144b9 100755 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -153,6 +153,7 @@ public: * file name is conversation.log */ std::string getFileName(); + LLConversation* findConversation(const LLIMModel::LLIMSession* session); private: @@ -184,7 +185,7 @@ private: void updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name); void updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages); - LLConversation* findConversation(const LLIMModel::LLIMSession* session); + typedef std::vector<LLConversation> conversations_vec_t; std::vector<LLConversation> mConversations; diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 6e32ce60ec..328a638f2f 100755 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -136,7 +136,24 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32 items.push_back(std::string("im")); items.push_back(std::string("offer_teleport")); items.push_back(std::string("request_teleport")); - items.push_back(std::string("voice_call")); + + if (getType() != CONV_SESSION_1_ON_1) + { + items.push_back(std::string("voice_call")); + } + else + { + LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL; + if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel()) + { + items.push_back(std::string("voice_call")); + } + else + { + items.push_back(std::string("disconnect_from_voice")); + } + } + items.push_back(std::string("chat_history")); items.push_back(std::string("separator_chat_history")); items.push_back(std::string("add_friend")); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index f828b56f7f..8bbc529244 100755 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1553,7 +1553,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* (drawable && drawable->isState(LLDrawable::REBUILD_ALL))) { if (drawable && drawable->isState(LLDrawable::REBUILD_ALL)) - { //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues + { + //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues for (S32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* facep = drawable->getFace(i); @@ -1570,13 +1571,15 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* buffer = face->getVertexBuffer(); } else - { //just rebuild this face + { + //just rebuild this face getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face); } } if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) - { //perform software vertex skinning for this face + { + //perform software vertex skinning for this face LLStrider<LLVector3> position; LLStrider<LLVector3> normal; @@ -1604,10 +1607,6 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* { joint = avatar->getJoint("mPelvis"); } - if (!joint) - { - LL_DEBUGS("Avatar") << "Failed to find " << skin->mJointNames[j] << LL_ENDL; - } if (joint) { mat[j] = skin->mInvBindMatrix[j]; @@ -1632,12 +1631,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* { F32 w = weight[j][k]; - idx[k] = llclamp((S32) floorf(w), 0, JOINT_COUNT-1); + idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)JOINT_COUNT-1); wght[k] = w - floorf(w); scale += wght[k]; } - + // This is enforced in unpackVolumeFaces() + llassert(scale>0.f); wght *= 1.f/scale; for (U32 k = 0; k < 4; k++) @@ -1737,6 +1737,10 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) for (U32 i = 0; i < count; ++i) { LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); + if (!joint) + { + joint = avatar->getJoint("mPelvis"); + } if (joint) { mat[i] = skin->mInvBindMatrix[i]; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 33f7bc305c..7b9fd5c6c6 100755 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -864,6 +864,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { LLDrawInfo& params = **i; + gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff); LLDrawPoolBump::bindBumpMap(params, bump_channel); pushBatch(params, mask, TRUE); } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index f2b369a9ad..8f3eaaa207 100755 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -380,9 +380,11 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) mShowDragMarker(FALSE), mLandingTab(NULL), mLastTab(NULL), - mTabsHighlightEnabled(TRUE) - , mUpdateDropDownItems(true) -, mRestoreOverflowMenu(false) + mTabsHighlightEnabled(TRUE), + mUpdateDropDownItems(true), + mRestoreOverflowMenu(false), + mGetPrevItems(true), + mItemsChangedTimer() { // Register callback for menus with current registrar (will be parent panel's registrar) LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", @@ -659,6 +661,15 @@ void LLFavoritesBarCtrl::changed(U32 mask) LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID()); } updateButtons(); + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + else + { + mItemsChangedTimer.reset(); + } + } } @@ -693,6 +704,21 @@ void LLFavoritesBarCtrl::draw() // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) mShowDragMarker = FALSE; } + if (mItemsChangedTimer.getStarted()) + { + if (mItemsChangedTimer.getElapsedTimeF32() > 1.f) + { + LLFavoritesOrderStorage::instance().saveFavoritesRecord(); + mItemsChangedTimer.stop(); + } + } + + if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired) + { + LLFavoritesOrderStorage::instance().mUpdateRequired = false; + mItemsChangedTimer.start(); + } + } const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() @@ -723,6 +749,12 @@ void LLFavoritesBarCtrl::updateButtons() return; } + if(mGetPrevItems) + { + LLFavoritesOrderStorage::instance().mPrevFavorites = mItems; + mGetPrevItems = false; + } + const LLButton::Params& button_params = getButtonParams(); if(mItems.empty()) @@ -844,6 +876,7 @@ void LLFavoritesBarCtrl::updateButtons() { mUpdateDropDownItems = false; } + } LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset) @@ -912,9 +945,11 @@ BOOL LLFavoritesBarCtrl::postBuild() BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) { + if (mFavoriteFolderId.isNull()) return FALSE; + LLInventoryModel::cat_array_t cats; LLIsType is_type(LLAssetType::AT_LANDMARK); @@ -1411,6 +1446,7 @@ void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; const S32 LLFavoritesOrderStorage::NO_INDEX = -1; +bool LLFavoritesOrderStorage::mSaveOnExit = false; void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index) { @@ -1447,6 +1483,7 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL; onLandmarkLoaded(asset_id, lm); } + return; } // static @@ -1482,13 +1519,16 @@ void LLFavoritesOrderStorage::destroyClass() LLFile::remove(old_filename); } - if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) - { - LLFavoritesOrderStorage::instance().saveFavoritesSLURLs(); - } - else + std::string filename = getSavedOrderFileName(); + file.open(filename.c_str()); + if (file.is_open()) { - LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser(); + file.close(); + LLFile::remove(filename); + if(mSaveOnExit) + { + LLFavoritesOrderStorage::instance().saveFavoritesRecord(true); + } } } @@ -1503,108 +1543,57 @@ std::string LLFavoritesOrderStorage::getSavedOrderFileName() void LLFavoritesOrderStorage::load() { - // load per-resident sorting information std::string filename = getSavedOrderFileName(); - LLSD settings_llsd; llifstream file; file.open(filename.c_str()); if (file.is_open()) { LLSDSerialize::fromXML(settings_llsd, file); - LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " - << (settings_llsd.isMap() ? "" : "un") << "successfully" - << LL_ENDL; - file.close(); - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL; - } - - for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); - iter != settings_llsd.endMap(); ++iter) - { - mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); + LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " + << (settings_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + file.close(); + mSaveOnExit = true; + + for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); + iter != settings_llsd.endMap(); ++iter) + { + mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); + } } -} - -void LLFavoritesOrderStorage::saveFavoritesSLURLs() -{ - // Do not change the file if we are not logged in yet. - if (!LLLoginInstance::getInstance()->authSuccess()) + else { - LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL; - return; + filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + LLSD fav_llsd; + LLSD user_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " + << (fav_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + in_file.close(); + user_llsd = fav_llsd[gAgentUsername]; + + S32 index = 0; + for (LLSD::array_iterator iter = user_llsd.beginArray(); + iter != user_llsd.endArray(); ++iter) + { + mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); + index++; + } + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; + } + } } - - std::string filename = getStoredFavoritesFilename(); - if (!filename.empty()) - { - llifstream in_file; - in_file.open(filename.c_str()); - LLSD fav_llsd; - if (in_file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, in_file); - LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " - << (fav_llsd.isMap() ? "" : "un") << "successfully" - << LL_ENDL; - in_file.close(); - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; - } - - const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - - LLSD user_llsd; - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) - { - LLSD value; - value["name"] = (*it)->getName(); - value["asset_id"] = (*it)->getAssetUUID(); - - slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); - if (slurl_iter != mSLURLs.end()) - { - LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) << ", SLURL=" << slurl_iter->second << ", value=" << value << LL_ENDL; - value["slurl"] = slurl_iter->second; - user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value; - } - else - { - LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL; - } - } - - LLAvatarName av_name; - LLAvatarNameCache::get( gAgentID, &av_name ); - // Note : use the "John Doe" and not the "john.doe" version of the name - // as we'll compare it with the stored credentials in the login panel. - fav_llsd[av_name.getUserName()] = user_llsd; - - llofstream file; - file.open(filename.c_str()); - if ( file.is_open() ) - { - LLSDSerialize::toPrettyXML(fav_llsd, file); - LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName() - << "' to '" << filename << "' " - << LL_ENDL; - file.close(); - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() - << "' at '" << filename << "' " - << LL_ENDL; - } - } } void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() @@ -1626,8 +1615,30 @@ void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() // See saveFavoritesSLURLs() here above for the reason why. if (fav_llsd.has(av_name.getUserName())) { - LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; - fav_llsd.erase(av_name.getUserName()); + LLSD user_llsd = fav_llsd[av_name.getUserName()]; + + if (user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"]= iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[av_name.getUserName()] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; + fav_llsd.erase(av_name.getUserName()); + } } llofstream out_file; @@ -1648,20 +1659,20 @@ void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmar if (landmark) { LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL; - LLVector3d pos_global; - if (!landmark->getGlobalPos(pos_global)) - { - // If global position was unknown on first getGlobalPos() call - // it should be set for the subsequent calls. - landmark->getGlobalPos(pos_global); - } + LLVector3d pos_global; + if (!landmark->getGlobalPos(pos_global)) + { + // If global position was unknown on first getGlobalPos() call + // it should be set for the subsequent calls. + landmark->getGlobalPos(pos_global); + } - if (!pos_global.isExactlyZero()) - { - LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; - LLLandmarkActions::getSLURLfromPosGlobal(pos_global, + if (!pos_global.isExactlyZero()) + { + LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; + LLLandmarkActions::getSLURLfromPosGlobal(pos_global, boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); - } + } } } @@ -1671,41 +1682,6 @@ void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::st mSLURLs[asset_id] = slurl; } -void LLFavoritesOrderStorage::save() -{ - if (mIsDirty) - { - // something changed, so save it - std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName(); - if (!filename.empty()) - { - LLSD settings_llsd; - - for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) - { - settings_llsd[iter->first.asString()] = iter->second; - } - - llofstream file; - file.open(filename.c_str()); - if ( file.is_open() ) - { - LLSDSerialize::toPrettyXML(settings_llsd, file); - LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL; - } - else - { - LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL; - } - } - else - { - LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL; - } - } -} - - void LLFavoritesOrderStorage::cleanup() { // nothing to clean @@ -1720,7 +1696,7 @@ void LLFavoritesOrderStorage::cleanup() sort_index_map_t aTempMap; //copy unremoved values from mSortIndexes to aTempMap - std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), + std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), inserter(aTempMap, aTempMap.begin()), is_not_in_fav); @@ -1752,8 +1728,8 @@ void LLFavoritesOrderStorage::saveOrder() void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items ) { - int sortField = 0; + int sortField = 0; // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) { @@ -1793,6 +1769,110 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it saveItemsOrder(items); } +BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) +{ + + LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if (favorite_folder.isNull()) + return FALSE; + + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + std::sort(items.begin(), items.end(), LLFavoritesSort()); + + if((items != mPrevFavorites) || pref_changed) + { + std::string filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + LLSD fav_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + in_file.close(); + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; + } + + LLSD user_llsd; + S32 fav_iter = 0; + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) + { + LLSD value; + if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) + { + value["name"] = (*it)->getName(); + value["asset_id"] = (*it)->getAssetUUID(); + value["id"] = (*it)->getUUID(); + slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); + if (slurl_iter != mSLURLs.end()) + { + value["slurl"] = slurl_iter->second; + user_llsd[fav_iter] = value; + } + else + { + getSLURL((*it)->getAssetUUID()); + mUpdateRequired = true; + return FALSE; + } + } + else + { + value["id"] = (*it)->getUUID(); + user_llsd[fav_iter] = value; + } + + fav_iter ++; + } + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + // Note : use the "John Doe" and not the "john.doe" version of the name + // as we'll compare it with the stored credentials in the login panel. + fav_llsd[av_name.getUserName()] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + mSaveOnExit = false; + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() + << "' at '" << filename << "' " << LL_ENDL; + } + } + + mPrevFavorites = items; + } + + return TRUE; + +} + +void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show) +{ + if (show) + { + saveFavoritesRecord(true); + } + else + { + removeFavoritesRecordOfUser(); + } +} + void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) { if (mTargetLandmarkId.isNull()) return; diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index a370724947..66fc8b2ae7 100755 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -105,8 +105,10 @@ protected: bool mUpdateDropDownItems; bool mRestoreOverflowMenu; - LLUUID mSelectedItemID; + bool mGetPrevItems; + LLUUID mSelectedItemID; + LLFrameTimer mItemsChangedTimer; LLUIImage* mImageDragIndication; private: @@ -204,12 +206,23 @@ public: * @see cleanup() */ static void destroyClass(); + static std::string getStoredFavoritesFilename(); + static std::string getSavedOrderFileName(); + + BOOL saveFavoritesRecord(bool pref_changed = false); + void showFavoritesOnLoginChanged(BOOL show); + + LLInventoryModel::item_array_t mPrevFavorites; + const static S32 NO_INDEX; + static bool mSaveOnExit; + bool mUpdateRequired; + private: friend class LLSingleton<LLFavoritesOrderStorage>; - LLFavoritesOrderStorage() : mIsDirty(false) { load(); } - ~LLFavoritesOrderStorage() { save(); } + LLFavoritesOrderStorage() : mIsDirty(false), mUpdateRequired(false){ load(); } + ~LLFavoritesOrderStorage() {} /** * Removes sort indexes for items which are not in Favorites bar for now. @@ -217,13 +230,8 @@ private: void cleanup(); const static std::string SORTING_DATA_FILE_NAME; - std::string getSavedOrderFileName(); - static std::string getStoredFavoritesFilename(); - - void load(); - void save(); - void saveFavoritesSLURLs(); + void load(); // Remove record of current user's favorites from file on disk. void removeFavoritesRecordOfUser(); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 7bd01f6beb..bababca652 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -34,10 +34,12 @@ // Viewer includes #include "llagent.h" #include "llagentui.h" -#include "llappviewer.h" +#include "llappviewer.h" +#include "llnotificationsutil.h" #include "llslurl.h" #include "llvoiceclient.h" #include "lluictrlfactory.h" +#include "llupdaterservice.h" #include "llviewertexteditor.h" #include "llviewercontrol.h" #include "llviewerstats.h" @@ -87,10 +89,24 @@ public: /// separated so that we can programmatically access the same info. static LLSD getInfo(); void onClickCopyToClipboard(); + void onClickUpdateCheck(); + + // checks state of updater service and starts a check outside of schedule. + // subscribes callback for closest state update + static void setUpdateListener(); private: void setSupportText(const std::string& server_release_notes_url); + // notifications for user requested checks + static void showCheckUpdateNotification(S32 state); + + // callback method for manual checks + static bool callbackCheckUpdate(LLSD const & event); + + // listener name for update checks + static const std::string sCheckUpdateListenerName; + static void startFetchServerReleaseNotes(); static void handleServerReleaseNotes(LLSD results); }; @@ -123,6 +139,9 @@ BOOL LLFloaterAbout::postBuild() getChild<LLUICtrl>("copy_btn")->setCommitCallback( boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this)); + getChild<LLUICtrl>("update_btn")->setCommitCallback( + boost::bind(&LLFloaterAbout::onClickUpdateCheck, this)); + static const LLUIColor about_color = LLUIColorTable::instance().getColor("TextFgReadOnlyColor"); if (gAgent.getRegion()) @@ -270,6 +289,11 @@ void LLFloaterAbout::onClickCopyToClipboard() support_widget->deselect(); } +void LLFloaterAbout::onClickUpdateCheck() +{ + setUpdateListener(); +} + void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url) { #if LL_WINDOWS @@ -291,6 +315,68 @@ void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url) } ///---------------------------------------------------------------------------- +/// Floater About Update-check related functions +///---------------------------------------------------------------------------- + +const std::string LLFloaterAbout::sCheckUpdateListenerName = "LLUpdateNotificationListener"; + +void LLFloaterAbout::showCheckUpdateNotification(S32 state) +{ + switch (state) + { + case LLUpdaterService::UP_TO_DATE: + LLNotificationsUtil::add("UpdateViewerUpToDate"); + break; + case LLUpdaterService::DOWNLOADING: + case LLUpdaterService::INSTALLING: + LLNotificationsUtil::add("UpdateDownloadInProgress"); + break; + case LLUpdaterService::TERMINAL: + // download complete, user triggered check after download pop-up appeared + LLNotificationsUtil::add("UpdateDownloadComplete"); + break; + default: + LLNotificationsUtil::add("UpdateCheckError"); + break; + } +} + +bool LLFloaterAbout::callbackCheckUpdate(LLSD const & event) +{ + if (!event.has("payload")) + { + return false; + } + + LLSD payload = event["payload"]; + if (payload.has("type") && payload["type"].asInteger() == LLUpdaterService::STATE_CHANGE) + { + LLEventPumps::instance().obtain("mainlooprepeater").stopListening(sCheckUpdateListenerName); + showCheckUpdateNotification(payload["state"].asInteger()); + } + return false; +} + +void LLFloaterAbout::setUpdateListener() +{ + LLUpdaterService update_service; + S32 service_state = update_service.getState(); + // Note: Do not set state listener before forceCheck() since it set's new state + if (update_service.forceCheck() || service_state == LLUpdaterService::CHECKING_FOR_UPDATE) + { + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainlooprepeater")); + if (mainloop.getListener(sCheckUpdateListenerName) == LLBoundListener()) // dummy listener + { + mainloop.listen(sCheckUpdateListenerName, boost::bind(&callbackCheckUpdate, _1)); + } + } + else + { + showCheckUpdateNotification(service_state); + } +} + +///---------------------------------------------------------------------------- /// LLFloaterAboutUtil ///---------------------------------------------------------------------------- void LLFloaterAboutUtil::registerFloater() @@ -300,3 +386,8 @@ void LLFloaterAboutUtil::registerFloater() } +void LLFloaterAboutUtil::checkUpdatesAndNotify() +{ + LLFloaterAbout::setUpdateListener(); +} + diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h index 8fc1aa4f29..be34b631cc 100755 --- a/indra/newview/llfloaterabout.h +++ b/indra/newview/llfloaterabout.h @@ -30,6 +30,9 @@ namespace LLFloaterAboutUtil { void registerFloater(); + + // Support for user initialized update/state checks + void checkUpdatesAndNotify(); } #endif // LL_LLFLOATERABOUT_H diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 34904cf7ed..957c91b226 100755 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -32,6 +32,7 @@ #include "llavataractions.h" #include "llfloaterbump.h" +#include "llfloaterreg.h" #include "llfloaterreporter.h" #include "llmutelist.h" #include "llpanelblockedlist.h" @@ -87,11 +88,11 @@ BOOL LLFloaterBump::postBuild() // virtual void LLFloaterBump::onOpen(const LLSD& key) { - mNames.clear(); - mList->deleteAllItems(); - if (gMeanCollisionList.empty()) { + mNames.clear(); + mList->deleteAllItems(); + std::string none_detected = getString("none_detected"); LLSD row; row["columns"][0]["value"] = none_detected; @@ -100,12 +101,20 @@ void LLFloaterBump::onOpen(const LLSD& key) } else { - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - add(mList, mcd); - } + populateCollisionList(); + } +} + +void LLFloaterBump::populateCollisionList() +{ + mNames.clear(); + mList->deleteAllItems(); + + for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); + iter != gMeanCollisionList.end(); ++iter) + { + LLMeanCollisionData *mcd = *iter; + add(mList, mcd); } } @@ -247,3 +256,8 @@ void LLFloaterBump::inviteToGroup() { LLAvatarActions::inviteToGroup(mItemUUID); } + +LLFloaterBump* LLFloaterBump::getInstance() +{ + return LLFloaterReg::getTypedInstance<LLFloaterBump>("bumps"); +} diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h index 11b7db9fee..ce52c75255 100755 --- a/indra/newview/llfloaterbump.h +++ b/indra/newview/llfloaterbump.h @@ -46,6 +46,10 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); + static LLFloaterBump* getInstance(); + + void populateCollisionList(); + void startIM(); void startCall(); void reportAbuse(); diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp index 3a2047cfef..da85d378b2 100644 --- a/indra/newview/llfloaterfacebook.cpp +++ b/indra/newview/llfloaterfacebook.cpp @@ -64,9 +64,9 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare"; const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare"; -const S32 MAX_QUALITY = 100; // Max quality value for jpeg images -const S32 MIN_QUALITY = 0; // Min quality value for jpeg images -const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook +const S32 MAX_QUALITY = 100; // Max quality value for jpeg images +const S32 MIN_QUALITY = 0; // Min quality value for jpeg images +const S32 TARGET_DATA_SIZE = 950000; // Size of the image (compressed) we're trying to send to Facebook std::string get_map_url() { diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index ab57e8c170..f1a6ef78a6 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -261,6 +261,8 @@ BOOL LLFloaterIMContainer::postBuild() mInitialized = true; + mIsFirstOpen = true; + // Add callbacks: // We'll take care of view updates on idle gIdleCallbacks.addFunction(idle, this); @@ -636,14 +638,16 @@ void LLFloaterIMContainer::setVisible(BOOL visible) { // Make sure we have the Nearby Chat present when showing the conversation container nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); - if (nearby_chat == NULL) + if ((nearby_chat == NULL) || mIsFirstOpen) { + mIsFirstOpen = false; // If not found, force the creation of the nearby chat conversation panel // *TODO: find a way to move this to XML as a default panel or something like that LLSD name("nearby_chat"); LLFloaterReg::toggleInstanceOrBringToFront(name); selectConversationPair(LLUUID(NULL), false, false); } + flashConversationItemWidget(mSelectedSession,false); LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession); @@ -1216,7 +1220,22 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command, { if (selectedIDS.size() > 0) { - LLAvatarActions::viewChatHistory(selectedIDS.front()); + if(conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP) + { + LLFloaterReg::showInstance("preview_conversation", conversationItem->getUUID(), true); + } + else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC) + { + LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(conversationItem->getUUID())); + if(conv) + { + LLFloaterReg::showInstance("preview_conversation", conv->getSessionID(), true); + } + } + else + { + LLAvatarActions::viewChatHistory(selectedIDS.front()); + } } } else @@ -1316,6 +1335,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata) { return LLLogChat::isNearbyTranscriptExist(); } + else if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_AD_HOC) + { + const LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(uuids.front())); + if(conv) + { + return LLLogChat::isAdHocTranscriptExist(conv->getHistoryFileName()); + } + return false; + } else { bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP); @@ -1881,22 +1909,28 @@ bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid) return false; } - if (!gdatap->mMembers.size()) + if (gdatap->mPendingBanRequest) { return false; } - LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid)); - if (mi == gdatap->mMembers.end()) + if (gdatap->isRoleMemberDataComplete()) { - return false; - } + if (!gdatap->mMembers.size()) + { + return false; + } - LLGroupMemberData* member_data = (*mi).second; - // Is the member an owner? - if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) - { - return false; + 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) && @@ -1924,20 +1958,8 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid) LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL; return; } - std::vector<LLUUID> ids; - ids.push_back(participant_uuid); - - LLGroupBanData ban_data; - gdatap->createBanEntry(participant_uuid, ban_data); - LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids); - LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids); - LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid); - LLSD args; - std::string name; - gCacheName->getFullName(participant_uuid, name); - args["AVATAR_NAME"] = name; - args["GROUP_NAME"] = gdatap->mName; - LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); + + gdatap->banMemberById(participant_uuid); } diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index f21c0b9947..60cef83d9a 100755 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -193,6 +193,8 @@ private: bool mInitialized; bool mIsFirstLaunch; + bool mIsFirstOpen; + LLUUID mSelectedSession; std::string mGeneralTitle; diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index b7fff6cae3..ee3d633dd0 100755 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -326,7 +326,21 @@ void LLFloaterJoystick::onClickOK(void *joy_panel) } } +void LLFloaterJoystick::onClickCloseBtn(bool app_quitting) +{ + cancel(); + closeFloater(app_quitting); +} + void LLFloaterJoystick::setSNDefaults() { LLViewerJoystick::getInstance()->setSNDefaults(); } + +void LLFloaterJoystick::onClose(bool app_quitting) +{ + if (app_quitting) + { + cancel(); + } +} diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 9c3752540d..a1b5951389 100755 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -45,6 +45,11 @@ public: virtual void draw(); static void setSNDefaults(); +protected: + + void onClose(bool app_quitting); + void onClickCloseBtn(bool app_quitting); + private: LLFloaterJoystick(const LLSD& data); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index ce32aeda94..f9fd5069af 100755 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2439,6 +2439,8 @@ void LLPanelLandAccess::refresh() mListAccess->clearSortOrder(); mListAccess->deleteAllItems(); S32 count = parcel->mAccessList.size(); + getChild<LLUICtrl>("AllowedText")->setTextArg("[COUNT]", llformat("%d",count)); + getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); @@ -2484,6 +2486,7 @@ void LLPanelLandAccess::refresh() mListBanned->clearSortOrder(); mListBanned->deleteAllItems(); S32 count = parcel->mBanList.size(); + getChild<LLUICtrl>("BanCheck")->setTextArg("[COUNT]", llformat("%d",count)); getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 449d5e7d64..05b4ecafe6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3683,7 +3683,7 @@ BOOL LLModelPreview::render() } else { - LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + LL_INFOS(" ") << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; regen = TRUE; } } @@ -3691,6 +3691,10 @@ BOOL LLModelPreview::render() if (regen) { genBuffers(mPreviewLOD, skin_weight); + { + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + regen = TRUE; + } } if (!skin_weight) diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 31c2a6f9aa..cb67787af3 100755 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -38,6 +38,8 @@ #include "llsdserialize.h" #include "llvoavatar.h" #include "llcorehttputil.h" +#include "lleventfilter.h" +#include "lleventcoro.h" LLFloaterPerms::LLFloaterPerms(const LLSD& seed) : LLFloater(seed) @@ -167,11 +169,15 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data) xfer->setEnabled(copyable); } +const int MAX_HTTP_RETRIES = 5; +const float RETRY_TIMEOUT = 5.0; + void LLFloaterPermsDefault::sendInitialPerms() { if(!mCapSent) { updateCap(); + setCapSent(true); } } @@ -193,7 +199,8 @@ void LLFloaterPermsDefault::updateCap() /*static*/ void LLFloaterPermsDefault::updateCapCoro(std::string url) { - static std::string previousReason; + int retryCount = 0; + std::string previousReason; LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); @@ -215,23 +222,37 @@ void LLFloaterPermsDefault::updateCapCoro(std::string url) LL_CONT << sent_perms_log.str() << LL_ENDL; } - LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + while (true) + { + ++retryCount; + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - if (!status) - { - const std::string& reason = status.toString(); - // Do not display the same error more than once in a row - if (reason != previousReason) + if (!status) { - previousReason = reason; - LLSD args; - args["REASON"] = reason; - LLNotificationsUtil::add("DefaultObjectPermissions", args); + LLEventTimeout timeout; + + const std::string& reason = status.toString(); + // Do not display the same error more than once in a row + if (reason != previousReason) + { + previousReason = reason; + LLSD args; + args["REASON"] = reason; + LLNotificationsUtil::add("DefaultObjectPermissions", args); + } + + timeout.eventAfter(RETRY_TIMEOUT, LLSD()); + llcoro::suspendUntilEventOn(timeout); + if (retryCount < MAX_HTTP_RETRIES) + continue; + + LL_WARNS("ObjectPermissionsFloater") << "Unable to send default permissions. Giving up for now." << LL_ENDL; + return; } - return; + break; } // Since we have had a successful POST call be sure to display the next error message diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index ee4396758e..dac610eda1 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -49,6 +49,7 @@ //#include "llfirstuse.h" #include "llfloaterreg.h" #include "llfloaterabout.h" +#include "llfavoritesbar.h" #include "llfloaterhardwaresettings.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" @@ -1919,7 +1920,7 @@ BOOL LLPanelPreference::postBuild() } if (hasChild("favorites_on_login_check", TRUE)) { - getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2)); + getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2)); bool show_favorites_at_login = LLPanelLogin::getShowFavorites(); getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login); } @@ -2004,11 +2005,15 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v } } -void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value) +void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value) { - if (checkbox && checkbox->getValue()) + if (checkbox) { - LLNotificationsUtil::add("FavoritesOnLogin"); + LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); + if(checkbox->getValue()) + { + LLNotificationsUtil::add("FavoritesOnLogin"); + } } } @@ -2235,6 +2240,11 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key) void LLFloaterPreferenceProxy::onClose(bool app_quitting) { + if(app_quitting) + { + cancel(); + } + if (mSocksSettingsDirty) { @@ -2334,6 +2344,11 @@ void LLFloaterPreferenceProxy::onBtnCancel() cancel(); } +void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting) +{ + cancel(); +} + void LLFloaterPreferenceProxy::cancel() { @@ -2344,7 +2359,7 @@ void LLFloaterPreferenceProxy::cancel() LLSD ctrl_value = iter->second; control->set(ctrl_value); } - + mSocksSettingsDirty = false; closeFloater(); } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 7bf6ae7d79..04e5e37731 100755 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -229,7 +229,7 @@ private: //for "Only friends and groups can call or IM me" static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&); //for "Show my Favorite Landmarks at Login" - static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value); + static void handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value); typedef std::map<std::string, LLColor4> string_color_map_t; string_color_map_t mSavedColors; @@ -269,6 +269,7 @@ protected: void saveSettings(); void onBtnOk(); void onBtnCancel(); + void onClickCloseBtn(bool app_quitting = false); void onChangeSocksSettings(); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 1c2340b0ef..ed6f4ede9f 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -35,6 +35,7 @@ #include "llassetstorage.h" #include "llavatarnamecache.h" #include "llcachename.h" +#include "llcheckboxctrl.h" #include "llfontgl.h" #include "llimagej2c.h" #include "llinventory.h" @@ -191,6 +192,7 @@ BOOL LLFloaterReporter::postBuild() mOwnerName = LLStringUtil::null; getChild<LLUICtrl>("summary_edit")->setFocus(TRUE); + getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE); mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString(); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 16fa4684ab..afec981d56 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -663,14 +663,20 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data) { LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl; LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + LLSnapshotLivePreview* previewp = getPreviewView(view); - if (!view || !check_box) + if (!view || !check_box || !previewp) { return; } gSavedSettings.setBOOL("UseFreezeFrame", check_box->get()); + if (check_box->get()) + { + previewp->prepareFreezeFrame(); + } + updateLayout(view); } diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index f6cfaf5522..9bb4fe59ad 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -88,6 +88,12 @@ BOOL LLFloaterTOS::postBuild() // Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer. // Store the URL separately and navigate here instead. web_browser->navigateTo( getString( "loading_url" ) ); + LLPluginClassMedia* media_plugin = web_browser->getMediaPlugin(); + if (media_plugin) + { + // All links from tos_html should be opened in external browser + media_plugin->setOverrideClickTarget("_external"); + } } return TRUE; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 1b1c24b19a..ece3e10faa 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -284,12 +284,12 @@ BOOL LLFloaterWorldMap::postBuild() LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo"); avatar_combo->selectFirstItem(); avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); - avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo); LLSearchEditor *location_editor = getChild<LLSearchEditor>("location"); location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); - location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); + location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); mListSearchResults = childGetListInterface("search_results"); @@ -297,7 +297,7 @@ BOOL LLFloaterWorldMap::postBuild() LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo"); landmark_combo->selectFirstItem(); landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); - landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); + landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo); mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f); diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 44eda4d6c0..e9f80b795a 100755 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -109,6 +109,29 @@ bool LLFolderViewModelInventory::contentsReady() return !LLInventoryModelBackgroundFetch::instance().folderFetchActive(); } +bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder) +{ + LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem()); + LLUUID cat_id = modelp->getUUID(); + if (cat_id.isNull()) + { + return false; + } + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (cat) + { + // don't need to check version - descendents_server == -1 if we have no data + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + if (descendents_server == descendents_actual + || (descendents_actual > 0 && descendents_server == -1)) // content was loaded in previous session + { + return true; + } + } + return false; +} + void LLFolderViewModelItemInventory::requestSort() { LLFolderViewModelItemCommon::requestSort(); diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 0516fc3b4b..dea54cbe57 100755 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -115,6 +115,7 @@ public: void sort(LLFolderViewFolder* folder); bool contentsReady(); + bool isFolderComplete(LLFolderViewFolder* folder); bool startDrag(std::vector<LLFolderViewModelItem*>& items); private: diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 4559132aeb..def0f72433 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -239,7 +239,8 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) : mRoleMemberDataComplete(false), mGroupPropertiesDataComplete(false), mPendingRoleMemberRequest(false), - mAccessTime(0.0f) + mAccessTime(0.0f), + mPendingBanRequest(false) { mMemberVersion.generate(); } @@ -761,8 +762,69 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id) mBanList.erase(ban_id); } +void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid) +{ + if (!mMemberDataComplete || + !mRoleDataComplete || + !(mRoleMemberDataComplete && mMembers.size())) + { + LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL; + mPendingBanRequest = true; + mPendingBanMemberID = participant_uuid; + if (!mMemberDataComplete) + { + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); + } + if (!mRoleDataComplete) + { + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID); + } + + return; + } + + LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid)); + if (mi == mMembers.end()) + { + if (!mPendingBanRequest) + { + mPendingBanRequest = true; + mPendingBanMemberID = participant_uuid; + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading + } + else + { + mPendingBanRequest = false; + } + + return; + } + + mPendingBanRequest = false; + + LLGroupMemberData* member_data = (*mi).second; + if (member_data && member_data->isInRole(mOwnerRole)) + { + return; // can't ban group owner + } + + std::vector<LLUUID> ids; + ids.push_back(participant_uuid); + + LLGroupBanData ban_data; + createBanEntry(participant_uuid, ban_data); + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids); + LLGroupMgr::getInstance()->sendGroupMembersRequest(mID); + LLSD args; + std::string name; + gCacheName->getFullName(participant_uuid, name); + args["AVATAR_NAME"] = name; + args["GROUP_NAME"] = mName; + LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); +} // // LLGroupMgr @@ -1245,6 +1307,11 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) group_datap->mChanged = TRUE; LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA); + + if (group_datap->mPendingBanRequest) + { + group_datap->banMemberById(group_datap->mPendingBanMemberID); + } } // static @@ -2108,11 +2175,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) return; } - // If we have no members, there's no reason to do anything else - S32 num_members = content["member_count"]; - if(num_members < 1) - return; - LLUUID group_id = content["group_id"].asUUID(); LLGroupMgrGroupData* group_datap = getGroupData(group_id); @@ -2122,6 +2184,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) return; } + // If we have no members, there's no reason to do anything else + S32 num_members = content["member_count"]; + if (num_members < 1) + { + LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL; + // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237 + group_datap->mMemberDataComplete = true; + group_datap->mChanged = TRUE; + LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); + return; + } + group_datap->mMemberCount = num_members; LLSD member_list = content["members"]; diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index fd0c2de854..e5ce768035 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -151,7 +151,7 @@ public: const uuid_vec_t& getRoleMembers() const { return mMemberIDs; } S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE); - S32 getTotalMembersInRole() { return mMemberIDs.size(); } + S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225 LLRoleData getRoleData() const { return mRoleData; } void setRoleData(LLRoleData data) { mRoleData = data; } @@ -271,8 +271,8 @@ public: void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData()); void removeBanEntry(const LLUUID& ban_id); + void banMemberById(const LLUUID& participant_uuid); - public: typedef std::map<LLUUID,LLGroupMemberData*> member_list_t; typedef std::map<LLUUID,LLGroupRoleData*> role_list_t; @@ -304,6 +304,9 @@ public: S32 mMemberCount; S32 mRoleCount; + bool mPendingBanRequest; + LLUUID mPendingBanMemberID; + protected: void sendRoleChanges(); void cancelRoleChanges(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0c70b074bf..58411af089 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -121,7 +121,7 @@ bool isAddAction(const std::string& action) bool isRemoveAction(const std::string& action) { - return ("take_off" == action || "detach" == action || "deactivate" == action); + return ("take_off" == action || "detach" == action); } bool isMarketplaceSendAction(const std::string& action) @@ -898,15 +898,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, return; } - // "Remove link" and "Delete" are the same operation. - if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) - { - items.push_back(std::string("Remove Link")); - } - else - { - items.push_back(std::string("Delete")); - } + items.push_back(std::string("Delete")); if (!isItemRemovable()) { @@ -1685,7 +1677,9 @@ void LLItemBridge::restoreItem() if(item) { LLInventoryModel* model = getInventoryModel(); - const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); + bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT); + + const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType())); // do not restamp on restore. LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE); } @@ -2312,7 +2306,8 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop, std::string& tooltip_msg, - BOOL user_confirm) + BOOL is_link, + BOOL user_confirm) { LLInventoryModel* model = getInventoryModel(); @@ -2355,6 +2350,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT); const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); //-------------------------------------------------------------------------------- @@ -2392,8 +2388,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } if (is_movable && move_is_into_outfit) { + if((mUUID == my_outifts_id) || (getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE)) + { + is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); + } + else + { + is_movable = false; + } + } + if(is_movable && move_is_into_current_outfit && is_link) + { is_movable = FALSE; - // tooltip? } if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE))) { @@ -2577,9 +2583,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } + // if target is current outfit folder we use link if (move_is_into_current_outfit && - inv_cat->getPreferredType() == LLFolderType::FT_NONE) + (inv_cat->getPreferredType() == LLFolderType::FT_NONE || + inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { // traverse category and add all contents to currently worn. BOOL append = true; @@ -3990,7 +3998,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID()); if (linked_category) { - accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg); + accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE); } } else @@ -4410,7 +4418,7 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c if (option == 0) // YES { std::string tooltip_msg; - dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE); + dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE, FALSE); } } @@ -5577,7 +5585,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action) gInventory.updateItem(item); gInventory.notifyObservers(); } - else if (isRemoveAction(action)) + else if ("deactivate" == action || isRemoveAction(action)) { LLGestureMgr::instance().deactivateGesture(mUUID); @@ -6187,12 +6195,8 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action void LLWearableBridge::openItem() { - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } + performAction(getInventoryModel(), + get_is_item_worn(mUUID) ? "take_off" : "wear"); } void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 30419ae930..9053c61171 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -264,7 +264,7 @@ public: {} BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); - BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); + BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE); void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item); void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 973bf59125..e3cb4d57ef 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2317,7 +2317,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root { LLSD args; args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem"); - LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&onItemsRemovalConfirmation, _1, _2, root->getHandle())); + 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 8aa8370f91..649db4032d 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -461,9 +461,9 @@ struct LLInventoryAction static void removeItemFromDND(LLFolderView* root); private: - static void buildMarketplaceFolders(LLFolderView* root); - static void updateMarketplaceFolders(); - static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed + static void buildMarketplaceFolders(LLFolderView* root); + static void updateMarketplaceFolders(); + static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed }; diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 4e9947fca0..46c1ffa789 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -515,7 +515,7 @@ void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id) { LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); LLSculptParams new_params(*old_params); - new_params.setSculptTexture(new_id); + new_params.setSculptTexture(new_id, (*old_params).getSculptType()); object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE); } } diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index cf04c5f7a5..8d21fda8f9 100755 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -862,14 +862,11 @@ void LLLocationInputCtrl::refreshParcelIcons() bool see_avs = current_parcel->getSeeAVs(); bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled(); - bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID()); - bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify()); - // Most icons are "block this ability" mParcelIcon[VOICE_ICON]->setVisible( !allow_voice ); mParcelIcon[FLY_ICON]->setVisible( !allow_fly ); mParcelIcon[PUSH_ICON]->setVisible( !allow_push ); - mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify ); + mParcelIcon[BUILD_ICON]->setVisible( !allow_build ); mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts ); mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage ); mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 7ddacf3033..4116e38f11 100755 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -804,6 +804,22 @@ bool LLLogChat::isNearbyTranscriptExist() return false; } +bool LLLogChat::isAdHocTranscriptExist(std::string file_name) +{ + std::vector<std::string> list_of_transcriptions; + LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); + + file_name = makeLogFileName(file_name); + BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) + { + if (transcript_file_name == file_name) + { + return true; + } + } + return false; +} + //*TODO mark object's names in a special way so that they will be distinguishable form avatar name //which are more strict by its nature (only firstname and secondname) //Example, an object's name can be written like "Object <actual_object's_name>" diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index ca597599dd..6022e539a9 100755 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -120,6 +120,7 @@ public: static void deleteTranscripts(); static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false); static bool isNearbyTranscriptExist(); + static bool isAdHocTranscriptExist(std::string file_name); static bool historyThreadsFinished(LLUUID session_id); static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 407613d32c..85faa70552 100755 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -1677,12 +1677,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1))); LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - - if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) + //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) + //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + /*if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) { continue; - } + }*/ F32 tick_scale = 1.f; for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) @@ -1710,12 +1710,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2))); LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - - if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) + //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) + //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + /*if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) { continue; - } + }*/ F32 tick_scale = 1.f; for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 394db71fb9..b4259a456c 100755 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1285,12 +1285,12 @@ void LLManipTranslate::renderSnapGuides() { tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit)); - F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()); - - if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f) + //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) + //F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()); + /*if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f) { continue; - } + }*/ // add in off-axis offset tick_start += (mSnapOffsetAxis * mSnapOffsetMeters); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b96bdd73ff..73faed7ef5 100755 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -95,6 +95,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mStretchToFill( true ), mMaintainAspectRatio ( true ), mDecoupleTextureSize ( false ), + mUpdateScrolls( false ), mTextureWidth ( 1024 ), mTextureHeight ( 1024 ), mClearCache(false), @@ -682,7 +683,13 @@ bool LLMediaCtrl::ensureMediaSourceExists() mMediaSource->addObserver( this ); mMediaSource->setBackgroundColor( getBackgroundColor() ); mMediaSource->setTrustedBrowser(mTrusted); - mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); + + F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; + if (scale_factor != mMediaSource->getPageZoomFactor()) + { + mMediaSource->setPageZoomFactor( scale_factor ); + mUpdateScrolls = true; + } if(mClearCache) { @@ -720,10 +727,11 @@ void LLMediaCtrl::draw() { F32 alpha = getDrawContext().mAlpha; - if ( gRestoreGL == 1 ) + if ( gRestoreGL == 1 || mUpdateScrolls) { LLRect r = getRect(); reshape( r.getWidth(), r.getHeight(), FALSE ); + mUpdateScrolls = false; return; } @@ -765,7 +773,12 @@ void LLMediaCtrl::draw() { gGL.pushUIMatrix(); { - mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); + F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; + if (scale_factor != mMediaSource->getPageZoomFactor()) + { + mMediaSource->setPageZoomFactor( scale_factor ); + mUpdateScrolls = true; + } // scale texture to fit the space using texture coords gGL.getTexUnit(0)->bind(media_texture); @@ -970,11 +983,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_CLICK_LINK_HREF: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; // retrieve the event parameters std::string url = self->getClickURL(); - std::string target = self->getClickTarget(); + std::string target = self->isOverrideClickTarget() ? self->getOverrideClickTarget() : self->getClickTarget(); std::string uuid = self->getClickUUID(); + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL; LLNotification::Params notify_params; notify_params.name = "PopupAttempt"; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 785c57b78a..988733b85a 100755 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -192,7 +192,8 @@ public: mHidingInitialLoad, mClearCache, mHoverTextChanged, - mDecoupleTextureSize; + mDecoupleTextureSize, + mUpdateScrolls; std::string mHomePageUrl, mHomePageMimeType, diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index fe562baf96..70035bcc74 100755 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -303,7 +303,15 @@ void LLFloaterMove::onFlyButtonClick() void LLFloaterMove::setMovementMode(const EMovementMode mode) { mCurrentMode = mode; - gAgent.setFlying(MM_FLY == mode); + + if(MM_FLY == mode) + { + LLAgent::toggleFlying(); + } + else + { + gAgent.setFlying(FALSE); + } // attempts to set avatar flying can not set it real flying in some cases. // For ex. when avatar fell down & is standing up. diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 79988a0800..5510598ae7 100755 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -130,8 +130,14 @@ BOOL LLNameListCtrl::handleDragAndDrop( return handled; } -void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group) +void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience) { + if(is_experience) + { + LLFloaterReg::showInstance("experience_profile", avatar_id, true); + return; + } + if (is_group) LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id)); else @@ -230,10 +236,11 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) // Should we show a group or an avatar inspector? bool is_group = hit_item->isGroup(); + bool is_experience = hit_item->isExperience(); LLToolTip::Params params; params.background_visible( false ); - params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) ); + params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience) ); params.delay_time(0.0f); // spawn instantly on hover params.image( icon ); params.message(""); @@ -295,7 +302,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( const std::string& prefix) { LLUUID id = name_item.value().asUUID(); - LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP); + LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP, name_item.target() == EXPERIENCE); if (!item) return NULL; @@ -353,6 +360,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( } break; } + case EXPERIENCE: + // just use supplied name default: break; } diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 515962df7d..19ce3c7aed 100755 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -44,22 +44,30 @@ class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameLi public: bool isGroup() const { return mIsGroup; } void setIsGroup(bool is_group) { mIsGroup = is_group; } + bool isExperience() const { return mIsExperience; } + void setIsExperience(bool is_experience) { mIsExperience = is_experience; } protected: friend class LLNameListCtrl; LLNameListItem( const LLScrollListItem::Params& p ) - : LLScrollListItem(p), mIsGroup(false) + : LLScrollListItem(p), mIsGroup(false), mIsExperience(false) { } LLNameListItem( const LLScrollListItem::Params& p, bool is_group ) - : LLScrollListItem(p), mIsGroup(is_group) + : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(false) + { + } + + LLNameListItem( const LLScrollListItem::Params& p, bool is_group, bool is_experience ) + : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(is_experience) { } private: bool mIsGroup; + bool mIsExperience; }; @@ -73,7 +81,8 @@ public: { INDIVIDUAL, GROUP, - SPECIAL + SPECIAL, + EXPERIENCE } ENameType; // provide names for enums @@ -160,7 +169,7 @@ public: /*virtual*/ void mouseOverHighlightNthItem( S32 index ); private: - void showInspector(const LLUUID& avatar_id, bool is_group); + void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, LLHandle<LLNameListItem> item); private: diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 9bd6007772..b7e1b2d3a4 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1168,6 +1168,8 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO targetPanel->setVisible(show); toggleTypeSpecificControls(type); + // Update type controls here + updateTypeSpecificControls(type); if (show) { @@ -1179,7 +1181,6 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO mNameEditor->setText(mWearableItem->getName()); updatePanelPickerControls(type); - updateTypeSpecificControls(type); // clear and rebuild visual param list U8 num_subparts = wearable_entry->mSubparts.size(); diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp index 9d52a1906b..32ec4930ab 100644 --- a/indra/newview/llpanelexperiencelisteditor.cpp +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -33,6 +33,7 @@ #include "llfloaterexperiencepicker.h" #include "llfloaterreg.h" #include "llhandle.h" +#include "llnamelistctrl.h" #include "llscrolllistctrl.h" #include "llviewerregion.h" #include "llagent.h" @@ -54,7 +55,7 @@ LLPanelExperienceListEditor::LLPanelExperienceListEditor() BOOL LLPanelExperienceListEditor::postBuild() { - mItems = getChild<LLScrollListCtrl>("experience_list"); + mItems = getChild<LLNameListCtrl>("experience_list"); mAdd = getChild<LLButton>("btn_add"); mRemove = getChild<LLButton>("btn_remove"); mProfile = getChild<LLButton>("btn_profile"); @@ -178,6 +179,7 @@ void LLPanelExperienceListEditor::onItems() { const LLUUID& experience = *it; item["id"]=experience; + item["target"] = LLNameListCtrl::EXPERIENCE; LLSD& columns = item["columns"]; columns[0]["column"] = "experience_name"; columns[0]["value"] = getString("loading"); diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h index f69f0509be..bc9867752d 100644 --- a/indra/newview/llpanelexperiencelisteditor.h +++ b/indra/newview/llpanelexperiencelisteditor.h @@ -31,6 +31,7 @@ #include "lluuid.h" #include <set> +class LLNameListCtrl; class LLScrollListCtrl; class LLButton; class LLFloaterExperiencePicker; @@ -82,7 +83,7 @@ private: uuid_list_t mExperienceIds; - LLScrollListCtrl* mItems; + LLNameListCtrl* mItems; filter_list mFilters; LLButton* mAdd; LLButton* mRemove; diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index dcc5f4f234..a7f2dbafa2 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -42,6 +42,7 @@ #include "llviewercontrol.h" #include "llfloater.h" #include "lltrans.h" +#include <boost/regex.hpp> #define BTN_FIND "find" #define BTN_OK "ok_btn" @@ -112,6 +113,46 @@ void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* u void LLPanelExperiencePicker::onBtnFind() { mCurrentPage=1; + boost::cmatch what; + std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString(); + const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); + if (boost::regex_match(text.c_str(), what, expression)) + { + LLURI uri(text); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string exp_id = path_array.get(2).asString(); + LLUUID experience_id(exp_id); + if (!experience_id.isNull()) + { + const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); + if(!experience_details.isUndefined()) + { + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + if(!experience_name_string.empty()) + { + getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string); + } + } + else + { + getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems(); + getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching")); + + getChildView(BTN_OK)->setEnabled(FALSE); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChildView(BTN_RIGHT)->setEnabled(FALSE); + getChildView(BTN_LEFT)->setEnabled(FALSE); + LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); + return; + } + } + } + } + + find(); } @@ -155,7 +196,6 @@ void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hpar } } - bool LLPanelExperiencePicker::isSelectButtonEnabled() { LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 9823e84cd9..d7e89b4832 100755 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -307,7 +307,7 @@ private: LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material); } - object->setTEMaterialParams(face, new_material); + object->setTEMaterialParams(face, new_material, TRUE); return new_material; } return NULL; diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index f67a90fd01..342b57ba4a 100755 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -338,7 +338,7 @@ void LLPanelGroup::update(LLGroupChange gc) group_name_ctrl->setToolTip(group_name); LLGroupData agent_gdatap; - bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); + bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery(); bool join_btn_visible = !is_member && gdatap->mOpenEnrollment; mButtonJoin->setVisible(join_btn_visible); @@ -470,7 +470,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) } LLGroupData agent_gdatap; - bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); + bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery(); tab_roles->setVisible(is_member); tab_notices->setVisible(is_member); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 7ffaa05919..b2164c1f21 100755 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -287,11 +287,6 @@ void LLPanelGroupGeneral::activate() { LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID); LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); - - if (!gdatap || !gdatap->isMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } mFirstUse = FALSE; } diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index e662a05dfc..866cb8dbef 100755 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -243,56 +243,59 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) LLGroupMgrGroupData::member_list_t::iterator agent_iter = gdatap->mMembers.find(gAgent.getID()); + //loop over the agent's roles in the group + //then add those roles to the list of roles that the agent + //can invite people to be. + //if the user is the owner then we add + //all of the roles in the group, + //else if they have the add to roles power + //we add every role but owner, + //else if they have the limited add to roles power + //we add every role the user is in, + //else we just add to everyone + bool is_owner = FALSE; + bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, + GP_ROLE_ASSIGN_MEMBER); + bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, + GP_ROLE_ASSIGN_MEMBER_LIMITED); + LLGroupMemberData* member_data = NULL; //get the member data for the agent if it exists - if ( agent_iter != gdatap->mMembers.end() ) + if (agent_iter != gdatap->mMembers.end()) { - LLGroupMemberData* member_data = (*agent_iter).second; - - //loop over the agent's roles in the group - //then add those roles to the list of roles that the agent - //can invite people to be - if ( member_data && mRoleNames) + member_data = (*agent_iter).second; + if (member_data && mRoleNames) { - //if the user is the owner then we add - //all of the roles in the group - //else if they have the add to roles power - //we add every role but owner, - //else if they have the limited add to roles power - //we add every role the user is in - //else we just add to everyone - bool is_owner = member_data->isOwner(); - bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, - GP_ROLE_ASSIGN_MEMBER); - bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, - GP_ROLE_ASSIGN_MEMBER_LIMITED); + is_owner = member_data->isOwner(); + }//end if member data is not null + }//end if agent is in the group + - LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin(); - LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); - //populate the role list - for ( ; rit != end; ++rit) + LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin(); + LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); + + //populate the role list: + for ( ; rit != end; ++rit) + { + LLUUID role_id = (*rit).first; + LLRoleData rd; + if ( gdatap->getRoleData(role_id,rd) ) + { + // Owners can add any role. + if ( is_owner + // Even 'can_assign_any' can't add owner role. + || (can_assign_any && role_id != gdatap->mOwnerRole) + // Add all roles user is in + || (can_assign_limited && member_data && member_data->isInRole(role_id)) + // Everyone role. + || role_id == LLUUID::null ) { - LLUUID role_id = (*rit).first; - LLRoleData rd; - if ( gdatap->getRoleData(role_id,rd) ) - { - // Owners can add any role. - if ( is_owner - // Even 'can_assign_any' can't add owner role. - || (can_assign_any && role_id != gdatap->mOwnerRole) - // Add all roles user is in - || (can_assign_limited && member_data->isInRole(role_id)) - // Everyone role. - || role_id == LLUUID::null ) - { - mRoleNames->add(rd.mRoleName, - role_id, - ADD_BOTTOM); - } - } + mRoleNames->add(rd.mRoleName, + role_id, + ADD_BOTTOM); } - }//end if member data is not null - }//end if agent is in the group + } + } } //static @@ -579,7 +582,8 @@ void LLPanelGroupInvite::updateLists() { waiting = true; } - if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete()) + if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() + && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them { if ( mImplementation->mRoleNames ) { diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index c3a10b3fa0..00c204e702 100755 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -350,12 +350,10 @@ void LLPanelGroupRoles::update(LLGroupChange gc) void LLPanelGroupRoles::activate() { + if (!gAgent.isInGroup(mGroupID)) return; + // Start requesting member and role data if needed. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); - if (!gdatap || !gdatap->isMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } if (!gdatap || !gdatap->isRoleDataComplete() ) { @@ -364,13 +362,7 @@ void LLPanelGroupRoles::activate() LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); } - - // Check role-member mapping data. - if (!gdatap || !gdatap->isRoleMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); - } - + // Need this to get base group member powers if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) { @@ -1163,7 +1155,37 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) if ( selfp ) { - selfp->handleEjectMembers(); + selfp->confirmEjectMembers(); + } +} + +void LLPanelGroupMembersSubTab::confirmEjectMembers() +{ + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); + if (selection.empty()) return; + + S32 selection_count = selection.size(); + if (selection_count == 1) + { + LLSD args; + std::string fullname; + gCacheName->getFullName(mMembersList->getValue(), fullname); + args["AVATAR_NAME"] = fullname; + LLSD payload; + LLNotificationsUtil::add("EjectGroupMemberWarning", + args, + payload, + boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); + } + else + { + LLSD args; + args["COUNT"] = llformat("%d", selection_count); + LLSD payload; + LLNotificationsUtil::add("EjectGroupMembersWarning", + args, + payload, + boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); } } @@ -1190,6 +1212,16 @@ void LLPanelGroupMembersSubTab::handleEjectMembers() LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); } +bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) // Eject button + { + handleEjectMembers(); + } + return false; +} + void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members) { LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); @@ -1327,15 +1359,26 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick() void LLPanelGroupMembersSubTab::activate() { + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + LLPanelGroupSubTab::activate(); if(!mActivated) { + if (!gdatap || !gdatap->isMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } + + if (!gdatap || !gdatap->isRoleMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } + update(GC_ALL); mActivated = true; } else { - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); // Members can be removed outside of this tab, checking changes if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount())) { @@ -1636,7 +1679,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) { // Build a string with info on retrieval progress. std::ostringstream retrieved; - if ( !gdatap->isMemberDataComplete() ) + + if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() ) + { + // MAINT-5237 + retrieved << "Member list not available."; + } + else if ( !gdatap->isMemberDataComplete() ) { // Still busy retreiving member list. retrieved << "Retrieving member list (" << gdatap->mMembers.size() @@ -1783,7 +1832,7 @@ void LLPanelGroupMembersSubTab::updateMembers() { mMembersList->setEnabled(TRUE); } - else + else if (gdatap->mMembers.size()) { mMembersList->setEnabled(FALSE); mMembersList->setCommentText(std::string("No match.")); @@ -1801,7 +1850,47 @@ void LLPanelGroupMembersSubTab::updateMembers() void LLPanelGroupMembersSubTab::onBanMember(void* user_data) { LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data); - self->handleBanMember(); + self->confirmBanMembers(); +} + +void LLPanelGroupMembersSubTab::confirmBanMembers() +{ + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); + if (selection.empty()) return; + + S32 selection_count = selection.size(); + if (selection_count == 1) + { + LLSD args; + std::string fullname; + gCacheName->getFullName(mMembersList->getValue(), fullname); + args["AVATAR_NAME"] = fullname; + LLSD payload; + LLNotificationsUtil::add("BanGroupMemberWarning", + args, + payload, + boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2)); + } + else + { + LLSD args; + args["COUNT"] = llformat("%d", selection_count); + LLSD payload; + LLNotificationsUtil::add("BanGroupMembersWarning", + args, + payload, + boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2)); + } +} + +bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) // Eject button + { + handleBanMember(); + } + return false; } void LLPanelGroupMembersSubTab::handleBanMember() @@ -2111,20 +2200,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) mDeleteRoleButton->setEnabled(FALSE); } } - - if(!mFirstOpen) - { - if (!gdatap || !gdatap->isMemberDataComplete()) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - if (!gdatap || !gdatap->isRoleMemberDataComplete()) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); - } - } - + if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc) && gdatap && gdatap->isMemberDataComplete() diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 540b24ada6..9a696124a8 100755 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -171,6 +171,7 @@ public: void handleEjectMembers(); void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members); bool handleEjectCallback(const LLSD& notification, const LLSD& response); + void confirmEjectMembers(); static void onRoleCheck(LLUICtrl* check, void* user_data); void handleRoleCheck(const LLUUID& role_id, @@ -178,6 +179,8 @@ public: static void onBanMember(void* user_data); void handleBanMember(); + bool handleBanCallback(const LLSD& notification, const LLSD& response); + void confirmBanMembers(); void applyMemberChanges(); diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index d4894d4a42..06bb886ae8 100755 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -147,6 +147,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type) } else { + LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos); region_name = desc; } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 7aaf9510eb..4229419fce 100755 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -604,7 +604,7 @@ void LLPanelMainInventory::updateItemcountText() } else { - text = getString("ItemcountUnknown"); + text = getString("ItemcountUnknown", string_args); } mCounterCtrl->setValue(text); diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index 2856ea9db1..d7c43c224c 100755 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -319,6 +319,10 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media // Helper to set media control to media URL as required void LLPanelMediaSettingsGeneral::updateMediaPreview() { + if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString()) + { + return; + } if ( mHomeURL->getValue().asString().length() > 0 ) { if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString()) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index dcd0aab3ab..5dd44b4444 100755 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1739,9 +1739,10 @@ void LLPanelObject::sendSculpt() return; LLSculptParams sculpt_params; + LLUUID sculpt_id = LLUUID::null; if (mCtrlSculptTexture) - sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); + sculpt_id = mCtrlSculptTexture->getImageAssetID(); U8 sculpt_type = 0; @@ -1765,7 +1766,7 @@ void LLPanelObject::sendSculpt() if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get())) sculpt_type |= LL_SCULPT_FLAG_INVERT; - sculpt_params.setSculptType(sculpt_type); + sculpt_params.setSculptTexture(sculpt_id, sculpt_type); mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); } @@ -2000,7 +2001,11 @@ void LLPanelObject::onCancelSculpt(const LLSD& data) LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); if(!mTextureCtrl) return; - + + if(mSculptTextureRevert == LLUUID::null) + { + mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE); + } mTextureCtrl->setImageAssetID(mSculptTextureRevert); sendSculpt(); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 5977d558d3..de4efc8612 100755 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -85,6 +85,8 @@ static const std::string RECENT_TAB_NAME = "recent_panel"; static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars static const std::string COLLAPSED_BY_USER = "collapsed_by_user"; +const S32 BASE_MAX_AGENT_GROUPS = 42; +const S32 PREMIUM_MAX_AGENT_GROUPS = 60; extern S32 gMaxAgentGroups; @@ -585,6 +587,7 @@ BOOL LLPanelPeople::postBuild() getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); mTabContainer = getChild<LLTabContainer>("tabs"); mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); @@ -902,8 +905,11 @@ void LLPanelPeople::updateButtons() LLPanel* groups_panel = mTabContainer->getCurrentPanel(); groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected - groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size())); - groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d",(gMaxAgentGroups-gAgent.mGroups.size()))); + + U32 groups_count = gAgent.mGroups.size(); + U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0; + groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); + groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining)); } else { @@ -1114,6 +1120,14 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) } } +void LLPanelPeople::onGroupLimitInfo() +{ + LLSD args; + args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS; + args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS; + LLNotificationsUtil::add("GroupLimitInfo", args); +} + void LLPanelPeople::onTabSelected(const LLSD& param) { std::string tab_name = getChild<LLPanel>(param.asString())->getName(); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index c1d7a134fa..eb7e76a772 100755 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -93,6 +93,7 @@ private: // UI callbacks void onFilterEdit(const std::string& search_string); + void onGroupLimitInfo(); void onTabSelected(const LLSD& param); void onAddFriendButtonClicked(); void onAddFriendWizButtonClicked(); diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index d73a5b402e..55c09d85ea 100755 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -432,7 +432,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) mNoPicks = !mPicksList->size(); } - else if(APT_CLASSIFIEDS == type) + else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type)) { LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data); if(c_info && getAvatarId() == c_info->target_id) diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 4bcd932d4b..a9a0c30e26 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -921,7 +921,12 @@ void LLPanelPlaces::onBackButtonClicked() void LLPanelPlaces::togglePickPanel(BOOL visible) { if (mPickPanel) + { mPickPanel->setVisible(visible); + mPlaceProfile->setVisible(!visible); + updateVerbs(); + } + } void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) @@ -1141,16 +1146,21 @@ void LLPanelPlaces::updateVerbs() bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; + bool is_pick_panel_visible = false; + if(mPickPanel) + { + is_pick_panel_visible = mPickPanel->isInVisibleChain(); + } bool have_3d_pos = ! mPosGlobal.isExactlyZero(); - mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); - mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); + mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn); mSaveBtn->setVisible(isLandmarkEditModeOn); mCancelBtn->setVisible(isLandmarkEditModeOn); mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); - mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); + mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index ac9a31ce4e..109013498e 100755 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -313,14 +313,11 @@ void LLPanelTopInfoBar::updateParcelIcons() bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel); bool see_avs = current_parcel->getSeeAVs(); - bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID()); - bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify()); - // Most icons are "block this ability" mParcelIcon[VOICE_ICON]->setVisible( !allow_voice ); mParcelIcon[FLY_ICON]->setVisible( !allow_fly ); mParcelIcon[PUSH_ICON]->setVisible( !allow_push ); - mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify ); + mParcelIcon[BUILD_ICON]->setVisible( !allow_build ); mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts ); mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage ); mDamageText->setVisible(allow_damage); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 5f029ca6a2..ed34190caa 100755 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1370,6 +1370,8 @@ void LLLiveLSLEditor::buildExperienceList() else { mExperiences->setEnabled(TRUE); + mExperiences->sortByName(TRUE); + mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex()); getChild<LLButton>("view_profile")->setVisible(TRUE); } } @@ -2642,8 +2644,12 @@ void LLLiveLSLEditor::onLoad(void* userdata) void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) { LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; - self->mCloseAfterSave = close_after_save; - self->saveIfNeeded(); + if(self) + { + self->mCloseAfterSave = close_after_save; + self->mScriptEd->mErrorList->setCommentText(""); + self->saveIfNeeded(); + } } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index f91a18d8d3..c8cf0faa15 100755 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -618,4 +618,5 @@ void LLPreviewTexture::setObjectID(const LLUUID& object_id) mAssetStatus = PREVIEW_ASSET_UNLOADED; loadAsset(); } + refreshFromItem(); } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4fafbf917b..55bcb3dc65 100755 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2127,7 +2127,7 @@ void LLSelectMgr::selectionRemoveMaterial() { LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL; LLMaterialMgr::getInstance()->remove(object->getID(),face); - object->setTEMaterialParams(face, NULL); + object->setTEMaterialParams(face, NULL, FALSE); } return true; } @@ -4950,6 +4950,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, ESendType send_type) { LLSelectNode* node; + LLSelectNode* linkset_root = NULL; LLViewerRegion* last_region; LLViewerRegion* current_region; @@ -4957,6 +4958,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, S32 packets_sent = 0; S32 objects_in_this_packet = 0; + bool link_operation = message_name == "ObjectLink"; + //clear update override data (allow next update through) struct f : public LLSelectedNodeFunctor { @@ -5065,6 +5068,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, && (! gMessageSystem->isSendFull(NULL)) && (objects_in_this_packet < MAX_OBJECTS_PER_PACKET)) { + if (link_operation && linkset_root == NULL) + { + // linksets over 254 will be split into multiple messages, + // but we need to provide same root for all messages or we will get separate linksets + linkset_root = node; + } // add another instance of the body of the data (*pack_body)(node, user_data); // do any related logging @@ -5093,6 +5102,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, gMessageSystem->newMessage(message_name.c_str()); (*pack_header)(user_data); + if (linkset_root != NULL) + { + if (current_region != last_region) + { + // root should be in one region with the child, reset it + linkset_root = NULL; + } + else + { + // add root instance into new message + (*pack_body)(linkset_root, user_data); + ++objects_sent; + ++objects_in_this_packet; + } + } + // don't move to the next object, we still need to add the // body data. } diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 17ecfab4fb..2548d730f0 100755 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -370,18 +370,25 @@ void LLSidepanelTaskInfo::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); + std::string creator_name; - LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); + LLUUID creator_id; + LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); - getChild<LLUICtrl>("Creator Name")->setValue(creator_name); - getChildView("Creator Name")->setEnabled(TRUE); + if(creator_id != mCreatorID ) + { + mDACreatorName->setValue(creator_name); + mCreatorID = creator_id; + } + mDACreatorName->setEnabled(TRUE); // Update owner text field getChildView("Owner:")->setEnabled(TRUE); std::string owner_name; - const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name); - if (mOwnerID.isNull()) + LLUUID owner_id; + const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + if (owner_id.isNull()) { if (LLSelectMgr::getInstance()->selectIsGroupOwned()) { @@ -402,7 +409,12 @@ void LLSidepanelTaskInfo::refresh() } } } - getChild<LLUICtrl>("Owner Name")->setValue(owner_name); + + if(owner_id.isNull() || (owner_id != mOwnerID)) + { + mDAOwnerName->setValue(owner_name); + mOwnerID = owner_id; + } getChildView("Owner Name")->setEnabled(TRUE); // update group text field diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 728fc69723..a8e012bfa1 100755 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -271,7 +271,14 @@ LLSLURL::LLSLURL(const std::string& slurl) // at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z // are collectively optional // are optional + mRegion = LLURI::unescape(path_array[0].asString()); + + if(LLStringUtil::containsNonprintable(mRegion)) + { + LLStringUtil::stripNonprintable(mRegion); + } + path_array.erase(0); // parse the x, y, and optionally z diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 8fb3340db0..b9e2e11bfa 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -195,7 +195,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail // Stop shining animation. mShineAnimTimer.stop(); mSnapshotDelayTimer.start(); - mSnapshotDelayTimer.setTimerExpirySec(delay); + mSnapshotDelayTimer.resetWithExpiry(delay); + mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal(); @@ -670,10 +671,27 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) return FALSE; } - // If we're in freeze-frame mode and camera has moved, update snapshot. + if (previewp->mSnapshotDelayTimer.getStarted()) // Wait for a snapshot delay timer + { + if (!previewp->mSnapshotDelayTimer.hasExpired()) + { + return FALSE; + } + previewp->mSnapshotDelayTimer.stop(); + } + + if (LLToolCamera::getInstance()->hasMouseCapture()) // Hide full-screen preview while camming, either don't take snapshots while ALT-zoom active + { + previewp->setVisible(FALSE); + return FALSE; + } + + // If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot. LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin(); LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); - if (previewp->mForceUpdateSnapshot || (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview && + if (previewp->mForceUpdateSnapshot || + (((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) || + (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) && (new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))) { previewp->mCameraPos = new_camera_pos; @@ -688,11 +706,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mForceUpdateSnapshot = FALSE; } - // see if it's time yet to snap the shot and bomb out otherwise. - previewp->mSnapshotActive = - (previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired()) - && !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active - if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate()) + if (previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate()) { return FALSE; } @@ -706,6 +720,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mPreviewImage = new LLImageRaw; } + previewp->mSnapshotActive = TRUE; + previewp->setVisible(FALSE); previewp->setEnabled(FALSE); @@ -734,40 +750,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) // Full size preview is set: get the decoded image result and save it for animation if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview) { - // Get the decoded version of the formatted image - previewp->getEncodedImage(); - - // We need to scale that a bit for display... - LLPointer<LLImageRaw> scaled = new LLImageRaw( - previewp->mPreviewImageEncoded->getData(), - previewp->mPreviewImageEncoded->getWidth(), - previewp->mPreviewImageEncoded->getHeight(), - previewp->mPreviewImageEncoded->getComponents()); - - if (!scaled->isBufferInvalid()) - { - // leave original image dimensions, just scale up texture buffer - if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024) - { - // go ahead and shrink image to appropriate power of 2 for display - scaled->biasedScaleToPowerOfTwo(1024); - previewp->setImageScaled(TRUE); - } - else - { - // expand image but keep original image data intact - scaled->expandToPowerOfTwo(1024, FALSE); - } - - previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); - LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; - gGL.getTexUnit(0)->bind(curr_preview_image); - curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); - curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); - - previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame - } + previewp->prepareFreezeFrame(); } + // The snapshot is updated now... previewp->mSnapshotUpToDate = TRUE; @@ -777,7 +762,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) } previewp->getWindow()->decBusyCount(); previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode - previewp->mSnapshotDelayTimer.stop(); previewp->mSnapshotActive = FALSE; LL_DEBUGS() << "done creating snapshot" << LL_ENDL; } @@ -796,6 +780,47 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) return TRUE; } +void LLSnapshotLivePreview::prepareFreezeFrame() +{ + // Get the decoded version of the formatted image + getEncodedImage(); + + // We need to scale that a bit for display... + LLPointer<LLImageRaw> scaled = new LLImageRaw( + mPreviewImageEncoded->getData(), + mPreviewImageEncoded->getWidth(), + mPreviewImageEncoded->getHeight(), + mPreviewImageEncoded->getComponents()); + + if (!scaled->isBufferInvalid()) + { + // leave original image dimensions, just scale up texture buffer + if (mPreviewImageEncoded->getWidth() > 1024 || mPreviewImageEncoded->getHeight() > 1024) + { + // go ahead and shrink image to appropriate power of 2 for display + scaled->biasedScaleToPowerOfTwo(1024); + setImageScaled(TRUE); + } + else + { + // expand image but keep original image data intact + scaled->expandToPowerOfTwo(1024, FALSE); + } + + mViewerImage[mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); + LLPointer<LLViewerTexture> curr_preview_image = mViewerImage[mCurImageIndex]; + gGL.getTexUnit(0)->bind(curr_preview_image); + curr_preview_image->setFilteringOption(getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); + curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); + + + if (gSavedSettings.getBOOL("UseFreezeFrame") && mAllowFullScreenPreview) + { + mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame + } + } +} + S32 LLSnapshotLivePreview::getEncodedImageWidth() const { S32 width = getWidth(); diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h index fed33bf37c..57e5d83f8e 100644 --- a/indra/newview/llsnapshotlivepreview.h +++ b/indra/newview/llsnapshotlivepreview.h @@ -119,7 +119,7 @@ public: void generateThumbnailImage(BOOL force_update = FALSE) ; void resetThumbnailImage() { mThumbnailImage = NULL ; } void drawPreviewRect(S32 offset_x, S32 offset_y) ; - + void prepareFreezeFrame(); LLViewerTexture* getBigThumbnailImage(); S32 getBigThumbnailWidth() const { return mBigThumbnailWidth ; } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 974029254f..e7971028bf 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -504,21 +504,8 @@ void LLSpeakerMgr::updateSpeakerList() // For groups, we need to hit the group manager. // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); - F32 large_group_delay = 0.f; - if (gdatap) - { - //This is a viewer-side bandaid for maint-4414 it does not fix the core issue. - large_group_delay = (F32)(gdatap->mMemberCount / 5000); - } - - const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay; - - if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout)) - { - // Request the data the first time around - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id); - } - else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + + if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) { // Add group members when we get the complete list (note: can take a while before we get that list) LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2c6b9d14bf..e97b73763b 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -404,9 +404,7 @@ bool idle_startup() gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); gSavedSettings.setString("LastGPUString", thisGPU); - // load dynamic GPU/feature tables from website (S3) - LLFeatureManager::getInstance()->fetchHTTPTables(); - + std::string xml_file = LLUI::locateSkin("xui_version.xml"); LLXMLNodePtr root; bool xml_ok = false; @@ -3197,6 +3195,23 @@ bool process_login_success_response() LLStringUtil::trim(gDisplayName); } } + std::string first_name; + if(response.has("first_name")) + { + first_name = response["first_name"].asString(); + LLStringUtil::replaceChar(first_name, '"', ' '); + LLStringUtil::trim(first_name); + gAgentUsername = first_name; + } + + if(response.has("last_name") && !gAgentUsername.empty() && (gAgentUsername != "Resident")) + { + std::string last_name = response["last_name"].asString(); + LLStringUtil::replaceChar(last_name, '"', ' '); + LLStringUtil::trim(last_name); + gAgentUsername = gAgentUsername + " " + last_name; + } + if(gDisplayName.empty()) { if(response.has("first_name")) @@ -3217,6 +3232,7 @@ bool process_login_success_response() gDisplayName += text; } } + if(gDisplayName.empty()) { gDisplayName.assign(gUserCredential->asString()); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index ef852bc905..bcdf8360ed 100755 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1544,17 +1544,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) { std::string dirname = mTexturesDirName + delem + subdirs[i]; LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL; - gDirUtilp->deleteFilesInDir(dirname, mask); if (purge_directories) { - LLFile::rmdir(dirname); + gDirUtilp->deleteDirAndContents(dirname); + } + else + { + gDirUtilp->deleteFilesInDir(dirname, mask); } } if (purge_directories) { gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); LLFile::rmdir(mTexturesDirName); - } + } } mHeaderIDMap.clear(); mTexturesSizeMap.clear(); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 8f482c5dca..05c98826d2 100755 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1140,8 +1140,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, } LLSculptParams sculpt_params; - sculpt_params.setSculptTexture(asset_id); - sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH); + sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH); hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); dialog_refresh_all(); diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index cad5769042..8a61114852 100755 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -84,7 +84,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard() const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length)); LLWString text_to_copy; // *HACK: Because LLSLURL is currently broken we cannot use it to check if unescaped_text is a valid SLURL (see EXT-8335). - if (LLStringUtil::startsWith(unescaped_text, "http://")) // SLURL + if (LLStringUtil::startsWith(unescaped_text, "http://") || LLStringUtil::startsWith(unescaped_text, "secondlife://")) // SLURL text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text)); else // human-readable location text_to_copy = utf8str_to_wstring(unescaped_text); diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 92d644c900..d93eb3d6e0 100755 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -254,6 +254,7 @@ public: void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;}; void clearCache(); void setPageZoomFactor( double factor ); + double getPageZoomFactor() {return mZoomFactor;} std::string getMimeType() { return mMimeType; } void scaleMouse(S32 *mouse_x, S32 *mouse_y); void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d8ec44b132..f32ae27073 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -57,6 +57,7 @@ #include "llfacebookconnect.h" #include "llfilepicker.h" #include "llfirstuse.h" +#include "llfloaterabout.h" #include "llfloaterbuy.h" #include "llfloaterbuycontents.h" #include "llbuycurrencyhtml.h" @@ -2106,6 +2107,22 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t +/////////////////////// +// CHECK FOR UPDATES // +/////////////////////// + + + +class LLAdvancedCheckViewerUpdates : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterAboutUtil::checkUpdatesAndNotify(); + return true; + } +}; + + //////////////////// // COMPRESS IMAGE // //////////////////// @@ -7107,11 +7124,10 @@ void handle_selected_texture_info(void*) { msg.append( llformat("%d ", (S32)(it->second[i]))); } - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); } + LLSD args; + args["MESSAGE"] = msg; + LLNotificationsUtil::add("SystemMessage", args); } } @@ -8887,6 +8903,7 @@ void initialize_menus() // Advanced (toplevel) view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckViewerUpdates(), "Advanced.CheckViewerUpdates"); view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 4062228ae5..77f8e9bf55 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -57,6 +57,7 @@ #include "llcallingcard.h" #include "llbuycurrencyhtml.h" #include "llfirstuse.h" +#include "llfloaterbump.h" #include "llfloaterbuyland.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" @@ -2351,7 +2352,8 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s LLNotificationsUtil::add("GodMessage", args); // Treat like a system message and put in chat history. - chat.mText = av_name.getCompleteName() + ": " + message; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat.mText = message; LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); if (nearby_chat) @@ -2862,6 +2864,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_FROM_TASK: { + if (is_do_not_disturb && !is_owned_by_me) { return; @@ -2945,17 +2948,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) payload["from_id"] = from_id; payload["slurl"] = location; payload["name"] = name; - std::string session_name; + if (from_group) { payload["group_owned"] = "true"; } - LLNotification::Params params("ServerObjectMessage"); - params.substitutions = substitutions; - params.payload = payload; - - LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group); + LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload); } break; @@ -3769,11 +3768,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } } - LLSD msg_notify = LLSD(LLSD::emptyMap()); - msg_notify["session_id"] = LLUUID(); - msg_notify["from_id"] = chat.mFromID; - msg_notify["source_type"] = chat.mSourceType; - on_new_message(msg_notify); + if (mesg != "") + { + LLSD msg_notify = LLSD(LLSD::emptyMap()); + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } + } } @@ -6243,6 +6246,11 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3)); } } + LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); + if(bumps_floater && bumps_floater->isInVisibleChain()) + { + bumps_floater->populateCollisionList(); + } } void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 190102ff0f..c1a7518ba2 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2885,6 +2885,9 @@ struct LLFilenameAndTask { LLUUID mTaskID; std::string mFilename; + + // for sequencing in case of multiple updates + S16 mSerial; #ifdef _DEBUG static S32 sCount; LLFilenameAndTask() @@ -2920,9 +2923,17 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) return; } - msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); LLFilenameAndTask* ft = new LLFilenameAndTask; ft->mTaskID = task_id; + // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); + + if (ft->mSerial < object->mInventorySerialNum) + { + // viewer did some changes to inventory that were not saved yet. + LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; + object->mInventorySerialNum = ft->mSerial; + } std::string unclean_filename; msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); @@ -2962,9 +2973,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS { LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; LLViewerObject* object = NULL; - if(ft && (0 == error_code) && - (object = gObjectList.findObject(ft->mTaskID))) + + if (ft + && (0 == error_code) + && (object = gObjectList.findObject(ft->mTaskID)) + && ft->mSerial >= object->mInventorySerialNum) { + object->mInventorySerialNum = ft->mSerial; if (object->loadTaskInvFile(ft->mFilename)) { @@ -2995,7 +3010,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS } else { - // This Occurs When to requests were made, and the first one + // This Occurs When two requests were made, and the first one // has already handled it. LL_DEBUGS() << "Problem loading task inventory. Return code: " << error_code << LL_ENDL; @@ -4637,7 +4652,7 @@ S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID return retval; } -S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer) { S32 retval = 0; const LLTextureEntry *tep = getTE(te); @@ -4647,13 +4662,14 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri return 0; } - retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams); + setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); + setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); + + retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams, isInitFromServer); LL_DEBUGS("Material") << "Changing material params for te " << (S32)te << ", object " << mID << " (" << retval << ")" << LL_ENDL; - setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); - setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); refreshMaterials(); return retval; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 05c87c153b..db2749f413 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -330,7 +330,7 @@ public: /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); /*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); - /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); + /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer); // Used by Materials update functions to properly kick off rebuilds // of VBs etc when materials updates require changes. diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 2c3067cd3a..f52c82dab7 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -60,6 +60,7 @@ #include "llfeaturemanager.h" #include "llviewernetwork.h" #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llsdserialize.h" #include "llcorehttputil.h" namespace LLStatViewer @@ -599,8 +600,10 @@ void send_stats() body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames"); body["MinimalSkin"] = false; - + LLViewerStats::getInstance()->addToMessage(body); + + LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, "Statistics posted to sim", "Failed to post statistics to sim"); LLViewerStats::instance().getRecording().resume(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index db949437a7..e0932ec36e 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -160,6 +160,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; const S32 MORPH_MASK_REQUESTED_DISCARD = 0; +const F32 MAX_STANDOFF_FROM_ORIGIN = 3; +const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32; + // Discard level at which to switch to baked textures // Should probably be 4 or 3, but didn't want to change it while change other logic - SJB const S32 SWITCH_TO_BAKED_DISCARD = 5; @@ -2132,7 +2135,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) // animate the character // store off last frame's root position to be consistent with camera position - LLVector3 root_pos_last = mRoot->getWorldPosition(); + mLastRootPos = mRoot->getWorldPosition(); BOOL detailed_update = updateCharacter(agent); static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false); @@ -2150,7 +2153,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) idleUpdateWindEffect(); } - idleUpdateNameTag( root_pos_last ); + idleUpdateNameTag( mLastRootPos ); idleUpdateRenderCost(); } @@ -6080,10 +6083,10 @@ void LLVOAvatar::getOffObject() { return; } - + LLViewerObject* sit_object = (LLViewerObject*)getParent(); - if (sit_object) + if (sit_object) { stopMotionFromSource(sit_object->getID()); LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE); @@ -6100,9 +6103,19 @@ void LLVOAvatar::getOffObject() } // assumes that transform will not be updated with drawable still having a parent + // or that drawable had no parent from the start LLVector3 cur_position_world = mDrawable->getWorldPosition(); LLQuaternion cur_rotation_world = mDrawable->getWorldRotation(); + if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN + && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN + || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE)) + { + // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent + // restore coordinates from cache + cur_position_world = mLastRootPos; + } + // set *local* position based on last *world* position, since we're unparenting the avatar mDrawable->mXform.setPosition(cur_position_world); mDrawable->mXform.setRotation(cur_rotation_world); @@ -6278,6 +6291,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) BOOL LLVOAvatar::isVisible() const { return mDrawable.notNull() + && (!mOrphaned || isSelf()) && (mDrawable->isVisible() || mIsDummy); } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1c3f4f2aa7..5b4379165a 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -869,6 +869,8 @@ public: private: // set this property only with LLVOAvatar::sitDown method BOOL mIsSitting; + // position backup in case of missing data + LLVector3 mLastRootPos; /** Hierarchy ** ** diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 267061b83d..19d61f6e33 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) +{ + bool regen_faces = false; + + LLVolume *old_volumep, *new_volumep; + F32 old_lod, new_lod; + S32 old_num_faces, new_num_faces; + + old_volumep = getVolume(); + old_lod = old_volumep->getDetail(); + old_num_faces = old_volumep->getNumFaces(); + old_volumep = NULL; + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); + const LLVolumeParams &volume_params = getVolume()->getParams(); + setVolume(volume_params, 0); + } + + new_volumep = getVolume(); + new_lod = new_volumep->getDetail(); + new_num_faces = new_volumep->getNumFaces(); + new_volumep = NULL; + + if ((new_lod != old_lod) || mSculptChanged) + { + compiled = TRUE; + sNumLODChanges += new_num_faces; + + if ((S32)getNumTEs() != getVolume()->getNumFaces()) + { + setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. + } + + drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); + regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs(); + if (regen_faces) + { + regenFaces(); + } + + if (mSculptChanged) + { //changes in sculpt maps can thrash an object bounding box without + //triggering a spatial group bounding box update -- force spatial group + //to update bounding boxes + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->unbound(); + } + } + } + } + + return regen_faces; +} + BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES); @@ -1664,83 +1724,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - if (mVolumeChanged || mFaceMappingChanged ) + if (mVolumeChanged || mFaceMappingChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - compiled = TRUE; + bool was_regen_faces = false; if (mVolumeChanged) { - LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); + was_regen_faces = lodOrSculptChanged(drawable, compiled); drawable->setState(LLDrawable::REBUILD_VOLUME); } - + else if (mSculptChanged || mLODChanged) { + compiled = TRUE; + was_regen_faces = lodOrSculptChanged(drawable, compiled); + } + + if (!was_regen_faces) { LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); regenFaces(); - genBBoxes(FALSE); } + + genBBoxes(FALSE); } - else if ((mLODChanged) || (mSculptChanged)) + else if (mLODChanged || mSculptChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - - LLVolume *old_volumep, *new_volumep; - F32 old_lod, new_lod; - S32 old_num_faces, new_num_faces ; - - old_volumep = getVolume(); - old_lod = old_volumep->getDetail(); - old_num_faces = old_volumep->getNumFaces() ; - old_volumep = NULL ; - - { - LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); - } - - new_volumep = getVolume(); - new_lod = new_volumep->getDetail(); - new_num_faces = new_volumep->getNumFaces() ; - new_volumep = NULL ; - - if ((new_lod != old_lod) || mSculptChanged) - { - compiled = TRUE; - sNumLODChanges += new_num_faces ; - - if((S32)getNumTEs() != getVolume()->getNumFaces()) - { - setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. - } - - drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() - - { - LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); - if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs()) - { - regenFaces(); - } - genBBoxes(FALSE); - - if (mSculptChanged) - { //changes in sculpt maps can thrash an object bounding box without - //triggering a spatial group bounding box update -- force spatial group - //to update bounding boxes - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->unbound(); - } - } - } - } - + compiled = TRUE; + lodOrSculptChanged(drawable, compiled); genBBoxes(FALSE); } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local @@ -2010,7 +2022,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM LLTextureEntry* texture_entry = pVol->getTE(te); if (texture_entry && (texture_entry->getMaterialID() == pMaterialID)) { - pVol->setTEMaterialParams(te, pMaterialParams); + pVol->setTEMaterialParams(te, pMaterialParams, FALSE); } } } @@ -2081,7 +2093,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture) for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) { LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); - LLViewerObject::setTEMaterialParams(it->first, it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE); } //clear wait-list @@ -2158,7 +2170,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture) for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) { LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); - LLViewerObject::setTEMaterialParams(it->first, it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE); } //clear wait-list @@ -2167,7 +2179,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture) return 0 != new_material.size(); } -S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer) { LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams); @@ -2264,7 +2276,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa } } - S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial); + S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer); LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" ) @@ -4163,7 +4175,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } //build matrix palette - static const size_t kMaxJoints = 64; + static const size_t kMaxJoints = 52; LLMatrix4a mp[kMaxJoints]; LLMatrix4* mat = (LLMatrix4*) mp; @@ -4174,6 +4186,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); if (!joint) { + // Fall back to a point inside the avatar if mesh is + // rigged to an unknown joint. joint = avatar->getJoint("mPelvis"); } if (joint) @@ -4220,8 +4234,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons wght[k] = w - floorf(w); scale += wght[k]; } - - wght *= 1.f/scale; + // This is enforced in unpackVolumeFaces() + llassert(scale>0.f); + wght *= 1.f / scale; for (U32 k = 0; k < 4; k++) { @@ -4229,9 +4244,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLMatrix4a src; // Insure ref'd bone is in our clamped array of mats - llassert(idx[k] < kMaxJoints); - // clamp k to kMaxJoints to avoid reading garbage off stack in release - src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w); + // clamp idx to maxJoints to avoid reading garbage off stack in release + S32 index = llclamp((S32)idx[k],(S32)0,(S32)kMaxJoints-1); + src.setMul(mp[index], w); final_mat.add(src); } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index bbaca316b0..ff7438ac09 100755 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -192,7 +192,7 @@ public: static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te); - /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); + /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer); /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s); /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t); @@ -339,6 +339,10 @@ protected: void cleanUpMediaImpls(); void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; void removeMediaImpl(S32 texture_index) ; + +private: + bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled); + public: static S32 getRenderComplexityMax() {return mRenderComplexity_last;} diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index bfae142812..837b30586b 100755 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -383,6 +383,7 @@ void LLWorldMap::reloadItems(bool force) LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT); LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT); LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT); } } diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml index aa6bc53672..299322001b 100755 --- a/indra/newview/skins/default/xui/da/menu_viewer.xml +++ b/indra/newview/skins/default/xui/da/menu_viewer.xml @@ -37,7 +37,7 @@ <menu_item_separator/> <menu_item_call label="Profil for sted" name="Place Profile"/> <menu_item_call label="Om land" name="About Land"/> - <menu_item_call label="Region/Estate" name="Region/Estate"/> + <menu_item_call label="Region/Estate" name="RegionEstate"/> <menu_item_call label="Køb dette land" name="Buy Land"/> <menu_item_call label="Mit land" name="My Land"/> <menu label="Vis" name="LandShow"> diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 33b876bdb9..aad3b9d062 100755 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1311,9 +1311,6 @@ Prøv igen om lidt. <notification name="NoValidCircuit"> Ingen gyldig kode for kredsløb. </notification> - <notification name="NoValidTimestamp"> - Ikke et gyldigt klokkeslæt. - </notification> <notification name="NoPendingConnection"> Kunne ikke skabe fast forbindelse. </notification> diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 1924ff4ec3..956530c990 100755 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Fliegen" name="Fly"/> <menu_item_check label="Immer rennen" name="Always Run"/> <menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/> - <menu_item_call label="Gehen/Rennen/Fliegen..." name="Walk / run / fly"/> + <menu_item_call label="Gehen/Rennen/Fliegen..." name="WalkRunFly"/> </menu> <menu label="Status" name="Status"> <menu_item_check label="Abwesend" name="Away"/> @@ -64,7 +64,7 @@ <menu_item_call label="Foto" name="Take Snapshot"/> <menu_item_call label="Ortsprofil" name="Place Profile"/> <menu_item_call label="Landinformationen" name="About Land"/> - <menu_item_call label="Region/Grundbesitz" name="Region/Estate"/> + <menu_item_call label="Region/Grundbesitz" name="RegionEstate"/> <menu_item_call label="Mein Landbesitz..." name="My Land"/> <menu_item_call label="Dieses Land kaufen" name="Buy Land"/> <menu label="Anzeigen" name="LandShow"> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 0b1c18cd51..fa7db0a8a3 100755 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2802,9 +2802,6 @@ Versuchen Sie es in einigen Minuten erneut. <notification name="NoValidCircuit"> Kein gültiger Verbindungscode. </notification> - <notification name="NoValidTimestamp"> - Kein gültiger Zeitstempel. - </notification> <notification name="NoPendingConnection"> Verbindung kann nicht hergestellt werden. </notification> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 60f36770bb..ec87b3684e 100755 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -43,6 +43,14 @@ top_pad="5" height="25" width="180" /> + <button + follows="left|top" + label="Check for updates" + name="update_btn" + left_pad="70" + top_delta="0" + height="25" + width="180" /> </panel> <panel border="true" diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 90d45d5ebc..edf028bf60 100755 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -2013,7 +2013,7 @@ Only large parcels can be listed in search. name="AllowedText" top="0" width="230"> - Allowed Residents + Allowed Residents ([COUNT]) </text> <name_list column_padding="0" @@ -2062,7 +2062,7 @@ Only large parcels can be listed in search. name="BanCheck" top="0" width="200"> - Banned Residents + Banned Residents ([COUNT]) </text> <name_list column_padding="0" diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml index 1f2fe62b3c..126e3aac48 100755 --- a/indra/newview/skins/default/xui/en/floater_bumps.xml +++ b/indra/newview/skins/default/xui/en/floater_bumps.xml @@ -7,7 +7,7 @@ help_topic="floater_bumps" save_rect="true" title="BUMPS, PUSHES & HITS" - width="400"> + width="420"> <floater.string name="none_detected"> None detected @@ -34,7 +34,7 @@ </floater.string> <floater.string name="timeStr"> - [[hour,datetime,slt]:[min,datetime,slt]] + [[hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt]] </floater.string> <scroll_list draw_border="false" @@ -45,5 +45,5 @@ multi_select="true" name="bump_list" top="20" - width="388" /> + width="408" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_experiences.xml b/indra/newview/skins/default/xui/en/floater_experiences.xml index 70e7507907..442da887c5 100644 --- a/indra/newview/skins/default/xui/en/floater_experiences.xml +++ b/indra/newview/skins/default/xui/en/floater_experiences.xml @@ -12,7 +12,7 @@ name="floater_experiences" save_rect="true" single_instance="true" - reuse_instance="false" + bg_opaque_color="0 0.5 0 0.3" title="EXPERIENCES"> <tab_container diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 3deb8f7233..61002bf1b5 100755 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -565,14 +565,6 @@ <menu_item_call label="Delete" layout="topleft" - name="Remove Link"> - <menu_item_call.on_click - function="Inventory.DoToSelected" - parameter="delete" /> - </menu_item_call> - <menu_item_call - label="Delete" - layout="topleft" name="Delete"> <menu_item_call.on_click function="Inventory.DoToSelected" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index e91eea04d1..73ca7c529d 100755 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -108,6 +108,12 @@ function="Floater.Show" parameter="sl_about" /> </menu_item_call> + <menu_item_call + label="Check for Updates" + name="Check for Updates"> + <menu_item_call.on_click + function="Advanced.CheckViewerUpdates"/> + </menu_item_call> </menu> <menu_item_check label="Show Debug Menu" diff --git a/indra/newview/skins/default/xui/en/menu_url_email.xml b/indra/newview/skins/default/xui/en/menu_url_email.xml new file mode 100644 index 0000000000..6467fe5c90 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_email.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Email Popup"> + <menu_item_call + label="Compose Email in an External client" + layout="topleft" + name="email_open_external"> + <menu_item_call.on_click + function="Url.OpenExternal" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy Email to clipboard" + layout="topleft" + name="email_copy"> + <menu_item_call.on_click + function="Url.CopyLabel" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 52fcfba79d..f22986438c 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -134,7 +134,7 @@ </menu_item_call> <menu_item_call label="Walk / run / fly..." - name="Walk / run / fly"> + name="WalkRunFly"> <menu_item_call.on_click function="Floater.ToggleOrBringToFront" parameter="moveview" /> @@ -502,7 +502,7 @@ </menu_item_call> <menu_item_call label="Region / Estate" - name="Region/Estate"> + name="RegionEstate"> <menu_item_call.on_click function="Floater.Show" parameter="region_info" /> @@ -1431,7 +1431,7 @@ function="Floater.Show" parameter="bumps" /> </menu_item_call> - <menu_item_separator/> + <menu_item_separator/> <menu_item_call label="About [APP_NAME]" name="About Second Life"> @@ -1439,6 +1439,12 @@ function="Floater.Show" parameter="sl_about" /> </menu_item_call> + <menu_item_call + label="Check for Updates" + name="Check for Updates"> + <menu_item_call.on_click + function="Advanced.CheckViewerUpdates"/> + </menu_item_call> </menu> <menu create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 66b52c586f..f79e8103b6 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -819,6 +819,33 @@ If you no longer wish to have these abilities granted to this role, disable them notext="Cancel" yestext="Eject"/> </notification> + + <notification + icon="alertmodal.tga" + name="BanGroupMemberWarning" + type="alertmodal"> + You are about to ban [AVATAR_NAME] from the group. + <tag>group</tag> + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm banning a participant from group" + name="okcancelignore" + notext="Cancel" + yestext="Ban"/> + </notification> + <notification + icon="alertmodal.tga" + name="BanGroupMembersWarning" + type="alertmodal"> + You are about to ban [COUNT] members from group. + <tag>group</tag> + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm banning multiple members from group" + name="okcancelignore" + notext="Cancel" + yestext="Ban"/> + </notification> <notification icon="alertmodal.tga" @@ -3892,6 +3919,53 @@ see [[INFO_URL] Information about this update] name="okbutton" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="UpdateDownloadInProgress" + type="alertmodal"> +An update is available! +It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="UpdateDownloadComplete" + type="alertmodal"> +An update was downloaded. It will be installed during restart. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="UpdateCheckError" + type="alertmodal"> +An error occured while checking for update. +Please try again later. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="UpdateViewerUpToDate" + type="alertmodal"> +Your viewer is up to date! +If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> <notification icon="alertmodal.tga" @@ -4217,6 +4291,21 @@ You have reached your maximum number of groups. Please leave some group before j <notification icon="alert.tga" + name="GroupLimitInfo" + type="alert"> +The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium] +accounts is [MAX_PREMIUM]. +If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more. + +[https://secondlife.com/my/account/membership.php Upgrade today!] + <tag>group</tag> + <usetemplate + name="okbutton" + yestext="Close"/> + </notification> + + <notification + icon="alert.tga" name="KickUser" type="alert"> <tag>win</tag> @@ -7029,15 +7118,6 @@ No valid circuit code. <notification icon="notify.tga" - name="NoValidTimestamp" - persist="true" - type="notify"> - <tag>fail</tag> -No valid timestamp. - </notification> - - <notification - icon="notify.tga" name="NoPendingConnection" persist="true" type="notify"> diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml index c76b958eda..c357f9e7d5 100644 --- a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml +++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml @@ -47,19 +47,19 @@ height="12" follows="top|left"> </text> - <scroll_list + <name_list draw_heading="false" left="3" width="225" height="75" follows="all" name="experience_list"> - <columns + <name_list.columns width="225" user_resize="false" name="experience_name" label="Name"/> - </scroll_list> + </name_list> <button layout="topleft" follows="top|right" diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index 0518688f45..0a85477bf4 100755 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -21,7 +21,7 @@ </panel.string> <panel.string name="ItemcountUnknown"> - + Fetched [ITEM_COUNT] Items [FILTER] </panel.string> <text type="string" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 2d4665c128..4fb8b9a67f 100755 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M left="3" use_ellipses="true" name="groupcount"> - You belong to [COUNT] groups, and can join [REMAINING] more. + You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Want more?] </text> <group_list allow_select="true" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 2e778014c5..3e96160834 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -216,7 +216,7 @@ control_name="QAMode" follows="top|left" height="15" - label="Show Developer Menu" + label="Show Develop Menu" layout="topleft" left="30" name="show_develop_menu_check" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 1e9a1aa27c..b201e071ef 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -270,7 +270,7 @@ value="1" /> --> <combo_box.item - label="Download and install updates manually" + label="I will download and install updates manually" name="Install_manual" value="0" /> </combo_box> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b7e0cff146..4eb6e2462d 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -238,6 +238,7 @@ Please try logging in again in a minute.</string> <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string> <string name="TooltipTooManyWearables">You can't wear a folder containing more than [AMOUNT] items. You can change this limit in Advanced > Show Debug Settings > WearFolderLimit.</string> <string name="TooltipPrice" value="L$[AMOUNT]: "/> + <string name="TooltipSLIcon">This links to a page on the official SecondLife.com or LindenLab.com domain.</string> <string name="TooltipOutboxDragToWorld">You can't rez items from the Marketplace Listings folder</string> <string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string> @@ -277,6 +278,7 @@ Please try logging in again in a minute.</string> <string name="TooltipMapUrl">Click to view this location on a map</string> <string name="TooltipSLAPP">Click to run the secondlife:// command</string> <string name="CurrentURL" value=" CurrentURL: [CurrentURL]" /> + <string name="TooltipEmail">Click to compose an email</string> <!-- text for SLURL labels --> <string name="SLurlLabelTeleport">Teleport to</string> diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index 5118171d80..f6ebb498ec 100755 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Volar" name="Fly"/> <menu_item_check label="Correr siempre" name="Always Run"/> <menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/> - <menu_item_call label="Caminar / Correr / Volar..." name="Walk / run / fly"/> + <menu_item_call label="Caminar / Correr / Volar..." name="WalkRunFly"/> </menu> <menu label="Estado" name="Status"> <menu_item_check label="Ausente" name="Away"/> @@ -63,7 +63,7 @@ <menu_item_call label="Foto" name="Take Snapshot"/> <menu_item_call label="Perfil del lugar" name="Place Profile"/> <menu_item_call label="Acerca del terreno" name="About Land"/> - <menu_item_call label="Región/Estado" name="Region/Estate"/> + <menu_item_call label="Región/Estado" name="RegionEstate"/> <menu_item_call label="Mis terrenos..." name="My Land"/> <menu_item_call label="Comprar este terreno" name="Buy Land"/> <menu label="Mostrar" name="LandShow"> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 9578e1b863..1e367b33fc 100755 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -2796,9 +2796,6 @@ Por favor, vuelve a intentarlo en unos momentos. <notification name="NoValidCircuit"> Circuito de código inválido. </notification> - <notification name="NoValidTimestamp"> - Fecha inválida. - </notification> <notification name="NoPendingConnection"> No se puede crear la conexión. </notification> diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index 33b2ba6982..788cdbf856 100755 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Voler" name="Fly"/> <menu_item_check label="Toujours courir" name="Always Run"/> <menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/> - <menu_item_call label="Marcher / Courir / Voler..." name="Walk / run / fly"/> + <menu_item_call label="Marcher / Courir / Voler..." name="WalkRunFly"/> </menu> <menu label="Statut" name="Status"> <menu_item_check label="Absent" name="Away"/> @@ -64,7 +64,7 @@ <menu_item_call label="Photo" name="Take Snapshot"/> <menu_item_call label="Profil du lieu" name="Place Profile"/> <menu_item_call label="À propos du terrain" name="About Land"/> - <menu_item_call label="Région/Domaine" name="Region/Estate"/> + <menu_item_call label="Région/Domaine" name="RegionEstate"/> <menu_item_call label="Mes terrains..." name="My Land"/> <menu_item_call label="Acheter ce terrain" name="Buy Land"/> <menu label="Afficher" name="LandShow"> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index f13a80fe61..29e6fe1979 100755 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2788,9 +2788,6 @@ Veuillez réessayer dans quelques minutes. <notification name="NoValidCircuit"> Aucun code de circuit valide. </notification> - <notification name="NoValidTimestamp"> - Timestamp non valide. - </notification> <notification name="NoPendingConnection"> Impossible de créer la connexion en attente. </notification> diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml index 40082cb265..2b8249c8a9 100755 --- a/indra/newview/skins/default/xui/fr/panel_login.xml +++ b/indra/newview/skins/default/xui/fr/panel_login.xml @@ -1,9 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <panel name="panel_login"> <panel.string name="forgot_password_url">http://secondlife.com/account/request.php?lang=fr</panel.string> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=fr - </panel.string> <layout_stack name="ui_stack"> <layout_panel name="ui_container"> <combo_box label="Nom d'utilisateur" name="username_combo" tool_tip="Nom d'utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/> diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index 3f4c370ccd..18ddad5ee8 100755 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Vola" name="Fly"/> <menu_item_check label="Corri sempre" name="Always Run"/> <menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/> - <menu_item_call label="Cammina / corri / vola..." name="Walk / run / fly"/> + <menu_item_call label="Cammina / corri / vola..." name="WalkRunFly"/> </menu> <menu label="Stato" name="Status"> <menu_item_check label="Assente" name="Away"/> @@ -64,7 +64,7 @@ <menu_item_call label="Istantanea" name="Take Snapshot"/> <menu_item_call label="Profilo del luogo" name="Place Profile"/> <menu_item_call label="Informazioni sul terreno" name="About Land"/> - <menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/> + <menu_item_call label="Regione/proprietà immobiliare" name="RegionEstate"/> <menu_item_call label="Terreni posseduti..." name="My Land"/> <menu_item_call label="Acquista questo terreno" name="Buy Land"/> <menu label="Mostra" name="LandShow"> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 06f2b70dcf..61131b09c3 100755 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2793,9 +2793,6 @@ Riprova tra qualche istante. <notification name="NoValidCircuit"> Nessun codice circuito valido. </notification> - <notification name="NoValidTimestamp"> - Nessuna data/timestamp valido. - </notification> <notification name="NoPendingConnection"> Impossibile creare la connessione in sospeso. </notification> diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index 3f756c5f94..0384dc1efc 100755 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="飛ぶ" name="Fly"/> <menu_item_check label="常に走る" name="Always Run"/> <menu_item_call label="私のアニメーションを停止する" name="Stop Animating My Avatar"/> - <menu_item_call label="歩行/走行/飛行..." name="Walk / run / fly"/> + <menu_item_call label="歩行/走行/飛行..." name="WalkRunFly"/> </menu> <menu label="ログイン" name="Status"> <menu_item_check label="一時退席中" name="Away"/> @@ -64,7 +64,7 @@ <menu_item_call label="スナップショット" name="Take Snapshot"/> <menu_item_call label="場所のプロフィール" name="Place Profile"/> <menu_item_call label="土地情報" name="About Land"/> - <menu_item_call label="地域 / 不動産" name="Region/Estate"/> + <menu_item_call label="地域 / 不動産" name="RegionEstate"/> <menu_item_call label="保有地..." name="My Land"/> <menu_item_call label="この土地を購入" name="Buy Land"/> <menu label="表示" name="LandShow"> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index 694f38467e..5f0ce7a73b 100755 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2836,9 +2836,6 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ <notification name="NoValidCircuit"> 回路コードが無効です。 </notification> - <notification name="NoValidTimestamp"> - タイムスタンプが無効です。 - </notification> <notification name="NoPendingConnection"> 接続を生成できません。 </notification> diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index ef3fe71945..6fd498eea8 100755 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -33,7 +33,7 @@ <menu_item_call label="Zrób zdjęcie" name="Take Snapshot"/> <menu_item_call label="Profil miejsca" name="Place Profile"/> <menu_item_call label="O posiadłości" name="About Land"/> - <menu_item_call label="Region/Majątek" name="Region/Estate"/> + <menu_item_call label="Region/Majątek" name="RegionEstate"/> <menu_item_call label="Moje posiadłości" name="My Land"/> <menu_item_call label="Kup posiadłość" name="Buy Land"/> <menu label="Pokaż" name="LandShow"> diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 62fda0d601..c4a65d92b4 100755 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2368,9 +2368,6 @@ Spróbuj ponowanie za kilka minut. <notification name="NoValidCircuit"> Nieważny obwód kodowania. </notification> - <notification name="NoValidTimestamp"> - Niewłaściwy czas zapisu. - </notification> <notification name="NoPendingConnection"> Brak możliwości wykonania połączenia. </notification> diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index 9b3b6077ed..3d5d9eccc6 100755 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Voar" name="Fly"/> <menu_item_check label="Correr sempre" name="Always Run"/> <menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/> - <menu_item_call label="Andar/correr/voar..." name="Walk / run / fly"/> + <menu_item_call label="Andar/correr/voar..." name="WalkRunFly"/> </menu> <menu label="Status" name="Status"> <menu_item_check label="Ausente" name="Away"/> @@ -64,7 +64,7 @@ <menu_item_call label="Foto" name="Take Snapshot"/> <menu_item_call label="Perfil da região" name="Place Profile"/> <menu_item_call label="Sobre terrenos" name="About Land"/> - <menu_item_call label="Região/Propriedade" name="Region/Estate"/> + <menu_item_call label="Região/Propriedade" name="RegionEstate"/> <menu_item_call label="Meus terrenos..." name="My Land"/> <menu_item_call label="Comprar este terreno" name="Buy Land"/> <menu label="Mostrar" name="LandShow"> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index 29b85d9e97..a264495404 100755 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2777,9 +2777,6 @@ Por favor, tente novamente em alguns instantes. <notification name="NoValidCircuit"> Código de circuito inválido. </notification> - <notification name="NoValidTimestamp"> - Hora inválida. - </notification> <notification name="NoPendingConnection"> Impossível criar a conexão pendente. </notification> diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index 958105a70f..d22ca845f9 100755 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Полет" name="Fly"/> <menu_item_check label="Всегда бегать" name="Always Run"/> <menu_item_call label="Остановить анимацию" name="Stop Animating My Avatar"/> - <menu_item_call label="Ходьба / бег / полет..." name="Walk / run / fly"/> + <menu_item_call label="Ходьба / бег / полет..." name="WalkRunFly"/> </menu> <menu label="Статус" name="Status"> <menu_item_check label="Нет на месте" name="Away"/> @@ -62,7 +62,7 @@ <menu_item_call label="Снимок" name="Take Snapshot"/> <menu_item_call label="Профиль места" name="Place Profile"/> <menu_item_call label="О земле" name="About Land"/> - <menu_item_call label="Регион/землевладение" name="Region/Estate"/> + <menu_item_call label="Регион/землевладение" name="RegionEstate"/> <menu_item_call label="Мои владения..." name="My Land"/> <menu_item_call label="Купить эту землю" name="Buy Land"/> <menu label="Показать" name="LandShow"> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index acf3ce608f..70b9a25590 100755 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -2788,9 +2788,6 @@ http://secondlife.com/download. <notification name="NoValidCircuit"> Нет подходящего кода канала. </notification> - <notification name="NoValidTimestamp"> - Нет подходящей метки времени. - </notification> <notification name="NoPendingConnection"> Невозможно создать отложенное соединение. </notification> diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index cc8d8c895b..cea57011dd 100755 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="Uç" name="Fly"/> <menu_item_check label="Daima Koş" name="Always Run"/> <menu_item_call label="Beni Anime Etmeyi Durdur" name="Stop Animating My Avatar"/> - <menu_item_call label="Yürü / koş / uç..." name="Walk / run / fly"/> + <menu_item_call label="Yürü / koş / uç..." name="WalkRunFly"/> </menu> <menu label="Durum" name="Status"> <menu_item_check label="Uzakta" name="Away"/> @@ -62,7 +62,7 @@ <menu_item_call label="Anlık Görüntü" name="Take Snapshot"/> <menu_item_call label="Profili yerleştir" name="Place Profile"/> <menu_item_call label="Arazi hakkında" name="About Land"/> - <menu_item_call label="Bölge / Gayrimenkul" name="Region/Estate"/> + <menu_item_call label="Bölge / Gayrimenkul" name="RegionEstate"/> <menu_item_call label="Sahip olduğum arazi parçaları..." name="My Land"/> <menu_item_call label="Bu araziyi satın al" name="Buy Land"/> <menu label="Göster" name="LandShow"> diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml index a6c69c7ab2..df22251b3d 100755 --- a/indra/newview/skins/default/xui/tr/notifications.xml +++ b/indra/newview/skins/default/xui/tr/notifications.xml @@ -2788,9 +2788,6 @@ Lütfen biraz sonra tekrar deneyin. <notification name="NoValidCircuit"> Geçerli bir devre kodu yok. </notification> - <notification name="NoValidTimestamp"> - Geçerli bir zaman damgası yok. - </notification> <notification name="NoPendingConnection"> Beklemedeki bağlantı oluşturulamıyor. </notification> diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index e94f52a401..9572ad49d3 100755 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -15,7 +15,7 @@ <menu_item_check label="飛行" name="Fly"/> <menu_item_check label="以跑代步" name="Always Run"/> <menu_item_call label="停止我身上的動作" name="Stop Animating My Avatar"/> - <menu_item_call label="行走 / 跑步 / 飛行…" name="Walk / run / fly"/> + <menu_item_call label="行走 / 跑步 / 飛行…" name="WalkRunFly"/> </menu> <menu label="狀態" name="Status"> <menu_item_check label="離開" name="Away"/> @@ -62,7 +62,7 @@ <menu_item_call label="快照" name="Take Snapshot"/> <menu_item_call label="地點小檔案" name="Place Profile"/> <menu_item_call label="土地資料" name="About Land"/> - <menu_item_call label="地區/領地" name="Region/Estate"/> + <menu_item_call label="地區/領地" name="RegionEstate"/> <menu_item_call label="我所擁有的土地…" name="My Land"/> <menu_item_call label="購買這塊土地" name="Buy Land"/> <menu label="顯示" name="LandShow"> diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml index 179f01e90d..0a98101b60 100755 --- a/indra/newview/skins/default/xui/zh/notifications.xml +++ b/indra/newview/skins/default/xui/zh/notifications.xml @@ -2778,9 +2778,6 @@ SHA1 指紋:[MD5_DIGEST] <notification name="NoValidCircuit"> 沒有有效的線路碼。 </notification> - <notification name="NoValidTimestamp"> - 沒有有效的時間戳記。 - </notification> <notification name="NoPendingConnection"> 無法建立待通的連線。 </notification> diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index c152493a51..788955a1b2 100755 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -132,6 +132,7 @@ public: void startChecking(bool install_if_ready); void stopChecking(); + bool forceCheck(); bool isChecking(); LLUpdaterService::eUpdaterState getState(); @@ -266,6 +267,46 @@ void LLUpdaterServiceImpl::stopChecking() setState(LLUpdaterService::TERMINAL); } +bool LLUpdaterServiceImpl::forceCheck() +{ + if (!mIsDownloading && getState() != LLUpdaterService::CHECKING_FOR_UPDATE) + { + if (mIsChecking) + { + // Service is running, just reset the timer + if (mTimer.getStarted()) + { + mTimer.setTimerExpirySec(0); + setState(LLUpdaterService::CHECKING_FOR_UPDATE); + return true; + } + } + else if (!mChannel.empty() && !mVersion.empty()) + { + // one time check + bool has_install = checkForInstall(false); + if (!has_install) + { + std::string query_url = LLGridManager::getInstance()->getUpdateServiceURL(); + if (!query_url.empty()) + { + setState(LLUpdaterService::CHECKING_FOR_UPDATE); + mUpdateChecker.checkVersion(query_url, mChannel, mVersion, + mPlatform, mPlatformVersion, mUniqueId, + mWillingToTest); + return true; + } + else + { + LL_WARNS("UpdaterService") + << "No updater service defined for grid '" << LLGridManager::getInstance()->getGrid() << LL_ENDL; + } + } + } + } + return false; +} + bool LLUpdaterServiceImpl::isChecking() { return mIsChecking; @@ -402,9 +443,9 @@ bool LLUpdaterServiceImpl::checkForResume() void LLUpdaterServiceImpl::error(std::string const & message) { + setState(LLUpdaterService::TEMPORARY_ERROR); if(mIsChecking) { - setState(LLUpdaterService::TEMPORARY_ERROR); restartTimer(mCheckPeriod); } } @@ -449,8 +490,12 @@ void LLUpdaterServiceImpl::response(LLSD const & content) else { LL_WARNS("UpdaterService") << "Invalid update query response ignored; retry in " - << mCheckPeriod << " seconds" << LL_ENDL; - restartTimer(mCheckPeriod); + << mCheckPeriod << " seconds" << LL_ENDL; + setState(LLUpdaterService::TEMPORARY_ERROR); + if (mIsChecking) + { + restartTimer(mCheckPeriod); + } } } @@ -672,6 +717,11 @@ void LLUpdaterService::stopChecking() mImpl->stopChecking(); } +bool LLUpdaterService::forceCheck() +{ + return mImpl->forceCheck(); +} + bool LLUpdaterService::isChecking() { return mImpl->isChecking(); diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 0ddf24935b..95bbe1695c 100755 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -84,6 +84,7 @@ public: void startChecking(bool install_if_ready = false); void stopChecking(); + bool forceCheck(); bool isChecking(); eUpdaterState getState(); |