diff options
Diffstat (limited to 'indra')
77 files changed, 863 insertions, 390 deletions
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 3a219eb998..be54ed053b 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2121,22 +2121,13 @@ std::string zip_llsd(LLSD& data) deflateEnd(&strm); free(output); -#if 0 //verify results work with unzip_llsd - std::istringstream test(result); - LLSD test_sd; - if (!unzip_llsd(test_sd, test, result.size())) - { - LL_ERRS() << "Invalid compression result!" << LL_ENDL; - } -#endif - return result; } //decompress a block of LLSD from provided istream // not very efficient -- creats a copy of decompressed LLSD block in memory // and deserializes from that copy using LLSDSerialize -bool unzip_llsd(LLSD& data, std::istream& is, S32 size) +LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size) { U8* result = NULL; U32 cur_size = 0; @@ -2144,7 +2135,11 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) const U32 CHUNK = 65536; - U8 *in = new U8[size]; + U8 *in = new(std::nothrow) U8[size]; + if (!in) + { + return ZR_MEM_ERROR; + } is.read((char*) in, size); U8 out[CHUNK]; @@ -2167,7 +2162,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) inflateEnd(&strm); free(result); delete [] in; - return false; + return ZR_DATA_ERROR; } switch (ret) @@ -2179,7 +2174,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) inflateEnd(&strm); free(result); delete [] in; - return false; + return ZR_MEM_ERROR; break; } @@ -2188,14 +2183,13 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) U8* new_result = (U8*)realloc(result, cur_size + have); if (new_result == NULL) { - LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; inflateEnd(&strm); if (result) { free(result); } delete[] in; - return false; + return ZR_MEM_ERROR; } result = new_result; memcpy(result+cur_size, out, have); @@ -2209,33 +2203,50 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) if (ret != Z_STREAM_END) { free(result); - return false; + return ZR_DATA_ERROR; } //result now points to the decompressed LLSD block { - std::string res_str((char*) result, cur_size); + std::istringstream istr; + // Since we are using this for meshes, data we are dealing with tend to be large. + // So string can potentially fail to allocate, make sure this won't cause problems + try + { + std::string res_str((char*)result, cur_size); - std::string deprecated_header("<? LLSD/Binary ?>"); + std::string deprecated_header("<? LLSD/Binary ?>"); - if (res_str.substr(0, deprecated_header.size()) == deprecated_header) + if (res_str.substr(0, deprecated_header.size()) == deprecated_header) + { + res_str = res_str.substr(deprecated_header.size() + 1, cur_size); + } + cur_size = res_str.size(); + + istr.str(res_str); + } +#ifdef LL_WINDOWS + catch (std::length_error) + { + free(result); + return ZR_SIZE_ERROR; + } +#endif + catch (std::bad_alloc) { - res_str = res_str.substr(deprecated_header.size()+1, cur_size); + free(result); + return ZR_MEM_ERROR; } - cur_size = res_str.size(); - std::istringstream istr(res_str); - if (!LLSDSerialize::fromBinary(data, istr, cur_size)) { - LL_WARNS() << "Failed to unzip LLSD block" << LL_ENDL; free(result); - return false; - } + return ZR_PARSE_ERROR; + } } free(result); - return true; + return ZR_OK; } //This unzip function will only work with a gzip header and trailer - while the contents //of the actual compressed data is the same for either format (gzip vs zlib ), the headers diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 23a0c8cfb1..9f58d44fe7 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -814,8 +814,24 @@ public: } }; +class LL_COMMON_API LLUZipHelper : public LLRefCount +{ +public: + typedef enum e_zip_result + { + ZR_OK = 0, + ZR_MEM_ERROR, + ZR_SIZE_ERROR, + ZR_DATA_ERROR, + ZR_PARSE_ERROR, + } EZipRresult; + // return OK or reason for failure + static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size); +}; + //dirty little zip functions -- yell at davep LL_COMMON_API std::string zip_llsd(LLSD& data); -LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size); + + LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size); #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 00acfd1e4c..32e8ea9682 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -129,50 +129,32 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap sThreadID = threadp->mID; - try + // Run the user supplied function + do { - // Run the user supplied function - do + try { - try - { - threadp->run(); - } - catch (const LLContinueError &e) - { - LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName << - "' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL; - //output possible call stacks to log file. - LLError::LLCallStacks::print(); - - LOG_UNHANDLED_EXCEPTION("LLThread"); - continue; - } - break; - - } while (true); + threadp->run(); + } + catch (const LLContinueError &e) + { + LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName << + "' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL; + //output possible call stacks to log file. + LLError::LLCallStacks::print(); - //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL; + LOG_UNHANDLED_EXCEPTION("LLThread"); + continue; + } + break; - // We're done with the run function, this thread is done executing now. - //NB: we are using this flag to sync across threads...we really need memory barriers here - threadp->mStatus = STOPPED; - } - catch (std::bad_alloc) - { - threadp->mStatus = CRASHED; - LLMemory::logMemoryInfo(TRUE); + } while (true); - //output possible call stacks to log file. - LLError::LLCallStacks::print(); + //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL; - LL_ERRS("THREAD") << "Bad memory allocation in LLThread::staticRun() named '" << threadp->mName << "'!" << LL_ENDL; - } - catch (...) - { - threadp->mStatus = CRASHED; - CRASH_ON_UNHANDLED_EXCEPTION("LLThread"); - } + // We're done with the run function, this thread is done executing now. + //NB: we are using this flag to sync across threads...we really need memory barriers here + threadp->mStatus = STOPPED; delete threadp->mRecorder; threadp->mRecorder = NULL; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index cd7125197c..4a76d15096 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -748,7 +748,11 @@ U8* LLImageBase::allocateData(S32 size) { size = 0; mWidth = mHeight = 0; - mData = NULL; + if (mData) + { + deleteData(); // virtual + mData = NULL; + } } mDataSize = size; claimMem(mDataSize); @@ -775,6 +779,7 @@ U8* LLImageBase::reallocateData(S32 size) disclaimMem(mDataSize); mDataSize = size; claimMem(mDataSize); + mBadBufferAllocation = false; return mData; } diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index a5e546e977..97b543f3b6 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -163,7 +163,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() { sJpegErrorEncountered = false; clean(); - FILE *fp = fopen (mSrcFilename.c_str(), "rb"); + FILE *fp = LLFile::fopen(mSrcFilename, "rb"); if (fp == NULL) { setLastError("Unable to open file for reading", mSrcFilename); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 68694496bc..c40df009d8 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -369,19 +369,28 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename) else { U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size); - apr_size_t bytes_read = file_size; - apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - infile.close() ; - - if (s != APR_SUCCESS || (S32)bytes_read != file_size) + if (!data) { - FREE_MEM(LLImageBase::getPrivatePool(), data); - setLastError("Unable to read entire file"); + infile.close(); + setLastError("Out of memory", filename); res = false; } else { - res = validate(data, file_size); + apr_size_t bytes_read = file_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + infile.close(); + + if (s != APR_SUCCESS || (S32)bytes_read != file_size) + { + FREE_MEM(LLImageBase::getPrivatePool(), data); + setLastError("Unable to read entire file"); + res = false; + } + else + { + res = validate(data, file_size); + } } } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 8b73f0ae8e..24f46d720b 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2367,9 +2367,10 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) //input stream is now pointing at a zlib compressed block of LLSD //decompress block LLSD mdl; - if (!unzip_llsd(mdl, is, size)) + U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size); + if (uzip_result != LLUZipHelper::ZR_OK) { - LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, will probably fetch from sim again." << LL_ENDL; + LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; return false; } @@ -2676,11 +2677,17 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } } } + + if (!cacheOptimize()) + { + // Out of memory? + LL_WARNS() << "Failed to optimize!" << LL_ENDL; + mVolumeFaces.clear(); + return false; + } mSculptLevel = 0; // success! - cacheOptimize(); - return true; } @@ -2712,12 +2719,16 @@ void LLVolume::copyVolumeFaces(const LLVolume* volume) mSculptLevel = 0; } -void LLVolume::cacheOptimize() +bool LLVolume::cacheOptimize() { for (S32 i = 0; i < mVolumeFaces.size(); ++i) { - mVolumeFaces[i].cacheOptimize(); + if (!mVolumeFaces[i].cacheOptimize()) + { + return false; + } } + return true; } @@ -5173,7 +5184,7 @@ public: }; -void LLVolumeFace::cacheOptimize() +bool LLVolumeFace::cacheOptimize() { //optimize for vertex cache according to Forsyth method: // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html @@ -5184,7 +5195,7 @@ void LLVolumeFace::cacheOptimize() if (mNumVertices < 3) { //nothing to do - return; + return true; } //mapping of vertices to triangles and indices @@ -5193,8 +5204,16 @@ void LLVolumeFace::cacheOptimize() //mapping of triangles do vertices std::vector<LLVCacheTriangleData> triangle_data; - triangle_data.resize(mNumIndices/3); - vertex_data.resize(mNumVertices); + try + { + triangle_data.resize(mNumIndices / 3); + vertex_data.resize(mNumVertices); + } + catch (std::bad_alloc) + { + LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL; + return false; + } for (U32 i = 0; i < mNumIndices; i++) { //populate vertex data and triangle data arrays @@ -5306,7 +5325,8 @@ void LLVolumeFace::cacheOptimize() LLVector4a* pos = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size); if (pos == NULL) { - LL_ERRS("LLVOLUME") << "Allocation of positions vector[" << sizeof(LLVector4a) * 2 * num_verts + size << "] failed. " << LL_ENDL; + LL_WARNS("LLVOLUME") << "Allocation of positions vector[" << sizeof(LLVector4a) * 2 * num_verts + size << "] failed. " << LL_ENDL; + return false; } LLVector4a* norm = pos + num_verts; LLVector2* tc = (LLVector2*) (norm + num_verts); @@ -5317,7 +5337,9 @@ void LLVolumeFace::cacheOptimize() wght = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); if (wght == NULL) { - LL_ERRS("LLVOLUME") << "Allocation of weights[" << sizeof(LLVector4a) * num_verts << "] failed" << LL_ENDL; + ll_aligned_free<64>(pos); + LL_WARNS("LLVOLUME") << "Allocation of weights[" << sizeof(LLVector4a) * num_verts << "] failed" << LL_ENDL; + return false; } } @@ -5327,13 +5349,28 @@ void LLVolumeFace::cacheOptimize() binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); if (binorm == NULL) { - LL_ERRS("LLVOLUME") << "Allocation of binormals[" << sizeof(LLVector4a)*num_verts << "] failed" << LL_ENDL; + ll_aligned_free<64>(pos); + ll_aligned_free_16(wght); + LL_WARNS("LLVOLUME") << "Allocation of binormals[" << sizeof(LLVector4a)*num_verts << "] failed" << LL_ENDL; + return false; } } //allocate mapping of old indices to new indices std::vector<S32> new_idx; - new_idx.resize(mNumVertices, -1); + + try + { + new_idx.resize(mNumVertices, -1); + } + catch (std::bad_alloc) + { + ll_aligned_free<64>(pos); + ll_aligned_free_16(wght); + ll_aligned_free_16(binorm); + LL_WARNS("LLVOLUME") << "Resize failed: " << mNumVertices << LL_ENDL; + return false; + } S32 cur_idx = 0; for (U32 i = 0; i < mNumIndices; ++i) @@ -5379,6 +5416,7 @@ void LLVolumeFace::cacheOptimize() //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); //LL_INFOS() << result << LL_ENDL; + return true; } void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index bba691d243..a8089f3709 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -903,7 +903,7 @@ public: }; void optimize(F32 angle_cutoff = 2.f); - void cacheOptimize(); + bool cacheOptimize(); void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); @@ -1063,7 +1063,7 @@ public: void copyVolumeFaces(const LLVolume* volume); void copyFacesTo(std::vector<LLVolumeFace> &faces) const; void copyFacesFrom(const std::vector<LLVolumeFace> &faces); - void cacheOptimize(); + bool cacheOptimize(); private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 5a112b5432..abe0e46e5d 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -769,7 +769,7 @@ LLUUID LLAvatarNameCache::findIdByName(const std::string& name) // Legacy method LLUUID id; - if (gCacheName->getUUID(name, id)) + if (gCacheName && gCacheName->getUUID(name, id)) { return id; } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index db6d00bc2c..8fbb4f6b96 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1034,8 +1034,11 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { //no exact match found, get closest point const F32 epsilon = 1e-5f; weight_map::iterator iter_up = mSkinWeights.lower_bound(pos); - weight_map::iterator iter_down = ++iter_up; - + weight_map::iterator iter_down = iter_up; + if (iter_up != mSkinWeights.end()) + { + iter_down = ++iter_up; + } weight_map::iterator best = iter_up; F32 min_dist = (iter->first - pos).magVec(); @@ -1354,7 +1357,7 @@ bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) LLSD skin_data; - if (unzip_llsd(skin_data, is, size)) + if (LLUZipHelper::unzip_llsd(skin_data, is, size) == LLUZipHelper::ZR_OK) { mSkinInfo.fromLLSD(skin_data); return true; @@ -1375,7 +1378,7 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is) LLSD data; - if (unzip_llsd(data, is, size)) + if (LLUZipHelper::unzip_llsd(data, is, size) == LLUZipHelper::ZR_OK) { mPhysics.fromLLSD(data); updateHullCenters(); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 20cba68f84..89500dcc04 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -622,7 +622,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) } static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage"); -void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) +BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE); bool is_compressed = false; @@ -787,19 +787,33 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) llassert(prev_mip_data); llassert(cur_mip_size == bytes*4); #endif - U8* new_data = new U8[bytes]; + U8* new_data = new(std::nothrow) U8[bytes]; + if (!new_data) + { + stop_glerror(); + + if (prev_mip_data) + delete[] prev_mip_data; + if (cur_mip_data) + delete[] cur_mip_data; + + mGLTextureCreated = false; + return FALSE; + } + else + { #ifdef SHOW_ASSERT - llassert(prev_mip_data); - llassert(cur_mip_size == bytes*4); - llassert_always(new_data); + llassert(prev_mip_data); + llassert(cur_mip_size == bytes * 4); #endif - LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); - cur_mip_data = new_data; + LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); + cur_mip_data = new_data; #ifdef SHOW_ASSERT - cur_mip_size = bytes; + cur_mip_size = bytes; #endif + } } llassert(w > 0 && h > 0 && cur_mip_data); @@ -886,6 +900,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } stop_glerror(); mGLTextureCreated = true; + return TRUE; } BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) @@ -1355,8 +1370,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (mTexName != 0 && discard_level == mCurrentDiscardLevel) { // This will only be true if the size has not changed - setImage(data_in, data_hasmips); - return TRUE; + return setImage(data_in, data_hasmips); } U32 old_name = mTexName; @@ -1398,7 +1412,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ mCurrentDiscardLevel = discard_level; - setImage(data_in, data_hasmips); + if (!setImage(data_in, data_hasmips)) + { + stop_glerror(); + return FALSE; + } // Set texture options to our defaults. gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index ad2aea9067..2be54be062 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -105,7 +105,7 @@ public: S32 category = sMaxCategories-1); BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); void setImage(const LLImageRaw* imageraw); - void setImage(const U8* data_in, BOOL data_hasmips = FALSE); + BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE); BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 5048799854..f10301b42d 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1057,10 +1057,12 @@ LLVertexBuffer::~LLVertexBuffer() if (mFence) { + // Sanity check. We have weird crashes in this destructor (on delete). Yet mFence is disabled. + // TODO: mFence was added in scope of SH-2038, but was never enabled, consider removing mFence. + LL_ERRS() << "LLVertexBuffer destruction failed" << LL_ENDL; delete mFence; + mFence = NULL; } - - mFence = NULL; sVertexCount -= mNumVerts; sIndexCount -= mNumIndices; @@ -1930,7 +1932,21 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedVertexRegions[i]; S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); + if (mSize >= length + offset) + { + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*)mMappedData + offset); + } + else + { + GLint size = 0; + glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); + LL_WARNS() << "Attempted to map regions to a buffer that is too small, " + << "mapped size: " << mSize + << ", gl buffer size: " << size + << ", length: " << length + << ", offset: " << offset + << LL_ENDL; + } stop_glerror(); } @@ -1998,7 +2014,21 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedIndexRegions[i]; S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); + if (mIndicesSize >= length + offset) + { + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); + } + else + { + GLint size = 0; + glGetBufferParameterivARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); + LL_WARNS() << "Attempted to map regions to a buffer that is too small, " + << "mapped size: " << mIndicesSize + << ", gl buffer size: " << size + << ", length: " << length + << ", offset: " << offset + << LL_ENDL; + } stop_glerror(); } diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index 42726de0ad..15b6899d74 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -224,7 +224,7 @@ void LLBadge::draw() { LLView* owner_view = mOwner.get(); - if (owner_view) + if (owner_view && owner_view->isInVisibleChain()) { // // Calculate badge size based on label text diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index a4243ebfa1..a4dc5bcde1 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -190,31 +190,32 @@ bool LLUrlEntryBase::isWikiLinkCorrect(std::string url) std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const { - LLUriParser up(unescapeUrl(url)); + LLUriParser up(escapeUrl(url)); up.normalize(); std::string label; up.extractParts(); up.glueFirst(label); - return label; + return unescapeUrl(label); } std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const { - LLUriParser up(unescapeUrl(url)); + std::string escaped_url = escapeUrl(url); + LLUriParser up(escaped_url); std::string label; up.extractParts(); up.glueFirst(label, false); - size_t pos = url.find(label); + size_t pos = escaped_url.find(label); if (pos == std::string::npos) { return ""; } pos += label.size(); - return url.substr(pos); + return unescapeUrl(escaped_url.substr(pos)); } diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index fa6593267a..ba6fa1e2e9 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -212,7 +212,7 @@ 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) { @@ -223,33 +223,6 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL // 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((match_entry != mUrlEntryNoLink) && (match_entry != mUrlEntryHTTPLabel) && (match_entry !=mUrlEntrySLLabel) - && 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); @@ -257,12 +230,10 @@ 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), - url_label, - url_query, + match_entry->getLabel(url, cb), + match_entry->getQuery(url), match_entry->getTooltip(url), match_entry->getIcon(url), match_entry->getStyle(), diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 1a280661b9..9fa07d1d34 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -421,6 +421,11 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mKeyVirtualKey = 0; mhDC = NULL; mhRC = NULL; + + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) + { + mMouseVanish = TRUE; + } // Initialize the keyboard gKeyboard = new LLKeyboardWin32(); @@ -1096,7 +1101,14 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO mhInstance, NULL); - LL_INFOS("Window") << "window is created." << LL_ENDL ; + if (mWindowHandle) + { + LL_INFOS("Window") << "window is created." << LL_ENDL ; + } + else + { + LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; + } //----------------------------------------------------------------------- // Create GL drawing context @@ -1411,7 +1423,16 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO mhInstance, NULL); - LL_INFOS("Window") << "recreate window done." << LL_ENDL ; + + if (mWindowHandle) + { + LL_INFOS("Window") << "recreate window done." << LL_ENDL ; + } + else + { + // Note: if value is NULL GetDC retrieves the DC for the entire screen. + LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; + } if (!(mhDC = GetDC(mWindowHandle))) { @@ -1680,7 +1701,7 @@ void LLWindowWin32::showCursorFromMouseMove() void LLWindowWin32::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent) + if (!mHideCursorPermanent && mMouseVanish) { hideCursor(); mHideCursorPermanent = FALSE; @@ -2641,20 +2662,20 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } case WM_SETFOCUS: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); if (gDebugWindowProc) { LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; } + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); window_imp->mCallbacks->handleFocus(window_imp); return 0; case WM_KILLFOCUS: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS"); if (gDebugWindowProc) { LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; } + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS"); window_imp->mCallbacks->handleFocusLost(window_imp); return 0; @@ -2668,6 +2689,18 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; break; + + case WM_SETTINGCHANGE: + { + if (w_param == SPI_SETMOUSEVANISH) + { + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) + { + window_imp->mMouseVanish = TRUE; + } + } + } + break; } window_imp->mCallbacks->handlePauseWatchdog(window_imp); diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 059a008c45..d72623a6f4 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -214,6 +214,8 @@ protected: U32 mRawWParam; U32 mRawLParam; + BOOL mMouseVanish; + friend class LLWindowManager; }; diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index ac14c3dfaa..cdb98d26e4 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -5.1.1 +5.1.3 diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 90f06746c9..df30f46002 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -530,7 +530,7 @@ location="ATTACH_FACE_JAW" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="48" @@ -541,7 +541,7 @@ location="ATTACH_FACE_LEAR" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="49" @@ -552,7 +552,7 @@ location="ATTACH_FACE_REAR" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="50" @@ -563,7 +563,7 @@ location="ATTACH_FACE_LEYE" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="51" @@ -574,7 +574,7 @@ location="ATTACH_FACE_REYE" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="52" @@ -585,7 +585,7 @@ location="ATTACH_FACE_TONGUE" position="0.000 0.000 0.000" rotation="0 0 0" - visible_in_first_person="true"/> + visible_in_first_person="false"/> <attachment_point id="53" diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 8fe684ad79..f0b74e7439 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -1011,7 +1011,7 @@ void LLAvatarActions::toggleMute(const LLUUID& id, U32 flags) LLAvatarNameCache::get(id, &av_name); LLMuteList* mute_list = LLMuteList::getInstance(); - bool is_muted = mute_list->isMuted(id, LLMute::flagVoiceChat); + bool is_muted = mute_list->isMuted(id, flags); LLMute mute(id, av_name.getUserName(), LLMute::AGENT); if (!is_muted) diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index f5721fb348..eddc87efcd 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -242,27 +242,28 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) S32 chars_in_line = mMsgText->getRect().getWidth() / messageFont->getWidth("c"); S32 max_lines = notification["available_height"].asInteger() / (mMsgText->getTextPixelHeight() + 4); - S32 new_line_chars = std::count(messageText.begin(), messageText.end(), '\n'); - S32 lines_count = (messageText.size() - new_line_chars) / chars_in_line + new_line_chars + 1; + int lines = 0; + int chars = 0; - //Remove excessive chars if message is not fit in available height. MAINT-6891 - if(lines_count > max_lines) + //Remove excessive chars if message does not fit in available height. MAINT-6891 + std::string::iterator it; + for (it = messageText.begin(); it < messageText.end() && lines < max_lines; it++) { - while(lines_count > max_lines) + if (*it == '\n') + ++lines; + else + ++chars; + + if (chars >= chars_in_line) { - std::size_t nl_pos = messageText.rfind('\n'); - if (nl_pos != std::string::npos) - { - nl_pos = nl_pos > messageText.length() - chars_in_line? nl_pos : messageText.length() - chars_in_line; - messageText.erase(messageText.begin() + nl_pos, messageText.end()); - } - else - { - messageText.erase(messageText.end() - chars_in_line, messageText.end()); - } - new_line_chars = std::count(messageText.begin(), messageText.end(), '\n'); - lines_count = (messageText.size() - new_line_chars) / chars_in_line + new_line_chars; + chars = 0; + ++lines; } + } + + if (it < messageText.end()) + { + messageText.erase(it, messageText.end()); messageText += " ..."; } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index d614d612ff..5b4b7789b4 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -750,7 +750,7 @@ void LLFavoritesBarCtrl::updateButtons() return; } - if(mGetPrevItems) + if(mGetPrevItems && gInventory.isCategoryComplete(mFavoriteFolderId)) { for (LLInventoryModel::item_array_t::iterator it = mItems.begin(); it != mItems.end(); it++) { diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 7e92643b93..125a823e58 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -341,7 +341,7 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter) dirname = filename + "\\"; else mFiles.push_back(dirname + filename); - tptrw += filename.size(); + tptrw += wcslen(tptrw); } } } diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index 8bdb70a20d..b8f854feb3 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -89,20 +89,11 @@ BOOL LLFloaterAvatarRenderSettings::postBuild() LLFloater::postBuild(); mAvatarSettingsList = getChild<LLNameListCtrl>("render_settings_list"); mAvatarSettingsList->setRightMouseDownCallback(boost::bind(&LLFloaterAvatarRenderSettings::onAvatarListRightClick, this, _1, _2, _3)); - this->setVisibleCallback(boost::bind(&LLFloaterAvatarRenderSettings::removePicker, this)); getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterAvatarRenderSettings::onFilterEdit, this, _2)); return TRUE; } -void LLFloaterAvatarRenderSettings::removePicker() -{ - if(mPicker.get()) - { - mPicker.get()->closeFloater(); - } -} - void LLFloaterAvatarRenderSettings::draw() { if(mNeedsUpdate) @@ -263,8 +254,6 @@ void LLFloaterAvatarRenderSettings::onClickAdd(const LLSD& userdata) { root_floater->addDependentFloater(picker); } - - mPicker = picker->getHandle(); } void LLFloaterAvatarRenderSettings::callbackAvatarPicked(const uuid_vec_t& ids, S32 visual_setting) diff --git a/indra/newview/llfloateravatarrendersettings.h b/indra/newview/llfloateravatarrendersettings.h index 6790b24b90..00ee074f17 100644 --- a/indra/newview/llfloateravatarrendersettings.h +++ b/indra/newview/llfloateravatarrendersettings.h @@ -66,7 +66,6 @@ private: bool mNeedsUpdate; LLListContextMenu* mContextMenu; LLNameListCtrl* mAvatarSettingsList; - LLHandle<LLFloater> mPicker; std::string mNameFilter; }; diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp index 4fd5c0587a..2afd889609 100644 --- a/indra/newview/llfloatermediasettings.cpp +++ b/indra/newview/llfloatermediasettings.cpp @@ -171,8 +171,12 @@ void LLFloaterMediaSettings::onClose(bool app_quitting) void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable ) { if (sInstance->hasFocus()) return; - - sInstance->clearValues(editable); + + // Clear values + sInstance->mPanelMediaSettingsGeneral->clearValues(sInstance->mPanelMediaSettingsGeneral, editable, false /*don't update preview*/); + sInstance->mPanelMediaSettingsSecurity->clearValues(sInstance->mPanelMediaSettingsSecurity, editable); + sInstance->mPanelMediaSettingsPermissions->clearValues(sInstance->mPanelMediaSettingsPermissions, editable); + // update all panels with values from simulator sInstance->mPanelMediaSettingsGeneral-> initValues( sInstance->mPanelMediaSettingsGeneral, media_settings, editable ); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 5222637039..5de7ca5289 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1304,7 +1304,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() BOOL shaders = ctrl_shader_enable->get(); if (shaders) { - terrain_detail->setValue(1); terrain_detail->setEnabled(FALSE); terrain_text->setEnabled(FALSE); } diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index a446b767ac..66e832111b 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -100,6 +100,7 @@ LLFloaterSearch::LLFloaterSearch(const Params& key) : mCategoryPaths["events"] = "search/events"; mCategoryPaths["groups"] = "search/groups"; mCategoryPaths["wiki"] = "search/wiki"; + mCategoryPaths["land"] = "land"; mCategoryPaths["destinations"] = "destinations"; mCategoryPaths["classifieds"] = "classifieds"; } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 2869256d09..c9d664c7c4 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -1317,7 +1317,6 @@ void LLFloaterTools::getMediaState() std::string multi_media_info_str = LLTrans::getString("Multiple Media"); std::string media_title = ""; - mNeedMediaTitle = false; // update UI depending on whether "object" (prim or face) has media // and whether or not you are allowed to edit it. @@ -1335,17 +1334,12 @@ void LLFloaterTools::getMediaState() { // initial media title is the media URL (until we get the name) media_title = media_data_get.getHomeURL(); - - // kick off a navigate and flag that we need to update the title - navigateToTitleMedia( media_data_get.getHomeURL() ); - mNeedMediaTitle = true; } // else all faces might be empty. } else // there' re Different Medias' been set on on the faces. { media_title = multi_media_info_str; - mNeedMediaTitle = false; } getChildView("media_tex")->setEnabled(bool_has_media && editable); @@ -1362,7 +1356,6 @@ void LLFloaterTools::getMediaState() if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) { media_title = multi_media_info_str; - mNeedMediaTitle = false; } else { @@ -1371,10 +1364,6 @@ void LLFloaterTools::getMediaState() { // initial media title is the media URL (until we get the name) media_title = media_data_get.getHomeURL(); - - // kick off a navigate and flag that we need to update the title - navigateToTitleMedia( media_data_get.getHomeURL() ); - mNeedMediaTitle = true; } } @@ -1383,6 +1372,8 @@ void LLFloaterTools::getMediaState() getChildView("delete_media")->setEnabled(TRUE); getChildView("add_media")->setEnabled(editable); } + + navigateToTitleMedia(media_title); media_info->setText(media_title); // load values for media settings @@ -1472,16 +1463,31 @@ void LLFloaterTools::clearMediaSettings() // void LLFloaterTools::navigateToTitleMedia( const std::string url ) { - if ( mTitleMedia ) + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + if (url.empty() || multi_media_info_str == url) + { + // nothing to show + mNeedMediaTitle = false; + } + else if (mTitleMedia) { LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin(); - if ( media_plugin ) + + if ( media_plugin ) // Shouldn't this be after navigateTo creates plugin? { // if it's a movie, we don't want to hear it media_plugin->setVolume( 0 ); }; - mTitleMedia->navigateTo( url ); - }; + + // check if url changed or if we need a new media source + if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == NULL) + { + mTitleMedia->navigateTo( url ); + } + + // flag that we need to update the title (even if no request were made) + mNeedMediaTitle = true; + } } ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 8f586f7da6..ffff564ad4 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -102,8 +102,6 @@ public: void onClickBtnAddMedia(); void onClickBtnEditMedia(); void clearMediaSettings(); - void updateMediaTitle(); - void navigateToTitleMedia( const std::string url ); bool selectedMediaEditable(); void updateLandImpacts(); @@ -116,6 +114,8 @@ private: void refreshMedia(); void getMediaState(); void updateMediaSettings(); + void navigateToTitleMedia( const std::string url ); // navigate if changed + void updateMediaTitle(); static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); static void setObjectType( LLPCode pcode ); diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp index 4bab89ace2..803c80ac1a 100644 --- a/indra/newview/llfloatertwitter.cpp +++ b/indra/newview/llfloatertwitter.cpp @@ -404,13 +404,12 @@ void LLTwitterPhotoPanel::clearAndClose() void LLTwitterPhotoPanel::updateStatusTextLength(BOOL restore_old_status_text) { bool add_location = mLocationCheckbox->getValue().asBoolean(); - bool add_photo = mPhotoCheckbox->getValue().asBoolean(); // Restrict the status text length to Twitter's character limit LLTextEditor* status_text_box = dynamic_cast<LLTextEditor*>(mStatusTextBox); if (status_text_box) { - int max_status_length = 140 - (add_location ? 40 : 0) - (add_photo ? 40 : 0); + int max_status_length = 280 - (add_location ? 40 : 0); status_text_box->setMaxTextLength(max_status_length); if (restore_old_status_text) { diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index a4fce36783..8332443162 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -205,7 +205,7 @@ void LLInspectGroup::nameUpdatedCallback( { if (id == mGroupID) { - getChild<LLUICtrl>("group_name")->setValue( LLSD(name) ); + getChild<LLUICtrl>("group_name")->setValue(LLSD("<nolink>" + name + "</nolink>")); } // Otherwise possibly a request for an older inspector, ignore it diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 904bc29929..3acfaeb049 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -43,6 +43,7 @@ #include "llfloatermarketplacelistings.h" #include "llfloateroutfitphotopreview.h" #include "llfloatersidepanelcontainer.h" +#include "llsidepanelinventory.h" #include "llfloaterworldmap.h" #include "llfolderview.h" #include "llfriendcard.h" @@ -1828,11 +1829,24 @@ void LLItemBridge::gotoItem() LLInventoryObject *obj = getInventoryObject(); if (obj && obj->getIsLinkType()) { - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (active_panel) + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); + if (gInventory.isObjectDescendentOf(obj->getLinkedUUID(), inbox_id)) { - active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory && sidepanel_inventory->getInboxPanel()) + { + sidepanel_inventory->getInboxPanel()->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } + } + else + { + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) + { + active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } } + } } @@ -2199,8 +2213,24 @@ std::string LLFolderBridge::getLabelSuffix() const { return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); } - - return LLInvFVBridge::getLabelSuffix(); + std::string suffix = ""; + if(mShowDescendantsCount) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getUUID(), cat_array, item_array, TRUE); + S32 count = item_array.size(); + if(count > 0) + { + std::ostringstream oss; + oss << count; + LLStringUtil::format_map_t args; + args["[ITEMS_COUNT]"] = oss.str(); + suffix = " " + LLTrans::getString("InventoryItemsCount", args); + } + } + + return LLInvFVBridge::getLabelSuffix() + suffix; } LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index fd532c609c..fd5c0433b1 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -268,7 +268,8 @@ public: : LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE), - mIsLoading(false) + mIsLoading(false), + mShowDescendantsCount(false) {} BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); @@ -293,6 +294,8 @@ public: virtual std::string getLabelSuffix() const; virtual LLFontGL::StyleFlags getLabelStyle() const; + void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;} + virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); @@ -373,6 +376,7 @@ protected: bool mCallingCards; bool mWearables; bool mIsLoading; + bool mShowDescendantsCount; LLTimer mTimeSinceRequestStart; std::string mMessage; LLRootHandle<LLFolderBridge> mHandle; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 8b50e4248e..e056ccebee 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1178,7 +1178,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn int incoming_folder_depth = get_folder_levels(inv_cat); // Compute the nested folders level we're inserting ourselves in // Note: add 1 when inserting under a listing folder as we need to take the root listing folder in the count - int insertion_point_folder_depth = (root_folder ? get_folder_path_length(root_folder->getUUID(), dest_folder->getUUID()) + 1 : 0); + int insertion_point_folder_depth = (root_folder ? get_folder_path_length(root_folder->getUUID(), dest_folder->getUUID()) + 1 : 1); // Get the version folder: that's where the folders and items counts start from const LLViewerInventoryCategory * version_folder = (insertion_point_folder_depth >= 2 ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 054db2a3ec..6a1ec9f991 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -617,6 +617,11 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return LLUUID::null; } + if (!gMessageSystem) + { + return LLUUID::null; + } + // Add the category to the internal representation LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d610b920b9..93269db380 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -563,6 +563,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { setSelection(item_id, FALSE); } + updateFolderLabel(model_item->getParentUUID()); } ////////////////////////////// @@ -574,6 +575,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Don't process the item if it is the root if (old_parent) { + LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent->getViewModelItem()); LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); // Item has been moved. if (old_parent != new_parent) @@ -591,6 +593,7 @@ void LLInventoryPanel::modelChanged(U32 mask) setSelection(item_id, FALSE); } } + updateFolderLabel(model_item->getParentUUID()); } else { @@ -602,6 +605,10 @@ void LLInventoryPanel::modelChanged(U32 mask) // doesn't include trash). Just remove the item's UI. view_item->destroyView(); } + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } old_parent->getViewModelItem()->dirtyDescendantsFilter(); } } @@ -619,6 +626,11 @@ void LLInventoryPanel::modelChanged(U32 mask) if(parent) { parent->getViewModelItem()->dirtyDescendantsFilter(); + LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(parent->getViewModelItem()); + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } } } } @@ -1110,6 +1122,73 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it fv->startRenamingSelectedItem(); } } + + std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList(); + LLFolderViewItem* prev_folder_item = getItemByID(mPreviousSelectedFolder); + + if (selected_items.size() == 1) + { + std::set<LLFolderViewItem*>::const_iterator iter = selected_items.begin(); + LLFolderViewItem* folder_item = (*iter); + if(folder_item && (folder_item != prev_folder_item)) + { + LLFolderViewModelItemInventory* fve_listener = static_cast<LLFolderViewModelItemInventory*>(folder_item->getViewModelItem()); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + if(prev_folder_item) + { + LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem(); + if(prev_bridge) + { + prev_bridge->clearDisplayName(); + prev_bridge->setShowDescendantsCount(false); + prev_folder_item->refresh(); + } + } + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem(); + if(bridge) + { + bridge->clearDisplayName(); + bridge->setShowDescendantsCount(true); + folder_item->refresh(); + mPreviousSelectedFolder = bridge->getUUID(); + } + } + } + } + else + { + if(prev_folder_item) + { + LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem(); + if(prev_bridge) + { + prev_bridge->clearDisplayName(); + prev_bridge->setShowDescendantsCount(false); + prev_folder_item->refresh(); + } + } + mPreviousSelectedFolder = LLUUID(); + } + +} + +void LLInventoryPanel::updateFolderLabel(const LLUUID& folder_id) +{ + if(folder_id != mPreviousSelectedFolder) return; + + LLFolderViewItem* folder_item = getItemByID(mPreviousSelectedFolder); + if(folder_item) + { + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem(); + if(bridge) + { + bridge->clearDisplayName(); + bridge->setShowDescendantsCount(true); + folder_item->refresh(); + } + } } void LLInventoryPanel::doCreate(const LLSD& userdata) @@ -1364,10 +1443,12 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) } //static -void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL main_panel) +void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL main_panel, BOOL take_keyboard_focus, BOOL reset_filter) { LLInventoryPanel *active_panel; - if (main_panel) + bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX))); + + if (main_panel && !in_inbox) { LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory")->selectAllItemsPanel(); } @@ -1376,42 +1457,22 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L if (active_panel) { LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL; - - LLViewerInventoryItem * item = gInventory.getItem(obj_id); - LLViewerInventoryCategory * cat = gInventory.getCategory(obj_id); - - bool in_inbox = false; - - LLViewerInventoryCategory * parent_cat = NULL; - - if (item) - { - parent_cat = gInventory.getCategory(item->getParentUUID()); - } - else if (cat) - { - parent_cat = gInventory.getCategory(cat->getParentUUID()); - } - - if (parent_cat) + + if (reset_filter) { - in_inbox = (LLFolderType::FT_INBOX == parent_cat->getPreferredType()); + reset_inventory_filter(); } - + if (in_inbox) { LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); LLInventoryPanel * inventory_panel = NULL; - - if (in_inbox) - { - sidepanel_inventory->openInbox(); - inventory_panel = sidepanel_inventory->getInboxPanel(); - } + sidepanel_inventory->openInbox(); + inventory_panel = sidepanel_inventory->getInboxPanel(); if (inventory_panel) { - inventory_panel->setSelection(obj_id, TAKE_FOCUS_YES); + inventory_panel->setSelection(obj_id, take_keyboard_focus); } } else @@ -1421,7 +1482,7 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L { floater_inventory->setFocus(TRUE); } - active_panel->setSelection(obj_id, TAKE_FOCUS_YES); + active_panel->setSelection(obj_id, take_keyboard_focus); } } } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index d849647bb6..12001f5a2b 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -209,6 +209,8 @@ public: bool attachObject(const LLSD& userdata); static void idle(void* user_data); + void updateFolderLabel(const LLUUID& folder_id); + // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); @@ -220,8 +222,12 @@ public: // Find whichever inventory panel is active / on top. // "Auto_open" determines if we open an inventory panel if none are open. static LLInventoryPanel *getActiveInventoryPanel(BOOL auto_open = TRUE); - - static void openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL main_panel = FALSE); + + static void openInventoryPanelAndSetSelection(BOOL auto_open, + const LLUUID& obj_id, + BOOL main_panel = FALSE, + BOOL take_keyboard_focus = TAKE_FOCUS_YES, + BOOL reset_filter = FALSE); void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); @@ -254,6 +260,8 @@ protected: LLHandle<LLFolderView> mFolderRoot; LLScrollContainer* mScroller; + LLUUID mPreviousSelectedFolder; + LLFolderViewModelInventory mInventoryViewModel; LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge; Params mParams; // stored copy of parameter block diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index ccbe13fb50..d9fc489b4e 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -410,9 +410,10 @@ void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUI std::istringstream content_stream(content_string); LLSD response_data; - if (!unzip_llsd(response_data, content_stream, content_binary.size())) + U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); + if (uzip_result != LLUZipHelper::ZR_OK) { - LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL; + LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; return; } @@ -452,9 +453,10 @@ void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LL std::istringstream content_stream(content_string); LLSD response_data; - if (!unzip_llsd(response_data, content_stream, content_binary.size())) + U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); + if (uzip_result != LLUZipHelper::ZR_OK) { - LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL; + LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; return; } @@ -520,9 +522,10 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content) std::istringstream content_stream(content_string); LLSD response_data; - if (!unzip_llsd(response_data, content_stream, content_binary.size())) + U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); + if (uzip_result != LLUZipHelper::ZR_OK) { - LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL; + LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; return; } else diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index df708013fc..fdaa28b22b 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1224,7 +1224,12 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) LLMeshRepository::sCacheBytesRead += size; ++LLMeshRepository::sCacheReads; file.seek(offset); - U8* buffer = new U8[size]; + U8* buffer = new(std::nothrow) U8[size]; + if (!buffer) + { + LL_WARNS(LOG_MESH) << "Failed to allocate memory for skin info" << LL_ENDL; + return false; + } file.read(buffer, size); //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) @@ -1316,7 +1321,12 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) ++LLMeshRepository::sCacheReads; file.seek(offset); - U8* buffer = new U8[size]; + U8* buffer = new(std::nothrow) U8[size]; + if (!buffer) + { + LL_WARNS(LOG_MESH) << "Failed to allocate memory for mesh decomposition" << LL_ENDL; + return false; + } file.read(buffer, size); //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) @@ -1407,7 +1417,12 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) LLMeshRepository::sCacheBytesRead += size; ++LLMeshRepository::sCacheReads; file.seek(offset); - U8* buffer = new U8[size]; + U8* buffer = new(std::nothrow) U8[size]; + if (!buffer) + { + LL_WARNS(LOG_MESH) << "Failed to allocate memory for physics shape" << LL_ENDL; + return false; + } file.read(buffer, size); //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) @@ -1727,8 +1742,17 @@ bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U } LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); - std::string mesh_string((char*) data, data_size); - std::istringstream stream(mesh_string); + std::istringstream stream; + try + { + std::string mesh_string((char*)data, data_size); + stream.str(mesh_string); + } + catch (std::bad_alloc) + { + // out of memory, we won't be able to process this mesh + return false; + } if (volume->unpackVolumeFaces(stream, data_size)) { @@ -1756,9 +1780,11 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat std::istringstream stream(res_str); - if (!unzip_llsd(skin, stream, data_size)) + U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); + if (uzip_result != LLUZipHelper::ZR_OK) { LL_WARNS(LOG_MESH) << "Mesh skin info parse error. Not a valid mesh asset! ID: " << mesh_id + << " uzip result" << uzip_result << LL_ENDL; return false; } @@ -1788,9 +1814,11 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 std::istringstream stream(res_str); - if (!unzip_llsd(decomp, stream, data_size)) + U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); + if (uzip_result != LLUZipHelper::ZR_OK) { LL_WARNS(LOG_MESH) << "Mesh decomposition parse error. Not a valid mesh asset! ID: " << mesh_id + << " uzip result: " << uzip_result << LL_ENDL; return false; } @@ -2918,9 +2946,12 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo // handler, optional first that takes a body, fallback second // that requires a temporary allocation and data copy. body_offset = mOffset - offset; - data = new U8[data_size - body_offset]; - body->read(body_offset, (char *) data, data_size - body_offset); - LLMeshRepository::sBytesReceived += data_size; + data = new(std::nothrow) U8[data_size - body_offset]; + if (data) + { + body->read(body_offset, (char *) data, data_size - body_offset); + LLMeshRepository::sBytesReceived += data_size; + } } processData(body, body_offset, data, data_size - body_offset); @@ -2969,7 +3000,9 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b U8 * data, S32 data_size) { LLUUID mesh_id = mMeshParams.getSculptID(); - bool success = (! MESH_HEADER_PROCESS_FAILED) && gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size); + bool success = (! MESH_HEADER_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong + && gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size); llassert(success); if (! success) { @@ -3093,7 +3126,9 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status) void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { - if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size)) + if ((!MESH_LOD_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong + && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size)) { // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE); @@ -3141,7 +3176,9 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status) void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { - if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) + if ((!MESH_SKIN_INFO_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong + && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) { // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); @@ -3187,7 +3224,9 @@ void LLMeshDecompositionHandler::processFailure(LLCore::HttpStatus status) void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { - if ((! MESH_DECOMP_PROCESS_FAILED) && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) + if ((!MESH_DECOMP_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong + && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) { // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); @@ -3232,7 +3271,9 @@ void LLMeshPhysicsShapeHandler::processFailure(LLCore::HttpStatus status) void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { - if ((! MESH_PHYS_SHAPE_PROCESS_FAILED) && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size)) + if ((!MESH_PHYS_SHAPE_PROCESS_FAILED) + && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong + && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size)) { // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); @@ -4827,26 +4868,32 @@ void on_new_single_inventory_upload_complete( gInventory.notifyObservers(); success = true; + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. - LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); if (panel) { - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); panel->setSelection( server_response["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); - - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus); } + else + { + LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, server_response["new_inventory_item"].asUUID(), TRUE, TAKE_FOCUS_NO, TRUE); + } + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); } else { LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; } + // Todo: This is mesh repository code, is following code really needed? // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index bf1716e18c..64df449c26 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -316,14 +316,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) updateAdd(localmute); notifyObservers(); notifyObserversDetailed(localmute); - if(!(localmute.mFlags & LLMute::flagParticles)) - { - //Kill all particle systems owned by muted task - if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT) - { - LLViewerPartSim::getInstance()->clearParticlesByOwnerID(localmute.mID); - } - } + //mute local lights that are attached to the avatar LLVOAvatar *avatarp = find_avatar(localmute.mID); if (avatarp) diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index f87ce8aa52..e2157f985e 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -995,7 +995,8 @@ void LLOutfitListBase::deselectOutfit(const LLUUID& category_id) // Reset selection if the outfit is selected. if (category_id == mSelectedOutfitUUID) { - signalSelectionOutfitUUID(LLUUID::null); + mSelectedOutfitUUID = LLUUID::null; + signalSelectionOutfitUUID(mSelectedOutfitUUID); } } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 0bcbdf7e67..c876c1c149 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -299,12 +299,24 @@ void LLPanelLogin::addFavoritesToStartLocation() // Load favorites into the combo. std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + LLStringUtil::toLower(user_defined_name); std::replace(user_defined_name.begin(), user_defined_name.end(), '.', ' '); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + LLGridManager::getInstance()->getGrid() + ".xml"); std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); mUsernameLength = user_defined_name.length(); updateLoginButtons(); + std::string::size_type index = user_defined_name.find(' '); + if (index != std::string::npos) + { + std::string username = user_defined_name.substr(0, index); + std::string lastname = user_defined_name.substr(index+1); + if (lastname == "resident") + { + user_defined_name = username; + } + } + LLSD fav_llsd; llifstream file; file.open(filename.c_str()); @@ -492,7 +504,7 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; if(authenticator.isMap() && authenticator.has("secret") && - (authenticator["secret"].asString().size() > 0)) + (authenticator["secret"].asString().size() > 0) && remember) { // This is a MD5 hex digest of a password. @@ -801,7 +813,8 @@ void LLPanelLogin::loadLoginPage() params["login_content_version"] = gSavedSettings.getString("LoginContentVersion"); // Make an LLURI with this augmented info - LLURI login_uri(LLURI::buildHTTP(login_page.authority(), + std::string url = login_page.scheme().empty()? login_page.authority() : login_page.scheme() + "://" + login_page.authority(); + LLURI login_uri(LLURI::buildHTTP(url, login_page.path(), params)); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ec80ff8de7..db9d61c637 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -44,6 +44,7 @@ #include "llfloaterreg.h" #include "llmenubutton.h" #include "lloutfitobserver.h" +#include "llpanelmarketplaceinbox.h" #include "llpreviewtexture.h" #include "llresmgr.h" #include "llscrollcontainer.h" @@ -178,7 +179,9 @@ BOOL LLPanelMainInventory::postBuild() mWornItemsPanel->setFilterWorn(); mWornItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); mWornItemsPanel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); - mWornItemsPanel->getFilter().markDefault(); + LLInventoryFilter& worn_filter = mWornItemsPanel->getFilter(); + worn_filter.setFilterCategoryTypes(worn_filter.getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX)); + worn_filter.markDefault(); mWornItemsPanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mWornItemsPanel, _1, _2)); } mSearchTypeCombo = getChild<LLComboBox>("search_type"); @@ -483,7 +486,7 @@ void LLPanelMainInventory::onClearSearch() if (mActivePanel && (getActivePanel() != mWornItemsPanel)) { initially_active = mActivePanel->getFilter().isNotDefault(); - mActivePanel->setFilterSubString(LLStringUtil::null); + setFilterSubString(LLStringUtil::null); mActivePanel->setFilterTypes(0xffffffffffffffffULL); mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS); } @@ -503,6 +506,16 @@ void LLPanelMainInventory::onClearSearch() mActivePanel->getRootFolder()->scrollToShowSelection(); } mFilterSubString = ""; + + LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox"); + if (inbox_panel) + { + inbox_panel->onClearSearch(); + } + } } void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) @@ -534,6 +547,16 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) // set new filter string setFilterSubString(mFilterSubString); + + LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + LLPanelMarketplaceInbox* inbox_panel = sidepanel_inventory->getChild<LLPanelMarketplaceInbox>("marketplace_inbox"); + if (inbox_panel) + { + inbox_panel->onFilterEdit(search_string); + } + } } @@ -685,8 +708,17 @@ void LLPanelMainInventory::updateItemcountText() LLResMgr::getInstance()->getIntegerString(mItemCountString, mItemCount); } + if(mCategoryCount != gInventory.getCategoryCount()) + { + mCategoryCount = gInventory.getCategoryCount(); + mCategoryCountString = ""; + LLLocale locale(LLLocale::USER_LOCALE); + LLResMgr::getInstance()->getIntegerString(mCategoryCountString, mCategoryCount); + } + LLStringUtil::format_map_t string_args; string_args["[ITEM_COUNT]"] = mItemCountString; + string_args["[CATEGORY_COUNT]"] = mCategoryCountString; string_args["[FILTER]"] = getFilterText(); std::string text = ""; @@ -705,6 +737,7 @@ void LLPanelMainInventory::updateItemcountText() } mCounterCtrl->setValue(text); + mCounterCtrl->setToolTip(text); } void LLPanelMainInventory::onFocusReceived() @@ -848,7 +881,6 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() // Get data needed for filter display U32 filter_types = mFilter->getFilterObjectTypes(); - std::string filter_string = mFilter->getFilterSubString(); LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); U32 hours = mFilter->getHoursAgo(); U32 date_search_direction = mFilter->getDateSearchDirection(); diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 2904d5de76..732a3b04e3 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -132,7 +132,7 @@ private: LLFilterEditor* mFilterEditor; LLTabContainer* mFilterTabs; - LLUICtrl* mCounterCtrl; + LLUICtrl* mCounterCtrl; LLHandle<LLFloater> mFinderHandle; LLInventoryPanel* mActivePanel; LLInventoryPanel* mWornItemsPanel; @@ -141,7 +141,9 @@ private: std::string mFilterText; std::string mFilterSubString; S32 mItemCount; - std::string mItemCountString; + std::string mItemCountString; + S32 mCategoryCount; + std::string mCategoryCountString; LLComboBox* mSearchTypeCombo; diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp index 79e079f6bd..8a86f4f63d 100644 --- a/indra/newview/llpanelmarketplaceinbox.cpp +++ b/indra/newview/llpanelmarketplaceinbox.cpp @@ -51,11 +51,15 @@ LLPanelMarketplaceInbox::LLPanelMarketplaceInbox(const Params& p) , mFreshCountCtrl(NULL) , mInboxButton(NULL) , mInventoryPanel(NULL) + , mSavedFolderState(NULL) { + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); } LLPanelMarketplaceInbox::~LLPanelMarketplaceInbox() { + delete mSavedFolderState; } // virtual @@ -96,6 +100,7 @@ LLInventoryPanel * LLPanelMarketplaceInbox::setupInventoryPanel() // Set the sort order newest to oldest mInventoryPanel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_DATE); mInventoryPanel->getFilter().markDefault(); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); // Set selection callback for proper update of inventory status buttons mInventoryPanel->setSelectCallback(boost::bind(&LLPanelMarketplaceInbox::onSelectionChange, this)); @@ -193,6 +198,38 @@ U32 LLPanelMarketplaceInbox::getTotalItemCount() const return item_count; } +void LLPanelMarketplaceInbox::onClearSearch() +{ + if (mInventoryPanel) + { + mInventoryPanel->setFilterSubString(LLStringUtil::null); + mSavedFolderState->setApply(TRUE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); + mInventoryPanel->getRootFolder()->scrollToShowSelection(); + } +} + +void LLPanelMarketplaceInbox::onFilterEdit(const std::string& search_string) +{ + if (mInventoryPanel) + { + + if (search_string == "") + { + onClearSearch(); + } + + if (!mInventoryPanel->getFilter().isNotDefault()) + { + mSavedFolderState->setApply(FALSE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + } + mInventoryPanel->setFilterSubString(search_string); + } +} + std::string LLPanelMarketplaceInbox::getBadgeString() const { std::string item_count_str(""); diff --git a/indra/newview/llpanelmarketplaceinbox.h b/indra/newview/llpanelmarketplaceinbox.h index 9eb74581a2..952e3a333a 100644 --- a/indra/newview/llpanelmarketplaceinbox.h +++ b/indra/newview/llpanelmarketplaceinbox.h @@ -28,7 +28,7 @@ #define LL_LLPANELMARKETPLACEINBOX_H #include "llpanel.h" - +#include "llfolderview.h" class LLButton; class LLInventoryPanel; class LLUICtrl; @@ -56,6 +56,9 @@ public: LLInventoryPanel * setupInventoryPanel(); + void onClearSearch(); + void onFilterEdit(const std::string& search_string); + U32 getFreshItemCount() const; U32 getTotalItemCount() const; @@ -71,6 +74,7 @@ private: LLUICtrl * mFreshCountCtrl; LLButton * mInboxButton; LLInventoryPanel * mInventoryPanel; + LLSaveFolderState* mSavedFolderState; }; diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index c5fda3c136..2d2ba30e9b 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -62,6 +62,12 @@ LLInboxInventoryPanel::LLInboxInventoryPanel(const LLInboxInventoryPanel::Params LLInboxInventoryPanel::~LLInboxInventoryPanel() {} +void LLInboxInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) +{ + LLInventoryPanel::initFromParams(params); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX)); +} + LLFolderViewFolder * LLInboxInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop) { LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); @@ -140,18 +146,16 @@ void LLInboxFolderViewFolder::draw() LLFolderViewFolder::draw(); } -void LLInboxFolderViewFolder::selectItem() +BOOL LLInboxFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) { deFreshify(); - - LLFolderViewFolder::selectItem(); + return LLFolderViewFolder::handleMouseDown(x, y, mask); } -void LLInboxFolderViewFolder::toggleOpen() +BOOL LLInboxFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) { deFreshify(); - - LLFolderViewFolder::toggleOpen(); + return LLFolderViewFolder::handleDoubleClick(x, y, mask); } void LLInboxFolderViewFolder::computeFreshness() diff --git a/indra/newview/llpanelmarketplaceinboxinventory.h b/indra/newview/llpanelmarketplaceinboxinventory.h index 66aafe83d1..d398cdafed 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.h +++ b/indra/newview/llpanelmarketplaceinboxinventory.h @@ -46,6 +46,7 @@ public: ~LLInboxInventoryPanel(); // virtual + void initFromParams(const LLInventoryPanel::Params&); LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop); LLFolderViewItem * createFolderViewItem(LLInvFVBridge * bridge); }; @@ -68,8 +69,8 @@ public: void addItem(LLFolderViewItem* item); void draw(); - void selectItem(); - void toggleOpen(); + BOOL handleMouseDown(S32 x, S32 y, MASK mask); + BOOL handleDoubleClick(S32 x, S32 y, MASK mask); void computeFreshness(); void deFreshify(); diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index d7c43c224c..3522189842 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -196,7 +196,7 @@ void LLPanelMediaSettingsGeneral::draw() //////////////////////////////////////////////////////////////////////////////// // static -void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable) +void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable, bool update_preview) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; self->mAutoLoop->clear(); @@ -217,7 +217,10 @@ void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable) self->mHeightPixels ->setEnabled(editable); self->mHomeURL ->setEnabled(editable); self->mWidthPixels ->setEnabled(editable); - self->updateMediaPreview(); + if (update_preview) + { + self->updateMediaPreview(); + } } // static diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h index 0ae1401ab2..06793d91fc 100644 --- a/indra/newview/llpanelmediasettingsgeneral.h +++ b/indra/newview/llpanelmediasettingsgeneral.h @@ -59,7 +59,7 @@ public: void setParent( LLFloaterMediaSettings* parent ); static void initValues( void* userdata, const LLSD& media_settings ,bool editable); - static void clearValues( void* userdata, bool editable); + static void clearValues( void* userdata, bool editable, bool update_preview = true); // Navigates the current selected face to the Home URL. // If 'only_if_current_is_empty' is "true", it only performs diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index ed942fc7fc..48dd45480e 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -395,11 +395,16 @@ void LLPanelPlaces::onOpen(const LLSD& key) mPlaceInfoType = key_type; mPosGlobal.setZero(); mItem = NULL; + mRegionId.setNull(); togglePlaceInfoPanel(TRUE); if (mPlaceInfoType == AGENT_INFO_TYPE) { mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT); + if (gAgent.getRegion()) + { + mRegionId = gAgent.getRegion()->getRegionID(); + } } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) { @@ -472,6 +477,8 @@ void LLPanelPlaces::onOpen(const LLSD& key) if (!parcel_mgr) return; + mParcelLocalId = parcel_mgr->getAgentParcel()->getLocalID(); + // Start using LLViewerParcelMgr for land selection if // information about nearby land is requested. // Otherwise stop using land selection and deselect land. @@ -828,10 +835,21 @@ void LLPanelPlaces::onOverflowButtonClicked() { menu = mPlaceMenu; + bool landmark_item_enabled = false; + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + if (is_agent_place_info_visible + && gAgent.getRegion() + && mRegionId == gAgent.getRegion()->getRegionID() + && parcel_mgr + && parcel_mgr->getAgentParcel()->getLocalID() == mParcelLocalId) + { + // Floater still shows location identical to agent's position + landmark_item_enabled = !LLLandmarkActions::landmarkAlreadyExists(); + } + // Enable adding a landmark only for agent current parcel and if // there is no landmark already pointing to that parcel in agent's inventory. - menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible && - !LLLandmarkActions::landmarkAlreadyExists()); + menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(landmark_item_enabled); // STORM-411 // Creating landmarks for remote locations is impossible. // So hide menu item "Make a Landmark" in "Teleport History Profile" panel. diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index c3d1b9bc53..27f991c202 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -146,6 +146,10 @@ private: // Information type currently shown in Place Information panel std::string mPlaceInfoType; + // Region and parcel ids, to detect location changes in case of AGENT_INFO_TYPE + LLUUID mRegionId; + S32 mParcelLocalId; + bool isLandmarkEditModeOn; // Holds info whether "My Landmarks" and "Teleport History" tabs have been created. diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 15d39c231f..08d734ddac 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -44,7 +44,7 @@ typedef std::map<std::string, std::string> controller_map_t; typedef std::map<std::string, F32> default_controller_map_t; #define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f -#define TIME_ITERATION_STEP 0.1f +#define TIME_ITERATION_STEP 0.05f inline F64 llsgn(const F64 a) { @@ -491,12 +491,6 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) // const F32 time_delta = time - mLastTime; - - // Don't update too frequently, to avoid precision errors from small time slices. - if (time_delta <= .01) - { - return FALSE; - } // If less than 1FPS, we don't want to be spending time updating physics at all. if (time_delta > 1.0) @@ -555,6 +549,18 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) // Break up the physics into a bunch of iterations so that differing framerates will show // roughly the same behavior. + // Explanation/example: Lets assume we have a bouncing object. Said abjects bounces at a + // trajectory that has points A>B>C. Object bounces from A to B with specific speed. + // It needs time T to move from A to B. + // As long as our frame's time significantly smaller then T our motion will be split into + // multiple parts. with each part speed will decrease. Object will reach B position (roughly) + // and bounce/fall back to A. + // But if frame's time (F_T) is larger then T, object will move with same speed for whole F_T + // and will jump over point B up to C ending up with increased amplitude. To avoid that we + // split F_T into smaller portions so that when frame's time is too long object can virtually + // bounce at right (relatively) position. + // Note: this doesn't look to be optimal, since it provides only "roughly same" behavior, but + // irregularity at higher fps looks to be insignificant so it works good enough for low fps. for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP) { F32 time_iteration_step = TIME_ITERATION_STEP; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ad9a554ef5..7ea6a14e6b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -718,7 +718,6 @@ bool idle_startup() set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); // LLViewerMedia::initBrowser(); - show_release_notes_if_required(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); return FALSE; } @@ -749,6 +748,7 @@ bool idle_startup() initialize_spellcheck_menu(); init_menus(); } + show_release_notes_if_required(); if (show_connect_box) { diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 371da5d0a2..dadf2f9701 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -452,27 +452,38 @@ bool LLTextureCacheRemoteWorker::doRead() size = llmin(size, mDataSize); // Allocate the read buffer mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size); - S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, - mReadData, offset, size, mCache->getLocalAPRFilePool()); - if (bytes_read != size) + if (mReadData) + { + S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, + mReadData, offset, size, mCache->getLocalAPRFilePool()); + if (bytes_read != size) + { + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " incorrect number of bytes read from header: " << bytes_read + << " / " << size << LL_ENDL; + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); + mReadData = NULL; + mDataSize = -1; // failed + done = true; + } + // If we already read all we expected, we're actually done + if (mDataSize <= bytes_read) + { + done = true; + } + else + { + mState = BODY; + } + } + else { LL_WARNS() << "LLTextureCacheWorker: " << mID - << " incorrect number of bytes read from header: " << bytes_read - << " / " << size << LL_ENDL; - FREE_MEM(LLImageBase::getPrivatePool(), mReadData); + << " failed to allocate memory for reading: " << mDataSize << LL_ENDL; mReadData = NULL; mDataSize = -1; // failed done = true; } - // If we already read all we expected, we're actually done - if (mDataSize <= bytes_read) - { - done = true; - } - else - { - mState = BODY; - } } // Fourth state / stage : read the rest of the data from the UUID based cached file diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index f917faadd4..1f7796e6d0 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1760,7 +1760,17 @@ bool LLTextureFetchWorker::doWork(S32 param) mRequestedSize -= src_offset; // Make requested values reflect useful part mRequestedOffset += src_offset; } - + + U8 * buffer = (U8 *)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size); + if (!buffer) + { + // abort. If we have no space for packet, we have not enough space to decode image + setState(DONE); + LL_WARNS(LOG_TXT) << mID << " abort: out of memory" << LL_ENDL; + releaseHttpSemaphore(); + return true; + } + if (mFormattedImage.isNull()) { // For now, create formatted image based on extension @@ -1780,10 +1790,10 @@ bool LLTextureFetchWorker::doWork(S32 param) { mFileSize = total_size + 1 ; //flag the file is not fully loaded. } - - U8 * buffer = (U8 *) ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size); + if (cur_size > 0) { + // Copy previously collected data into buffer memcpy(buffer, mFormattedImage->getData(), cur_size); } mHttpBufferArray->read(src_offset, (char *) buffer + cur_size, append_size); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 01b4fcfbe1..4f68c9a98e 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -760,17 +760,22 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti { success = true; + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. - LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); if (panel) { - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); panel->setSelection(serverInventoryItem, TAKE_FOCUS_NO); - - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus); } + else + { + LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, TRUE, TAKE_FOCUS_NO, TRUE); + } + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); } else { diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index fffcb68cbb..474f3de664 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -786,13 +786,24 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } } // update the audio stream here as well + static bool restore_parcel_audio = false; if( !inworld_audio_enabled) { if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) { LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); + restore_parcel_audio = true; } } + else + { + if(gAudiop && LLViewerMedia::hasParcelAudio() && restore_parcel_audio && gSavedSettings.getBOOL("MediaTentativeAutoPlay")) + { + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL()); + restore_parcel_audio = false; + } + } + pimpl->setPriority(new_priority); if(pimpl->getUsedInUI()) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 94a86a7831..e9085f9327 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -871,7 +871,7 @@ private: */ bool isSelectionChanged() { - LLInventoryPanel* active_panel = dynamic_cast<LLInventoryPanel*>(mActivePanel.get()); + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (NULL == active_panel) { @@ -881,7 +881,7 @@ private: // get selected items (without destination folder) selected_items_t selected_items; - std::set<LLFolderViewItem*> selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + std::set<LLFolderViewItem*> selection = active_panel->getRootFolder()->getSelectionList(); for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); it != end_it; ++it) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6c2d4d7fea..5d49c888cf 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -270,7 +270,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPhysicsShapeUnknown(true), mAttachmentItemID(LLUUID::null), mLastUpdateType(OUT_UNKNOWN), - mLastUpdateCached(FALSE) + mLastUpdateCached(FALSE), + mCachedMuteListUpdateTime(0), + mCachedOwnerInMuteList(false) { if (!is_global) { @@ -5116,6 +5118,30 @@ void LLViewerObject::updateText() } } +bool LLViewerObject::isOwnerInMuteList(LLUUID id) +{ + LLUUID owner_id = id.isNull() ? mOwnerID : id; + if (isAvatar() || owner_id.isNull()) + { + return false; + } + bool muted = false; + F64 now = LLFrameTimer::getTotalSeconds(); + if (now < mCachedMuteListUpdateTime) + { + muted = mCachedOwnerInMuteList; + } + else + { + muted = LLMuteList::getInstance()->isMuted(owner_id); + + const F64 SECONDS_BETWEEN_MUTE_UPDATES = 1; + mCachedMuteListUpdateTime = now + SECONDS_BETWEEN_MUTE_UPDATES; + mCachedOwnerInMuteList = muted; + } + return muted; +} + LLVOAvatar* LLViewerObject::asAvatar() { return NULL; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 7a490f6957..21c95d5533 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -422,6 +422,8 @@ public: void updateText(); // update text label position virtual void updateDrawable(BOOL force_damped); // force updates on static objects + bool isOwnerInMuteList(LLUUID item_id = LLUUID()); + void setDrawableState(U32 state, BOOL recursive = TRUE); void clearDrawableState(U32 state, BOOL recursive = TRUE); BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const; @@ -823,6 +825,9 @@ private: static BOOL sVelocityInterpolate; static BOOL sPingInterpolate; + bool mCachedOwnerInMuteList; + F64 mCachedMuteListUpdateTime; + //-------------------------------------------------------------------- // For objects that are attachments //-------------------------------------------------------------------- diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 3c83e3a006..dc54346d59 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -478,15 +478,25 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { U32 flags = 0; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - - if(flags & FLAGS_TEMPORARY_ON_REZ) + + compressed_dp.unpackUUID(fullid, "ID"); + compressed_dp.unpackU32(local_id, "LocalID"); + compressed_dp.unpackU8(pcode, "PCode"); + + if (pcode == 0) { - compressed_dp.unpackUUID(fullid, "ID"); - compressed_dp.unpackU32(local_id, "LocalID"); - compressed_dp.unpackU8(pcode, "PCode"); - } - else //send to object cache + // object creation will fail, LLViewerObject::createObject() + LL_WARNS() << "Received object " << fullid + << " with 0 PCode. Local id: " << local_id + << " Flags: " << flags + << " Region: " << regionp->getName() + << " Region id: " << regionp->getRegionID() << LL_ENDL; + recorder.objectUpdateFailure(local_id, update_type, msg_size); + continue; + } + else if ((flags & FLAGS_TEMPORARY_ON_REZ) == 0) { + //send to object cache regionp->cacheFullUpdate(compressed_dp, flags); continue; } @@ -732,9 +742,9 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) S32 num_updates, max_value; if (NUM_BINS - 1 == mCurBin) { + // Remainder (mObjects.size() could have changed) num_updates = (S32) mObjects.size() - mCurLazyUpdateIndex; max_value = (S32) mObjects.size(); - gTextureList.setUpdateStats(TRUE); } else { @@ -791,10 +801,14 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) mCurLazyUpdateIndex = max_value; if (mCurLazyUpdateIndex == mObjects.size()) { + // restart mCurLazyUpdateIndex = 0; + mCurBin = 0; // keep in sync with index (mObjects.size() could have changed) + } + else + { + mCurBin = (mCurBin + 1) % NUM_BINS; } - - mCurBin = (mCurBin + 1) % NUM_BINS; LLVOAvatar::cullAvatarsByPixelArea(); } diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index b4617566ac..25cf082751 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -37,6 +37,7 @@ #include "llviewerregion.h" #include "llvopartgroup.h" #include "llworld.h" +#include "llmutelist.h" #include "pipeline.h" #include "llspatialpartition.h" #include "llvoavatarself.h" @@ -711,6 +712,11 @@ void LLViewerPartSim::updateSimulation() upd = FALSE; } + if(vobj && vobj->isOwnerInMuteList(mViewerPartSources[i]->getOwnerUUID())) + { + upd = FALSE; + } + if (upd && vobj && (vobj->getPCode() == LL_PCODE_VOLUME)) { if(vobj->getAvatar() && vobj->getAvatar()->isTooComplex()) @@ -750,7 +756,7 @@ void LLViewerPartSim::updateSimulation() LLViewerObject* vobj = mViewerPartGroups[i]->mVOPartGroupp; S32 visirate = 1; - if (vobj) + if (vobj && !vobj->isDead() && vobj->mDrawable && !vobj->mDrawable->isDead()) { LLSpatialGroup* group = vobj->mDrawable->getSpatialGroup(); if (group && !group->isVisible()) // && !group->isState(LLSpatialGroup::OBJECT_DIRTY)) @@ -761,7 +767,7 @@ void LLViewerPartSim::updateSimulation() if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%visirate == 0) { - if (vobj) + if (vobj && !vobj->isDead()) { gPipeline.markRebuild(vobj->mDrawable, LLDrawable::REBUILD_ALL, TRUE); } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 0a3012ffef..45ea169fb8 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -92,7 +92,6 @@ LLTextureKey::LLTextureKey(LLUUID id, ETexListType tex_type) LLViewerTextureList::LLViewerTextureList() : mForceResetTextureStats(FALSE), - mUpdateStats(FALSE), mMaxResidentTexMemInMegaBytes(0), mMaxTotalTextureMemInMegaBytes(0), mInitialized(FALSE) @@ -103,7 +102,6 @@ void LLViewerTextureList::init() { mInitialized = TRUE ; sNumImages = 0; - mUpdateStats = TRUE; mMaxResidentTexMemInMegaBytes = (U32Bytes)0; mMaxTotalTextureMemInMegaBytes = (U32Bytes)0; @@ -1171,7 +1169,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) void LLViewerTextureList::updateImagesUpdateStats() { - if (mUpdateStats && mForceResetTextureStats) + if (mForceResetTextureStats) { for (image_priority_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) @@ -1179,7 +1177,6 @@ void LLViewerTextureList::updateImagesUpdateStats() LLViewerFetchedTexture* imagep = *iter++; imagep->resetTextureStats(); } - mUpdateStats = FALSE; mForceResetTextureStats = FALSE; } } diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 070544063a..281d23c671 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -124,8 +124,6 @@ public: void handleIRCallback(void **data, const S32 number); - void setUpdateStats(BOOL b) { mUpdateStats = b; } - S32Megabytes getMaxResidentTexMem() const { return mMaxResidentTexMemInMegaBytes; } S32Megabytes getMaxTotalTextureMem() const { return mMaxTotalTextureMemInMegaBytes;} S32 getNumImages() { return mImageList.size(); } @@ -224,7 +222,6 @@ private: std::set<LLPointer<LLViewerFetchedTexture> > mImagePreloads; BOOL mInitialized ; - BOOL mUpdateStats; S32Megabytes mMaxResidentTexMemInMegaBytes; S32Megabytes mMaxTotalTextureMemInMegaBytes; LLFrameTimer mForceDecodeTimer; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 119c1a9db6..74deaffe16 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1406,7 +1406,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { // Let the voice chat code check for its PTT key. Note that this never affects event processing. LLVoiceClient::getInstance()->keyDown(key, mask); - + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) { gAgent.clearAFK(); @@ -1959,7 +1959,11 @@ void LLViewerWindow::initBase() // (But wait to add it as a child of the root view so that it will be in front of the // other views.) MainPanel* main_view = new MainPanel(); - main_view->buildFromFile("main_view.xml"); + if (!main_view->buildFromFile("main_view.xml")) + { + LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file main_view.xml, " + << "if this problem happens again, please validate your installation." << LL_ENDL; + } main_view->setShape(full_window); getRootView()->addChild(main_view); @@ -2264,6 +2268,7 @@ void LLViewerWindow::shutdownGL() LLViewerWindow::~LLViewerWindow() { LL_INFOS() << "Destroying Window" << LL_ENDL; + gDebugWindowProc = TRUE; // event catching, at this point it shouldn't output at all destroyWindow(); delete mDebugText; @@ -4443,7 +4448,8 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picke err = LLFile::stat( filepath, &stat_info ); i++; } - while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). + while( -1 != err // Search until the file is not found (i.e., stat() gives an error). + && is_snapshot_name_loc_set); // Or stop if we are rewriting. LL_INFOS() << "Saving snapshot to " << filepath << LL_ENDL; return image->save(filepath); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 93a176d435..8e46e08b14 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -888,14 +888,9 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() bool LLVivoxVoiceClient::provisionVoiceAccount() { LL_INFOS("Voice") << "Provisioning voice account." << LL_ENDL; - while (!gAgent.getRegion()) - { LL_DEBUGS("Voice") << "no region for voice provisioning; waiting " << LL_ENDL; - // *TODO* Set up a call back on agent that sends a message to a pump we can use to wake up. - llcoro::suspend(); - } - while (!gAgent.getRegion()->capabilitiesReceived()) + while (!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; // *TODO* Pump a message for wake up. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f77b48ff80..7b4d8ef329 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -628,7 +628,7 @@ void LLVOVolume::updateTextures() if (mDrawable.notNull() && !isVisible() && !mDrawable->isActive()) { //delete vertex buffer to free up some VRAM LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) + if (group && (group->mVertexBuffer.notNull() || !group->mBufferMap.empty() || !group->mDrawMap.empty())) { group->destroyGL(true); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index ee2270c323..5fb3d62445 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -645,7 +645,7 @@ LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p) setRightMouseDownCallback(boost::bind(&LLWearableItemsList::onRightClick, this, _2, _3)); } mWornIndicationEnabled = p.worn_indication_enabled; - setNoItemsCommentText(LLTrans::getString("LoadingData")); + setNoItemsCommentText(LLTrans::getString("NoneFound")); } // virtual diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 62fad32246..9ae788a409 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1750,8 +1750,10 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) case MAP_ITEM_LAND_FOR_SALE: case MAP_ITEM_LAND_FOR_SALE_ADULT: { + LLVector3d pos_global = viewPosToGlobal(x, y); + LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); LLFloaterReg::hideInstance("world_map"); - LLFloaterReg::showInstance("search", LLSD().with("category", "destinations").with("query", id)); + LLFloaterReg::showInstance("search", LLSD().with("category", "land").with("query", info->getName())); break; } case MAP_ITEM_CLASSIFIED: diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml index dddb258ed9..af6d11f47e 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml @@ -47,7 +47,6 @@ top="20" width="500"> <panel - border="none" height="150" label="Search" layout="topleft" @@ -108,7 +107,6 @@ </scroll_list> </panel> <panel - border="none" height="150" label="Friends" layout="topleft" @@ -144,7 +142,6 @@ <scroll_list follows="all" height="120" - border="false" layout="topleft" left="0" name="Friends" @@ -154,7 +151,6 @@ </panel> <panel - border="none" height="150" label="Near Me" layout="topleft" @@ -213,7 +209,6 @@ draw_heading="true" follows="all" height="100" - border="false" layout="topleft" left="0" name="NearMe" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 9e4cb4e267..6aa6653f42 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5928,7 +5928,7 @@ The folder '[FOLDERNAME]' is a system folder. Deleting system folders icon="alertmodal.tga" name="ConfirmEmptyTrash" type="alertmodal"> -[COUNT] items will be permanently deleted. Are you sure you want to permanently delete the contents of your Trash? +[COUNT] items and folders will be permanently deleted. Are you sure you want to permanently delete the contents of your Trash? <tag>confirm</tag> <usetemplate name="okcancelbuttons" 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 df70398599..d77fbdec0a 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -13,26 +13,27 @@ </panel.string> <panel.string name="ItemcountFetching"> - Fetching [ITEM_COUNT] Items... [FILTER] + Fetching [ITEM_COUNT] Items and [CATEGORY_COUNT] Folders... [FILTER] </panel.string> <panel.string name="ItemcountCompleted"> - [ITEM_COUNT] Items [FILTER] + [ITEM_COUNT] Items and [CATEGORY_COUNT] Folders [FILTER] </panel.string> <panel.string name="ItemcountUnknown"> - Fetched [ITEM_COUNT] Items [FILTER] + Fetched [ITEM_COUNT] Items and [CATEGORY_COUNT] Folders [FILTER] </panel.string> <text type="string" length="1" - follows="left|top" + follows="left|top|right" height="13" layout="topleft" left="12" name="ItemcountText" font="SansSerifMedium" text_color="EmphasisColor" + use_ellipses="true" top_pad="0" width="300"> Items: diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml index 4d9316768b..c1a68fb9af 100644 --- a/indra/newview/skins/default/xui/en/panel_notification.xml +++ b/indra/newview/skins/default/xui/en/panel_notification.xml @@ -71,7 +71,6 @@ mouse_opaque="false" name="text_editor_box" read_only="true" - tab_stop="false" text_color="White" text_readonly_color="White" top="10" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 807d116b3b..5f30a7e87d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2329,7 +2329,7 @@ If you continue to receive this message, please contact Second Life support for <string name="InventoryMarketplaceListingsNoItems"> Drag folders to this area to list them for sale on the [[MARKETPLACE_DASHBOARD_URL] Marketplace]. </string> - + <string name="InventoryItemsCount">( [ITEMS_COUNT] Items )</string> <string name="Marketplace Validation Log"></string> <string name="Marketplace Validation Warning Stock">stock folder must be contained by a version folder</string> <string name="Marketplace Validation Error Mixed Stock">: Error: all items in a stock folder must be no-copy and of the same type</string> |