diff options
188 files changed, 5028 insertions, 1679 deletions
| diff --git a/doc/contributions.txt b/doc/contributions.txt index 211d4fcf08..7493e96c39 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -185,6 +185,7 @@ Ansariel Hiller  	BUG-3764  	STORM-1984  	STORM-1979 +	MAINT-5533  Aralara Rajal  Arare Chantilly  	CHUIBUG-191 diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ae11988df8..3a8eabac09 100755 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -2176,8 +2176,7 @@ void* ll_aligned_malloc_fallback( size_t size, int align )  	SYSTEM_INFO sysinfo;  	GetSystemInfo(&sysinfo); -	unsigned int for_alloc = sysinfo.dwPageSize; -	while(for_alloc < size) for_alloc += sysinfo.dwPageSize; +	unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize;  	void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);  	if(NULL == p) { diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d3a9bbc4ae..0fb257aab1 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -98,7 +98,7 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)  //------------------------------------------------------------------------------------------------  //------------------------------------------------------------------------------------------------  	// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library -	// change preprocessro code to: #if 1 && defined(LL_WINDOWS) +	// change preprocessor code to: #if 1 && defined(LL_WINDOWS)  #if 0 && defined(LL_WINDOWS)  	void* ll_aligned_malloc_fallback( size_t size, int align ); diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index d98bc297e5..82d0dc8b4b 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -238,12 +238,12 @@ void LLUriParser::glueSecond(std::string& uri) const  	{  		uri += '?';  		uri += mQuery; +	} -		if (mFragment.size()) -		{ -			uri += '#'; -			uri += mFragment; -		} +	if (mFragment.size()) +	{ +		uri += '#'; +		uri += mFragment;  	}  } diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 8573fe0d91..a2ce2fee86 100755 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -443,6 +443,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )  		mBitfieldMask[2] = 0x000000FF;  	} +	if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset) +	{ //here we have situation when data size in src less than actually needed +		return FALSE; +	}  	S32 src_row_span = getWidth() * 4;  	S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4 @@ -476,6 +480,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )  	S32 src_row_span = getWidth() * 1;  	S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4 +	if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) +	{ //here we have situation when data size in src less than actually needed +		return FALSE; +	} +  	for( S32 row = 0; row < getHeight(); row++ )  	{  		for( S32 col = 0; col < getWidth(); col++ ) @@ -501,6 +510,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )  	S32 src_row_span = getWidth() * 3;  	S32 alignment_bytes = (3 * src_row_span) % 4;  // round up to nearest multiple of 4 +	if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) +	{ //here we have situation when data size in src less than actually needed +		return FALSE; +	} +  	for( S32 row = 0; row < getHeight(); row++ )  	{  		for( S32 col = 0; col < getWidth(); col++ ) diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 4eb8dc7440..d0ae105ba7 100755 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu  	// Origin is the bottom left  	U8* dst = raw_image->getData();  	U8* src = getData() + mDataOffset; +  	S32 pixels = getWidth() * getHeight(); +	 +	if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset) +	{ //here we have situation when data size in src less than actually needed +		return FALSE; +	}  	if (getComponents() == 4)  	{ diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 4703e6cf1a..edf5a1b75c 100755 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5584,7 +5584,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)  	{  		resizeVertices(num_vertices+1); -		if (!partial_build) +		//if (!partial_build)  		{  			resizeIndices(num_indices+3);  		} @@ -5592,7 +5592,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)  	else  	{  		resizeVertices(num_vertices); -		if (!partial_build) +		//if (!partial_build)  		{  			resizeIndices(num_indices);  		} @@ -5714,10 +5714,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)  	LL_CHECK_MEMORY -	if (partial_build) -	{ -		return TRUE; -	} +	//if (partial_build) +	//{ +	//	return TRUE; +	//}  	if (mTypeMask & HOLLOW_MASK)  	{ diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 625f7cff02..1da2d0c6b1 100755 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -190,8 +190,12 @@ const U8 LL_SCULPT_TYPE_MESH      = 5;  const U8 LL_SCULPT_TYPE_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |  	LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; +// for value checks, assign new value after adding new types +const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; +  const U8 LL_SCULPT_FLAG_INVERT    = 64;  const U8 LL_SCULPT_FLAG_MIRROR    = 128; +const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR;  const S32 LL_SCULPT_MESH_MAX_FACES = 8; diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 52626b0302..4bfd0de81e 100755 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -146,6 +146,8 @@ void LLPluginClassMedia::reset()  	mClickTarget.clear();  	mClickUUID.clear();  	mStatusCode = 0; + +	mClickEnforceTarget = false;  	// media_time class  	mCurrentTime = 0.0f; @@ -1358,6 +1360,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path)  	sendMessage(message);  } +void LLPluginClassMedia::setOverrideClickTarget(const std::string &target) +{ +	mClickEnforceTarget = true; +	mOverrideClickTarget = target; +} +  void LLPluginClassMedia::crashPlugin()  {  	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 5fe8254331..96d577f43c 100755 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -249,6 +249,13 @@ public:  	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE  	std::string getClickUUID() const { return mClickUUID; }; +	// mClickTarget is received from message and governs how link will be opened +	// use this to enforce your own way of opening links inside plugins +	void setOverrideClickTarget(const std::string &target); +	void resetOverrideClickTarget() { mClickEnforceTarget = false; }; +	bool isOverrideClickTarget() const { return mClickEnforceTarget; } +	std::string getOverrideClickTarget() const { return mOverrideClickTarget; }; +  	// These are valid during MEDIA_EVENT_DEBUG_MESSAGE  	std::string getDebugMessageText() const { return mDebugMessageText; };  	std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; @@ -404,6 +411,8 @@ protected:  	std::string		mClickNavType;  	std::string		mClickTarget;  	std::string		mClickUUID; +	bool			mClickEnforceTarget; +	std::string		mOverrideClickTarget;  	std::string		mDebugMessageText;  	std::string		mDebugMessageLevel;  	S32				mGeometryX; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 29747cb09c..9eff74f1e8 100755 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -317,9 +317,9 @@ S32 LLPrimitive::setTEMaterialID(const U8 index, const LLMaterialID& pMaterialID  	return mTextureList.setMaterialID(index, pMaterialID);  } -S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) +S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)  { -	return mTextureList.setMaterialParams(index, pMaterialParams); +	return mTextureList.setMaterialParams(index, pMaterialParams, isInitFromServer);  }  LLMaterialPtr LLPrimitive::getTEMaterialParams(const U8 index) @@ -1869,9 +1869,12 @@ BOOL LLSculptParams::pack(LLDataPacker &dp) const  BOOL LLSculptParams::unpack(LLDataPacker &dp)  { -	dp.unpackUUID(mSculptTexture, "texture"); -	dp.unpackU8(mSculptType, "type"); -	 +	U8 type; +	LLUUID id; +	dp.unpackUUID(id, "texture"); +	dp.unpackU8(type, "type"); + +	setSculptTexture(id, type);  	return TRUE;  } @@ -1896,8 +1899,7 @@ bool LLSculptParams::operator==(const LLNetworkData& data) const  void LLSculptParams::copy(const LLNetworkData& data)  {  	const LLSculptParams *param = (LLSculptParams*)&data; -	mSculptTexture = param->mSculptTexture; -	mSculptType = param->mSculptType; +	setSculptTexture(param->mSculptTexture, param->mSculptType);  } @@ -1915,20 +1917,38 @@ LLSD LLSculptParams::asLLSD() const  bool LLSculptParams::fromLLSD(LLSD& sd)  {  	const char *w; -	w = "texture"; +	U8 type; +	w = "type";  	if (sd.has(w))  	{ -		setSculptTexture( sd[w] ); -	} else goto fail; -	w = "type"; +		type = sd[w].asInteger(); +	} +	else return false; + +	w = "texture";  	if (sd.has(w))  	{ -		setSculptType( (U8)sd[w].asInteger() ); -	} else goto fail; -	 +		setSculptTexture(sd[w], type); +	} +	else return false; +  	return true; - fail: -	return false; +} + +void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type) +{ +	U8 type = sculpt_type & LL_SCULPT_TYPE_MASK; +	U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK; +	if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX) +	{ +		mSculptTexture.set(SCULPT_DEFAULT_TEXTURE); +		mSculptType = LL_SCULPT_TYPE_SPHERE; +	} +	else +	{ +		mSculptTexture = texture_id; +		mSculptType = sculpt_type; +	}  }  //============================================================================ diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 1bf83e36b4..54870fbb10 100755 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -259,9 +259,8 @@ public:  	operator LLSD() const { return asLLSD(); }  	bool fromLLSD(LLSD& sd); -	void setSculptTexture(const LLUUID& id) { mSculptTexture = id; } +	void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type);  	LLUUID getSculptTexture() const         { return mSculptTexture; } -	void setSculptType(U8 type)             { mSculptType = type; }  	U8 getSculptType() const                { return mSculptType; }  }; @@ -385,7 +384,7 @@ public:  	virtual S32 setTEMediaFlags(const U8 te, const U8 flags);  	virtual S32 setTEGlow(const U8 te, const F32 glow);  	virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); -	virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams); +	virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);  	virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed  	virtual void setTESelected(const U8 te, bool sel); diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index f4f08248b8..6aae2f97c6 100755 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -368,11 +368,18 @@ S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMateri  	return TEM_CHANGE_NONE;  } -S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) +S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)  {  	if (index < mEntryList.size())  	{ -		return mEntryList[index]->setMaterialParams(pMaterialParams); +		if (!isInitFromServer && mEntryList[index]->isMatParamsInitFromServer()) +		{ +			return TEM_CHANGE_NONE; +		} +		else +		{ +			return mEntryList[index]->setMaterialParams(pMaterialParams); +		}  	}  	return TEM_CHANGE_NONE;  } diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index 49c636e40f..63e6372405 100755 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -105,7 +105,7 @@ public:  	S32 setMediaFlags(const U8 index, const U8 media_flags);  	S32 setGlow(const U8 index, const F32 glow);  	S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID); -	S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams); +	S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);  	LLMaterialPtr getMaterialParams(const U8 index); diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 284dfc15f4..6020031099 100755 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -63,6 +63,7 @@ LLTextureEntry::LLTextureEntry()    : mMediaEntry(NULL)    , mSelected(false)    , mMaterialUpdatePending(false) +  , mInitMatParamsFromServer(false)  {  	init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);  } @@ -71,6 +72,7 @@ LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)    : mMediaEntry(NULL)    , mSelected(false)    , mMaterialUpdatePending(false) +  , mInitMatParamsFromServer(false)  {  	init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);  } @@ -79,6 +81,7 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)    : mMediaEntry(NULL)    , mSelected(false)    , mMaterialUpdatePending(false) +  , mInitMatParamsFromServer(false)  {  	mID = rhs.mID;  	mScaleS = rhs.mScaleS; @@ -562,6 +565,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)  		mMaterialUpdatePending = true;  	}  	mMaterial = pMaterialParams; +	this->mInitMatParamsFromServer = TRUE;  	return TEM_CHANGE_TEXTURE;  } diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index a40c3988f2..81e2e8a5a2 100755 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -160,6 +160,8 @@ public:  	const LLMaterialID& getMaterialID() const { return mMaterialID; };  	const LLMaterialPtr getMaterialParams() const { return mMaterial; }; +	bool isMatParamsInitFromServer() const { return mInitMatParamsFromServer; }; +      // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.      // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()      // to NOT return NULL.   @@ -217,6 +219,8 @@ protected:  	bool                mMaterialUpdatePending;  	LLMaterialID        mMaterialID;  	LLMaterialPtr		mMaterial; +	bool                mInitMatParamsFromServer; // Flag to identification when material paramas initialized from  +  	// Note the media data is not sent via the same message structure as the rest of the TE  	LLMediaEntry*		mMediaEntry;			// The media data for the face diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 3396213f1c..c937d190c6 100755 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -153,7 +153,7 @@ void LLDockableFloater::setVisible(BOOL visible)  		mDockControl.get()->repositionDockable();  	} -	if (visible) +	if (visible && !isMinimized())  	{  		LLFloater::setFrontmost(getAutoFocus());  	} diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 81a0204bc5..3def0386e1 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -129,6 +129,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)  	mSelectPending(FALSE),  	mLabelStyle( LLFontGL::NORMAL ),  	mHasVisibleChildren(FALSE), +	mIsFolderComplete(true),      mLocalIndentation(p.folder_indentation),  	mIndentation(0),  	mItemHeight(p.item_height), @@ -674,7 +675,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L  	//  	const S32 TOP_PAD = default_params.item_top_pad; -	if (hasVisibleChildren()) +	if (hasVisibleChildren() || !isFolderComplete())  	{  		LLUIImage* arrow_image = default_params.folder_arrow_image;  		gl_draw_scaled_rotated_image( @@ -934,6 +935,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):  	mLastArrangeGeneration( -1 ),  	mLastCalculatedWidth(0)  { +	// folder might have children that are not loaded yet. Mark it as incomplete until chance to check it. +	mIsFolderComplete = false;  }  void LLFolderViewFolder::updateLabelRotation() @@ -1016,6 +1019,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )  		mHasVisibleChildren = found;  	} +	if (!mIsFolderComplete) +	{ +		mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); +	} + +  	// calculate height as a single item (without any children), and reshapes rectangle to match  	LLFolderViewItem::arrange( width, height ); @@ -1463,31 +1472,37 @@ void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection)  	LLFolderView* root = getRoot(); -	for (std::vector<LLFolderViewItem*>::iterator it = items_to_select_forward.begin(), end_it = items_to_select_forward.end(); +	BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected + +	// array always go from 'will be selected' to ' will be unselected', iterate +	// in opposite direction to simplify identification of 'point of origin' in +	// case it is in the list we are working with +	for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend();  		it != end_it;  		++it)  	{  		LLFolderViewItem* item = *it; -		if (item->isSelected()) +		BOOL selected = item->isSelected(); +		if (!selection_reverse && selected)  		{ -			root->removeFromSelectionList(item); +			// it is our 'point of origin' where we shift/expand from +			// don't deselect it +			selection_reverse = TRUE;  		}  		else  		{ -			item->selectItem(); +			root->changeSelection(item, !selected);  		} -		root->addToSelectionList(item);  	} -	if (new_selection->isSelected()) +	if (selection_reverse)  	{ -		root->removeFromSelectionList(new_selection); +		// at some point we reversed selection, first element should be deselected +		root->changeSelection(last_selected_item_from_cur, FALSE);  	} -	else -	{ -		new_selection->selectItem(); -	} -	root->addToSelectionList(new_selection); + +	// element we expand to should always be selected +	root->changeSelection(new_selection, TRUE);  } @@ -1677,7 +1692,9 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r  	mIsOpen = openitem;  		if(!was_open && openitem)  		{ -		getViewModelItem()->openItem(); +			getViewModelItem()->openItem(); +			// openItem() will request content, it won't be incomplete +			mIsFolderComplete = true;  		}  		else if(was_open && !openitem)  		{ diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index ed4496cfaa..0322c8836d 100755 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -115,6 +115,7 @@ protected:  	F32							mControlLabelRotation;  	LLFolderView*				mRoot;  	bool						mHasVisibleChildren, +								mIsFolderComplete, // indicates that some children were not loaded/added yet  								mIsCurSelection,  								mDragAndDropTarget,  								mIsMouseOverTitle, @@ -212,6 +213,9 @@ public:  	BOOL hasVisibleChildren() { return mHasVisibleChildren; } +	// true if object can't have children +	BOOL isFolderComplete() { return mIsFolderComplete; } +  	// Call through to the viewed object and return true if it can be  	// removed. Returns true if it's removed.  	//virtual BOOL removeRecursively(BOOL single_item); diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index d60e36183b..a395af537a 100755 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -122,6 +122,7 @@ public:  	virtual void filter() = 0;  	virtual bool contentsReady() = 0; +	virtual bool isFolderComplete(class LLFolderViewFolder*) = 0;  	virtual void setFolderView(LLFolderView* folder_view) = 0;  	virtual LLFolderViewFilter& getFilter() = 0;  	virtual const LLFolderViewFilter& getFilter() const = 0; @@ -444,6 +445,7 @@ public:  	// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,  	// this method needs to be overloaded and return the relevant fetch status.  	virtual bool contentsReady()					{ return true; } +	virtual bool isFolderComplete(LLFolderViewFolder* folder)					{ return true; }  	struct ViewModelCompare  	{ diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7cdbcb0621..3b8d282445 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -225,7 +225,6 @@ BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)  BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask)  { -	setHover(TRUE);  	getWindow()->setCursor(UI_CURSOR_ARROW);  	return TRUE;  } @@ -236,6 +235,18 @@ BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask)  	return LLUICtrl::handleRightMouseDown(x,y,mask);  } +void LLMenuItemGL::onMouseEnter(S32 x, S32 y, MASK mask) +{ +	setHover(TRUE); +	LLUICtrl::onMouseEnter(x,y,mask); +} + +void LLMenuItemGL::onMouseLeave(S32 x, S32 y, MASK mask) +{ +	setHover(FALSE); +	LLUICtrl::onMouseLeave(x,y,mask); +} +  //virtual  BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)  { @@ -533,9 +544,6 @@ void LLMenuItemGL::draw( void )  			gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1);  		}  	} - -	// clear got hover every frame -	setHover(FALSE);  }  BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& text ) @@ -1043,7 +1051,7 @@ void LLMenuItemBranchGL::onCommit( void )  	// keyboard navigation automatically propagates highlight to sub-menu  	// to facilitate fast menu control via jump keys -	if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem()) +	if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem())  	{  		getBranch()->highlightNextItem(NULL);  	} @@ -1456,7 +1464,16 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )  {  	// switch to mouse control mode  	LLMenuGL::setKeyboardMode(FALSE); -	onCommit(); + +	if (getVisible() && isOpen()) +	{ +		LLMenuGL::sMenuContainer->hideMenus(); +	} +	else +	{ +		onCommit(); +	} +  	make_ui_sound("UISndClick");  	return TRUE;  } @@ -1588,10 +1605,6 @@ void LLMenuItemBranchDownGL::draw( void )  			gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS);  		}  	} - -	// reset every frame so that we only show highlight  -	// when we get hover events on that frame -	setHover(FALSE);  } @@ -3625,8 +3638,24 @@ BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )  	BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;  	if (!handled)  	{ -		// clicked off of menu, hide them all -		hideMenus(); +		LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu(); +		LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL; +		if (parent_menu && parent_menu->getVisible()) +		{ +			// don't hide menu if parent was hit +			LLRect parent_rect; +			parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this); +			if (!parent_rect.pointInRect(x, y)) +			{ +				// clicked off of menu and parent, hide them all +				hideMenus(); +			} +		} +		else +		{ +			// no visible parent, clicked off of menu, hide them all +			hideMenus(); +		}  	}  	return handled;  } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index ae9b169691..28f9e3b6e9 100755 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -158,6 +158,10 @@ public:  	virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );  	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );  	virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + +	virtual void	onMouseEnter(S32 x, S32 y, MASK mask); +	virtual void	onMouseLeave(S32 x, S32 y, MASK mask); +  	virtual void draw( void );  	BOOL getHover() const { return mGotHover; } diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index ea96fc573d..1fdd05a11c 100755 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -29,6 +29,7 @@  #include "linden_common.h"  #include "llsearcheditor.h" +#include "llkeyboard.h"  LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)  :	LLUICtrl(p), @@ -166,4 +167,16 @@ void LLSearchEditor::handleKeystroke()  	{  		mKeystrokeCallback(this, getValue());  	} + +	KEY key = gKeyboard->currentKey(); +	if (key == KEY_LEFT || +		key == KEY_RIGHT) +	{ +			return; +	} + +	if (mTextChangedCallback) +	{ +		mTextChangedCallback(this, getValue()); +	}  } diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index c2d7916938..3b12868225 100755 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -82,12 +82,14 @@ public:  	virtual void	setFocus( BOOL b );  	void			setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } +	void			setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }  protected:  	void onClearButtonClick(const LLSD& data);  	virtual void handleKeystroke();  	commit_callback_t mKeystrokeCallback; +	commit_callback_t mTextChangedCallback;  	LLLineEditor* mSearchEditor;  	LLButton* mSearchButton;  	LLButton* mClearButton; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 602a703450..bf660849c4 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -37,6 +37,7 @@  #include "lltextparser.h"  #include "lltextutil.h"  #include "lltooltip.h" +#include "lltrans.h"  #include "lluictrl.h"  #include "llurlaction.h"  #include "llurlregistry.h" @@ -2060,27 +2061,33 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  			// add icon before url if need  			LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); +			if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) +			{ +				setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); +			}  			// output the styled Url  			appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); +			bool tooltip_required =  !match.getTooltip().empty(); + +			// set the tooltip for the Url label +			if (tooltip_required) +			{ +				setLastSegmentToolTip(match.getTooltip()); +			} -			// show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries +			// show query part of url with gray color only for LLUrlEntryHTTP url entries  			std::string label = match.getQuery();  			if (label.size())  			{  				link_params.color = LLColor4::grey;  				link_params.readonly_color = LLColor4::grey;  				appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); -			} -			 -			// set the tooltip for the Url label -			if (! match.getTooltip().empty()) -			{ -				segment_set_t::iterator it = getSegIterContaining(getLength()-1); -				if (it != mSegments.end()) + +				// set the tooltip for the query part of url +				if (tooltip_required)  				{ -					LLTextSegmentPtr segment = *it; -					segment->setToolTip(match.getTooltip()); +					setLastSegmentToolTip(match.getTooltip());  				}  			} @@ -2107,6 +2114,16 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  	}  } +void LLTextBase::setLastSegmentToolTip(const std::string &tooltip) +{ +	segment_set_t::iterator it = getSegIterContaining(getLength()-1); +	if (it != mSegments.end()) +	{ +		LLTextSegmentPtr segment = *it; +		segment->setToolTip(tooltip); +	} +} +  static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text");  void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) @@ -3557,6 +3574,22 @@ S32	 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  	return 0;  } +BOOL LLImageTextSegment::handleToolTip(S32 x, S32 y, MASK mask) +{ +	if (!mTooltip.empty()) +	{ +		LLToolTipMgr::instance().show(mTooltip); +		return TRUE; +	} + +	return FALSE; +} + +void LLImageTextSegment::setToolTip(const std::string& tooltip) +{ +	mTooltip = tooltip; +} +  F32	LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)  {  	if ( (start >= 0) && (end <= mEnd - mStart)) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index dfc10923f3..87809aa8fb 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -241,9 +241,15 @@ public:  	S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;  	F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); +	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, MASK mask); +	/*virtual*/ void	setToolTip(const std::string& tooltip); +  private:  	class LLTextBase&	mEditor;  	LLStyleConstSP	mStyle; + +protected: +	std::string		mTooltip;  };  typedef LLPointer<LLTextSegment> LLTextSegmentPtr; @@ -392,6 +398,8 @@ public:  	const	std::string& 	getLabel()	{ return mLabel.getString(); }  	const	LLWString&		getWlabel() { return mLabel.getWString();} +	void					setLastSegmentToolTip(const std::string &tooltip); +  	/**  	 * If label is set, draws text label (which is LLLabelTextSegment)  	 * that is visible when no user text provided diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 6db0d88998..7f6cc22e90 100755 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -203,10 +203,10 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const  {  	LLUriParser up(unescapeUrl(url)); -	std::string query; +	std::string label;  	up.extractParts(); -	up.glueSecond(query); - +	up.glueFirst(label); +	std::string query = url.substr(label.size());  	return query;  } @@ -229,7 +229,7 @@ static std::string getStringAfterToken(const std::string str, const std::string  LLUrlEntryHTTP::LLUrlEntryHTTP()  	: LLUrlEntryBase()  { -	mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", +	mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?\\.[a-z](:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",  							boost::regex::perl|boost::regex::icase);  	mMenuName = "menu_url_http.xml";  	mTooltip = LLTrans::getString("TooltipHttpUrl"); @@ -287,46 +287,6 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const  	return getUrlFromWikiLink(string);  } -// -// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com -// -LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol() -	: LLUrlEntryBase() -{ -	mPattern = boost::regex("(" -				"\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR -				"|" // or -				"(?<!@)\\b[^[:space:]:@/>]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net -				")", -				boost::regex::perl|boost::regex::icase); -	mMenuName = "menu_url_http.xml"; -	mTooltip = LLTrans::getString("TooltipHttpUrl"); -} - -std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb) -{ -	return urlToLabelWithGreyQuery(url); -} - -std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const -{ -	return urlToGreyQuery(url); -} - -std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const -{ -	if (string.find("://") == std::string::npos) -	{ -		return "http://" + escapeUrl(string); -	} -	return escapeUrl(string); -} - -std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const -{ -	return unescapeUrl(url); -} -  LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL()  	: LLUrlEntryBase()  { @@ -489,7 +449,7 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const  //  LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL()  {                               -	mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*", +	mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*",  		boost::regex::perl|boost::regex::icase);  	mIcon = "Hand"; @@ -527,7 +487,7 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const  //  LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()    { -	mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)", +	mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",  		boost::regex::perl|boost::regex::icase);  	mIcon = "Hand"; @@ -1401,9 +1361,43 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)  	return mIcon;  } +// +// LLUrlEntryEmail Describes a generic mailto: Urls +// +LLUrlEntryEmail::LLUrlEntryEmail() +	: LLUrlEntryBase() +{ +	mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,6}", +							boost::regex::perl | boost::regex::icase); +	mMenuName = "menu_url_email.xml"; +	mTooltip = LLTrans::getString("TooltipEmail"); +} + +std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ +	int pos = url.find("mailto:"); + +	if (pos == std::string::npos) +	{ +		return escapeUrl(url); +	} + +	std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8)); +	return ret; +} + +std::string LLUrlEntryEmail::getUrl(const std::string &string) const +{ +	if (string.find("mailto:") == std::string::npos) +	{ +		return "mailto:" + escapeUrl(string); +	} +	return escapeUrl(string); +} +  LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile()  { -    mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*", +    mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/profile",          boost::regex::perl|boost::regex::icase);      mIcon = "Generic_Experience";  	mMenuName = "menu_url_experience.xml"; diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index dd1f257a3d..413c20a657 100755 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -157,19 +157,6 @@ public:  	/*virtual*/ std::string getUrl(const std::string &string) const;  }; -/// -/// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com -/// -class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase -{ -public: -	LLUrlEntryHTTPNoProtocol(); -	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); -	/*virtual*/ std::string getQuery(const std::string &url) const; -	/*virtual*/ std::string getUrl(const std::string &string) const; -	/*virtual*/ std::string getTooltip(const std::string &url) const; -}; -  class LLUrlEntryInvalidSLURL : public LLUrlEntryBase  {  public: @@ -506,5 +493,16 @@ public:  	/*virtual*/ std::string getIcon(const std::string &url);  }; +/// +/// LLUrlEntryEmail Describes a generic mailto: Urls +/// +class LLUrlEntryEmail : public LLUrlEntryBase +{ +public: +	LLUrlEntryEmail(); +	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +	/*virtual*/ std::string getUrl(const std::string &string) const; +}; +  #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 2085505947..69eefa736c 100755 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -76,9 +76,7 @@ LLUrlRegistry::LLUrlRegistry()  	registerUrl(new LLUrlEntrySL());  	mUrlEntrySLLabel = new LLUrlEntrySLLabel();  	registerUrl(mUrlEntrySLLabel); -	// most common pattern is a URL without any protocol, -	// e.g., "secondlife.com" -	registerUrl(new LLUrlEntryHTTPNoProtocol());	 +	registerUrl(new LLUrlEntryEmail());  }  LLUrlRegistry::~LLUrlRegistry() @@ -155,11 +153,9 @@ static bool stringHasUrl(const std::string &text)  	return (text.find("://") != std::string::npos ||  			text.find("www.") != std::string::npos ||  			text.find(".com") != std::string::npos || -			text.find(".net") != std::string::npos || -			text.find(".edu") != std::string::npos || -			text.find(".org") != std::string::npos ||  			text.find("<nolink>") != std::string::npos || -			text.find("<icon") != std::string::npos); +			text.find("<icon") != std::string::npos || +			text.find("@") != std::string::npos);  }  bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) @@ -218,9 +214,40 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL  	// did we find a match? if so, return its details in the match object  	if (match_entry)  	{ + +		// Skip if link is an email with an empty username (starting with @). See MAINT-5371. +		if (match_start > 0 && text.substr(match_start - 1, 1) == "@") +			return false; +  		// fill in the LLUrlMatch object and return it  		std::string url = text.substr(match_start, match_end - match_start + 1); +		LLUrlEntryBase *stripped_entry = NULL; +		if(LLStringUtil::containsNonprintable(url)) +		{ +			LLStringUtil::stripNonprintable(url); + +			std::vector<LLUrlEntryBase *>::iterator iter; +			for (iter = mUrlEntry.begin(); iter != mUrlEntry.end(); ++iter) +			{ +				LLUrlEntryBase *url_entry = *iter; +				U32 start = 0, end = 0; +				if (matchRegex(url.c_str(), url_entry->getPattern(), start, end)) +				{ +					if (mLLUrlEntryInvalidSLURL == *iter) +					{ +						if(url_entry && url_entry->isSLURLvalid(url)) +						{ +							continue; +						} +					} +					stripped_entry = url_entry; +					break; +				} +			} +		} + +  		if (match_entry == mUrlEntryTrusted)  		{  			LLUriParser up(url); @@ -228,10 +255,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL  			url = up.normalizedUri();  		} +		std::string url_label = stripped_entry? stripped_entry->getLabel(url, cb) : match_entry->getLabel(url, cb); +		std::string url_query = stripped_entry? stripped_entry->getQuery(url) : match_entry->getQuery(url);  		match.setValues(match_start, match_end,  						match_entry->getUrl(url), -						match_entry->getLabel(url, cb), -						match_entry->getQuery(url), +						url_label, +						url_query,  						match_entry->getTooltip(url),  						match_entry->getIcon(url),  						match_entry->getStyle(), diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 15f2354552..96e94c0f80 100755 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -653,79 +653,6 @@ namespace tut  	void object::test<11>()  	{  		// -		// test LLUrlEntryHTTPNoProtocol - general URLs without a protocol -		// -		LLUrlEntryHTTPNoProtocol url; - -		testRegex("naked .com URL", url, -				  "see google.com", -				  "http://google.com"); - -		testRegex("naked .org URL", url, -				  "see en.wikipedia.org for details", -				  "http://en.wikipedia.org"); - -		testRegex("naked .net URL", url, -				  "example.net", -				  "http://example.net"); - -		testRegex("naked .edu URL (2 instances)", url, -				  "MIT web site is at web.mit.edu and also www.mit.edu", -				  "http://web.mit.edu"); - -		testRegex("don't match e-mail addresses", url, -				  "test@lindenlab.com", -				  ""); - -		testRegex(".com URL with path", url, -				  "see secondlife.com/status for grid status", -				  "http://secondlife.com/status"); - -		testRegex(".com URL with port", url, -				  "secondlife.com:80", -				  "http://secondlife.com:80"); - -		testRegex(".com URL with port and path", url, -				  "see secondlife.com:80/status", -				  "http://secondlife.com:80/status"); - -		testRegex("www.*.com URL with port and path", url, -				  "see www.secondlife.com:80/status", -				  "http://www.secondlife.com:80/status"); - -		testRegex("invalid .com URL [1]", url, -				  "..com", -				  ""); - -		testRegex("invalid .com URL [2]", url, -				  "you.come", -				  ""); - -		testRegex("invalid .com URL [3]", url, -				  "recommended", -				  ""); - -		testRegex("invalid .edu URL", url, -				  "hi there scheduled maitenance has begun", -				  ""); - -		testRegex("invalid .net URL", url, -				  "foo.netty", -				  ""); - -		testRegex("XML tags around URL [1]", url, -				  "<foo>secondlife.com</foo>", -				  "http://secondlife.com"); - -		testRegex("XML tags around URL [2]", url, -				  "<foo>secondlife.com/status?bar=1</foo>", -				  "http://secondlife.com/status?bar=1"); -	} - -	template<> template<> -	void object::test<12>() -	{ -		//  		// test LLUrlEntryNoLink - turn off hyperlinking  		//  		LLUrlEntryNoLink url; @@ -752,7 +679,7 @@ namespace tut  	}  	template<> template<> -	void object::test<13>() +	void object::test<12>()  	{  		//  		// test LLUrlEntryRegion - secondlife:///app/region/<location> URLs @@ -860,4 +787,101 @@ namespace tut  			"secondlife:///app/region/Product%20Engine",  			"Product Engine");  	} + +	template<> template<> +	void object::test<13>() +	{ +		// +		// test LLUrlEntryemail - general emails +		// +		LLUrlEntryEmail url; + +		// Regex tests. +		testRegex("match e-mail addresses", url, +				  "test@lindenlab.com", +				  "mailto:test@lindenlab.com"); + +		testRegex("match e-mail addresses with mailto: prefix", url, +				  "mailto:test@lindenlab.com", +				  "mailto:test@lindenlab.com"); + +		testRegex("match e-mail addresses with different domains", url, +				  "test@foo.org.us", +				  "mailto:test@foo.org.us"); + +		testRegex("match e-mail addresses with different domains", url, +				  "test@foo.bar", +				  "mailto:test@foo.bar"); + +		testRegex("don't match incorrect e-mail addresses", url, +				  "test @foo.com", +				  ""); + +		testRegex("don't match incorrect e-mail addresses", url, +				  "test@ foo.com", +				  ""); +	} + +	template<> template<> +	void object::test<14>() +	{ +		// +		// test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls +		// +		LLUrlEntrySecondlifeURL url; + +		testRegex("match urls with protocol", url, +				  "this url should match http://lindenlab.com/products/second-life", +				  "http://lindenlab.com/products/second-life"); + +		testRegex("match urls with protocol", url, +				  "search something https://marketplace.secondlife.com/products/search on marketplace and test the https", +				  "https://marketplace.secondlife.com/products/search"); + +		testRegex("match urls with port", url, +				  "let's specify some port http://secondlife.com:888/status", +				  "http://secondlife.com:888/status"); + +		testRegex("don't match urls w/o protocol", url, +				  "looks like an url something www.marketplace.secondlife.com/products but no https prefix", +				  ""); + +		testRegex("but with a protocol www is fine", url, +				  "so let's add a protocol http://www.marketplace.secondlife.com:8888/products", +				  "http://www.marketplace.secondlife.com:8888/products"); + +		testRegex("don't match urls w/o protocol", url, +				  "and even no www something secondlife.com/status", +				  ""); +	} + +	template<> template<> +	void object::test<15>() +	{ +		// +		// test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls +		// + +		LLUrlEntrySimpleSecondlifeURL url; + +		testRegex("match urls with a protocol", url, +				  "this url should match http://lindenlab.com", +				  "http://lindenlab.com"); + +		testRegex("match urls with a protocol", url, +				  "search something https://marketplace.secondlife.com on marketplace and test the https", +				  "https://marketplace.secondlife.com"); + +		testRegex("don't match urls w/o protocol", url, +				  "looks like an url something www.marketplace.secondlife.com but no https prefix", +				  ""); + +		testRegex("but with a protocol www is fine", url, +				  "so let's add a protocol http://www.marketplace.secondlife.com", +				  "http://www.marketplace.secondlife.com"); + +		testRegex("don't match urls w/o protocol", url, +				  "and even no www something lindenlab.com", +				  ""); +	}  } diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 5720660034..1b24250618 100755 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -49,8 +49,8 @@ LLSplashScreen *gSplashScreenp = NULL;  BOOL gDebugClicks = FALSE;  BOOL gDebugWindowProc = FALSE; -const S32 gURLProtocolWhitelistCount = 4; -const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:" }; +const S32 gURLProtocolWhitelistCount = 5; +const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" };  // CP: added a handler list - this is what's used to open the protocol and is based on registry entry  //	   only meaningful difference currently is that file: protocols are opened using http: diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index f02052ca6a..e6e8f27f53 100755 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -53,6 +53,7 @@ bool runMainLoop();  void initMainLoop();  void cleanupViewer();  void handleUrl(const char* url); +void dispatchUrl(std::string url);  /* Defined in llwindowmacosx-objc.mm: */  int createNSApp(int argc, const char **argv); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 98d0ba53f6..f05836742a 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1730,6 +1730,17 @@        <key>Value</key>        <integer>1</integer>      </map> +	<key>ChatShowIcons</key> +	<map> +		<key>Comment</key> +		<string>Show/hide people icons in chat</string> +		<key>Persist</key> +		<integer>1</integer> +		<key>Type</key> +		<string>Boolean</string> +		<key>Value</key> +		<integer>1</integer> +	</map>      <key>CheesyBeacon</key>      <map>        <key>Comment</key> @@ -11029,6 +11040,17 @@        <key>Value</key>        <integer>1</integer>      </map> +	<key>GlobalShowIconsOverride</key> +	<map> +		<key>Comment</key> +		<string>Show/hide people icons in any list. This option should be set back to 0 when icons are enabled locally for the lists</string> +		<key>Persist</key> +		<integer>1</integer> +		<key>Type</key> +		<string>Boolean</string> +		<key>Value</key> +		<integer>0</integer> +	</map>      <key>FriendsSortOrder</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index 595c11fae2..58fb01d200 100755 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -29,6 +29,7 @@ out vec4 frag_data[3];  #define frag_data gl_FragData  #endif +uniform float minimum_alpha;  uniform sampler2D diffuseMap;  uniform sampler2D bumpMap; @@ -47,16 +48,23 @@ vec2 encode_normal(vec3 n)  void main()   { -	vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb; -	vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0; +	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy); +	 +	if(col.a < minimum_alpha) +	{ +		discard; +    }		 +		col *= vertex_color; +		 +		vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0; -	vec3 tnorm = vec3(dot(norm,vary_mat0), +		vec3 tnorm = vec3(dot(norm,vary_mat0),  			  dot(norm,vary_mat1),  			  dot(norm,vary_mat2)); -	frag_data[0] = vec4(col, 0.0); -	frag_data[1] = vertex_color.aaaa; // spec -	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested -	vec3 nvn = normalize(tnorm); -	frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); +		frag_data[0] = vec4(col.rgb, 0.0); +		frag_data[1] = vertex_color.aaaa; // spec +		//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested +		vec3 nvn = normalize(tnorm); +		frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0);	  } diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 95cdf90e99..b8677fd9e4 100755 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -165,7 +165,9 @@ lbl_configure_default_lang:  	StrCpy $LANGUAGE $0
  # For silent installs, no language prompt, use default
 -    IfSilent lbl_return
 +    IfSilent 0 +3
 +    StrCpy $SKIP_AUTORUN "true"
 +    Goto lbl_return
      StrCmp $SKIP_DIALOGS "true" lbl_return
  lbl_build_menu:
 diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 092d868bb9..297bd9a05b 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2843,7 +2843,7 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */  // This implementation should mirror LLAgentInfo::hasPowerInGroup  BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const  { -	if (isGodlike()) +	if (isGodlikeWithoutAdminMenuFakery())  		return true;  	// GP_NO_POWERS can also mean no power is enough to grant an ability. diff --git a/indra/newview/llagentdata.cpp b/indra/newview/llagentdata.cpp index 5f6a082d75..d2c644a06f 100755 --- a/indra/newview/llagentdata.cpp +++ b/indra/newview/llagentdata.cpp @@ -31,3 +31,4 @@  LLUUID gAgentID;  LLUUID gAgentSessionID; +std::string gAgentUsername; diff --git a/indra/newview/llagentdata.h b/indra/newview/llagentdata.h index 83d6a53d5e..efdd97f6c4 100755 --- a/indra/newview/llagentdata.h +++ b/indra/newview/llagentdata.h @@ -30,5 +30,6 @@  extern LLUUID gAgentID;  extern LLUUID gAgentSessionID; +extern std::string gAgentUsername;  #endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 35593dd4ff..53ae3c62ec 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1869,6 +1869,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)  		{  			++n_clothes;  		} +		else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) +		{ +			return isAgentAvatarValid(); +		}  		else  		{  			LL_WARNS() << "Unexpected wearable type" << LL_ENDL; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9b9b591cd1..fbf2a04bcc 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2784,10 +2784,12 @@ bool LLAppViewer::initConfiguration()  	//  	gWindowTitle = LLTrans::getString("APP_NAME");  #if LL_DEBUG -	gWindowTitle += std::string(" [DEBUG] ") + gArgs; -#else -	gWindowTitle += std::string(" ") + gArgs; +	gWindowTitle += std::string(" [DEBUG]")  #endif +	if (!gArgs.empty()) +	{ +		gWindowTitle += std::string(" ") + gArgs; +	}  	LLStringUtil::truncate(gWindowTitle, 255);  	//RN: if we received a URL, hand it off to the existing instance. @@ -4948,6 +4950,7 @@ void LLAppViewer::idle()  		gIdleCallbacks.callFunctions();  		gInventory.idleNotifyObservers(); +		LLAvatarTracker::instance().idleNotifyObservers();  	}  	// Metrics logging (LLViewerAssetStats, etc.) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 56154a2de3..09227806fd 100755 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -62,9 +62,10 @@ namespace  	// They are not used immediately by the app.  	int gArgC;  	char** gArgV; -	LLAppViewerMacOSX* gViewerAppPtr; +	LLAppViewerMacOSX* gViewerAppPtr = NULL;      void (*gOldTerminateHandler)() = NULL; +    std::string gHandleSLURL;  }  static void exceptionTerminateHandler() @@ -107,7 +108,11 @@ bool initViewer()  	{  		LL_WARNS() << "Application init failed." << LL_ENDL;  	} - +    else if (!gHandleSLURL.empty()) +    { +        dispatchUrl(gHandleSLURL); +        gHandleSLURL = ""; +    }  	return ok;  } @@ -393,22 +398,31 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute()  void handleUrl(const char* url_utf8)  { -    if (url_utf8) +    if (url_utf8 && gViewerAppPtr)      { -        std::string url = url_utf8; -	    // Safari 3.2 silently mangles secondlife:///app/ URLs into -	    // secondlife:/app/ (only one leading slash). -	    // Fix them up to meet the URL specification. JC -	    const std::string prefix = "secondlife:/app/"; -	    std::string test_prefix = url.substr(0, prefix.length()); -	    LLStringUtil::toLower(test_prefix); -	    if (test_prefix == prefix) -	    { -		    url.replace(0, prefix.length(), "secondlife:///app/"); -	    } -		 -	    LLMediaCtrl* web = NULL; -    	const bool trusted_browser = false; -	    LLURLDispatcher::dispatch(url, "", web, trusted_browser); +        gHandleSLURL = ""; +        dispatchUrl(url_utf8);      } +    else if (url_utf8) +    { +        gHandleSLURL = url_utf8; +    } +} + +void dispatchUrl(std::string url) +{ +    // Safari 3.2 silently mangles secondlife:///app/ URLs into +    // secondlife:/app/ (only one leading slash). +    // Fix them up to meet the URL specification. JC +    const std::string prefix = "secondlife:/app/"; +    std::string test_prefix = url.substr(0, prefix.length()); +    LLStringUtil::toLower(test_prefix); +    if (test_prefix == prefix) +    { +        url.replace(0, prefix.length(), "secondlife:///app/"); +    } +     +    LLMediaCtrl* web = NULL; +    const bool trusted_browser = false; +    LLURLDispatcher::dispatch(url, "", web, trusted_browser);  } diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 8846d1317d..c7fa375ada 100755 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -63,16 +63,18 @@ bool LLAvatarList::contains(const LLUUID& id)  	return std::find(ids.begin(), ids.end(), id) != ids.end();  } -void LLAvatarList::toggleIcons() +void LLAvatarList::setIconsVisible(bool visible)  { +	if (visible == mShowIcons) // nothing to be done here. +		return; +  	// Save the new value for new items to use. -	mShowIcons = !mShowIcons; -	gSavedSettings.setBOOL(mIconParamName, mShowIcons); -	 +	mShowIcons = visible; +  	// Show/hide icons for all existing items.  	std::vector<LLPanel*> items;  	getItems(items); -	for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++) +	for (std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)  	{  		static_cast<LLAvatarListItem*>(*it)->setAvatarIconVisible(mShowIcons);  	} @@ -187,6 +189,8 @@ void LLAvatarList::draw()  		updateAvatarNames();  	} +	setIconsVisible(gSavedSettings.getBOOL(mIconParamName) && !gSavedSettings.getBOOL("GlobalShowIconsOverride")); +  	if (mDirty)  		refresh(); diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 3542577ae3..159ff991e6 100755 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -76,7 +76,7 @@ public:  	void setSessionID(const LLUUID& session_id) { mSessionID = session_id; }  	const LLUUID& getSessionID() { return mSessionID; } -	void toggleIcons(); +	void setIconsVisible(bool visible);  	void setSpeakingIndicatorsVisible(bool visible);  	void showPermissions(bool visible);  	void sortByName(); diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index b6c5496c17..f79d1aa609 100755 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -97,7 +97,8 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id,  LLAvatarTracker::LLAvatarTracker() :  	mTrackingData(NULL),  	mTrackedAgentValid(false), -	mModifyMask(0x0)	 +	mModifyMask(0x0), +	mIsNotifyObservers(FALSE)  {  } @@ -272,7 +273,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)  					<< "]" << LL_ENDL;  		}  	} -	notifyObservers(); +	// do not notify observers here - list can be large so let it be done on idle.  	return new_buddy_count;  } @@ -473,8 +474,25 @@ void LLAvatarTracker::removeObserver(LLFriendObserver* observer)  		mObservers.end());  } +void LLAvatarTracker::idleNotifyObservers() +{ +	if (mModifyMask == LLFriendObserver::NONE && mChangedBuddyIDs.size() == 0) +	{ +		return; +	} +	notifyObservers(); +} +  void LLAvatarTracker::notifyObservers()  { +	if (mIsNotifyObservers) +	{ +		// Don't allow multiple calls. +		// new masks and ids will be processed later from idle. +		return; +	} +	mIsNotifyObservers = TRUE; +  	observer_list_t observers(mObservers);  	observer_list_t::iterator it = observers.begin();  	observer_list_t::iterator end = observers.end(); @@ -490,6 +508,7 @@ void LLAvatarTracker::notifyObservers()  	mModifyMask = LLFriendObserver::NONE;  	mChangedBuddyIDs.clear(); +	mIsNotifyObservers = FALSE;  }  void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer) @@ -531,7 +550,7 @@ void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)  // store flag for change  // and id of object change applies to  void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent) -{  +{  	mModifyMask |= mask;   	if (referent.notNull())  	{ diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 6e5fc01cd8..1f819a42fd 100755 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -143,6 +143,7 @@ public:  	// observers left behind.  	void addObserver(LLFriendObserver* observer);  	void removeObserver(LLFriendObserver* observer); +	void idleNotifyObservers();  	void notifyObservers();  	// Observers interested in updates of a particular avatar. @@ -209,6 +210,8 @@ private:  	LLAvatarTracker(const LLAvatarTracker&);  	bool operator==(const LLAvatarTracker&); +	BOOL mIsNotifyObservers; +  public:  	// don't you dare create or delete this object  	LLAvatarTracker(); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index b81b95462e..dc0835eb1c 100755 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -376,6 +376,10 @@ public:  			|| mSourceType == CHAT_SOURCE_SYSTEM)  		{  			mFrom = LLTrans::getString("SECOND_LIFE"); +			if(!chat.mFromName.empty() && (mFrom != chat.mFromName)) +			{ +				mFrom += " (" + chat.mFromName + ")"; +			}  			user_name->setValue(mFrom);  			updateMinUserNameWidth();  		} diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 8ce5aca909..307f93e28c 100755 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -483,7 +483,7 @@ void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel  		const LLAssetType::EType item_type = item->getType();  		if (item_type == LLAssetType::AT_CLOTHING) continue;  		LLPanelInventoryListItemBase* item_panel = NULL; -		if (item_type == LLAssetType::AT_OBJECT) +		if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_GESTURE)  		{  			item_panel = buildAttachemntListItem(item);  			mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false); diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index b38d472156..62f08144b9 100755 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -153,6 +153,7 @@ public:  	 * file name is conversation.log  	 */  	std::string getFileName(); +	LLConversation* findConversation(const LLIMModel::LLIMSession* session);  private: @@ -184,7 +185,7 @@ private:  	void updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name);  	void updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages); -	LLConversation* findConversation(const LLIMModel::LLIMSession* session); +  	typedef std::vector<LLConversation> conversations_vec_t;  	std::vector<LLConversation>				mConversations; diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 6e32ce60ec..328a638f2f 100755 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -136,7 +136,24 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32  		items.push_back(std::string("im"));  		items.push_back(std::string("offer_teleport"));  		items.push_back(std::string("request_teleport")); -		items.push_back(std::string("voice_call")); + +		if (getType() != CONV_SESSION_1_ON_1) +		{ +			items.push_back(std::string("voice_call")); +		} +		else +		{ +			LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL; +			if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel()) +			{ +				items.push_back(std::string("voice_call")); +			} +			else +			{ +				items.push_back(std::string("disconnect_from_voice")); +			} +		} +  		items.push_back(std::string("chat_history"));  		items.push_back(std::string("separator_chat_history"));  		items.push_back(std::string("add_friend")); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index b18e543f0a..3a6e4c4dfe 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -85,7 +85,8 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes      mHasArrow(true),  	mIsInActiveVoiceChannel(false),  	mFlashStateOn(false), -	mFlashStarted(false) +	mFlashStarted(false), +	mShowIcons(true)  {  	mFlashTimer = new LLFlashTimer();  } @@ -173,7 +174,7 @@ BOOL LLConversationViewSession::postBuild()  			if (session)  			{  				LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon"); -				icon->setVisible(true); +				icon->setVisible(mShowIcons);  				icon->setValue(session->mOtherParticipantID);  				mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true);                  mHasArrow = false; @@ -426,6 +427,49 @@ void LLConversationViewSession::showVoiceIndicator(bool visible)  	requestArrange();  } +void LLConversationViewSession::setIconsVisible(bool visible) +{ +	if (visible == mShowIcons) // nothing to be done here. +		return; + +	// Save the new value for new items to use. +	mShowIcons = visible; +		 +	// Show/hide icons for the 1-n-1 chat. +	LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem()); +	if (vmi) +	{ +		switch (vmi->getType()) +		{ +		case LLConversationItem::CONV_PARTICIPANT: +		case LLConversationItem::CONV_SESSION_1_ON_1: +		{ +			LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("avatar_icon"); +			icon->setVisible(mShowIcons); +			break; +		} +		/* +		case LLConversationItem::CONV_SESSION_AD_HOC: +		case LLConversationItem::CONV_SESSION_GROUP: +		{ +			LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("group_icon"); +			icon->setVisible(mShowIcons); +			break; +		} +		*/ +		default: +			break; +		} +	} + +	// Show/hide icons for all existing items. +	items_t::const_iterator iter; +	for (iter = getItemsBegin(); iter != getItemsEnd(); iter++) +	{ +		dynamic_cast<LLConversationViewParticipant*>(*iter)->setAvatarIconVisible(mShowIcons); +	} +} +  void LLConversationViewSession::refresh()  {  	// Refresh the session view from its model data @@ -458,6 +502,9 @@ void LLConversationViewSession::refresh()  			}  		}  	} +	 +	setIconsVisible(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride")); +	  	requestArrange();  	// Do the regular upstream refresh  	LLFolderViewFolder::refresh(); @@ -509,7 +556,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti      LLAvatarIconCtrl::Params avatar_icon_params(params.avatar_icon());      applyXUILayout(avatar_icon_params, this);      LLAvatarIconCtrl * avatarIcon = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_icon_params); -    addChild(avatarIcon);	 +    addChild(avatarIcon);  	LLButton::Params info_button_params(params.info_button());      applyXUILayout(info_button_params, this); @@ -525,6 +572,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti  BOOL LLConversationViewParticipant::postBuild()  {      mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon"); +	mAvatarIcon->setVisible(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride"));  	mInfoBtn = getChild<LLButton>("info_btn");  	mInfoBtn->setClickedCallback(boost::bind(&LLConversationViewParticipant::onInfoBtnClick, this)); @@ -588,12 +636,12 @@ S32 LLConversationViewParticipant::arrange(S32* width, S32* height)      S32 arranged = LLFolderViewItem::arrange(width, height);      //Adjusts the avatar icon based upon the indentation -    LLRect avatarRect(getIndentation(),  -                        mAvatarIcon->getRect().mTop, -                        getIndentation() + mAvatarIcon->getRect().getWidth(), -                        mAvatarIcon->getRect().mBottom); -    mAvatarIcon->setShape(avatarRect); - +	LLRect avatarRect(getIndentation(), +						mAvatarIcon->getRect().mTop, +						getIndentation() + mAvatarIcon->getRect().getWidth(), +						mAvatarIcon->getRect().mBottom); +	mAvatarIcon->setShape(avatarRect); +	      //Since dimensions changed, adjust the children (info button, speaker indicator)      updateChildren(); @@ -665,7 +713,7 @@ void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask)  S32 LLConversationViewParticipant::getLabelXPos()  { -    return getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad; +    return getIndentation() + (mAvatarIcon->getVisible() ? mAvatarIcon->getRect().getWidth() : 0) + mIconPad;  }  // static @@ -744,5 +792,18 @@ void LLConversationViewParticipant::hideSpeakingIndicator()  	mSpeakingIndicator->setVisible(false);  } +void LLConversationViewParticipant::setAvatarIconVisible(bool visible) +{ +	// Already done? Then do nothing. +	if (mAvatarIcon->getVisible() == (BOOL)visible) +	{ +		return; +	} + +	// Show/hide avatar icon. +	mAvatarIcon->setVisible(visible); +	updateChildren(); +} +  // EOF diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 5a74974302..6aaba9b59c 100644 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -83,7 +83,7 @@ public:  	LLConversationViewParticipant* findParticipant(const LLUUID& participant_id);  	void showVoiceIndicator(bool visible); - +	void setIconsVisible(bool visible);  	virtual void refresh();  	/*virtual*/ void setFlashState(bool flash_state); @@ -110,6 +110,8 @@ private:  	bool					mIsInActiveVoiceChannel; +	bool                    mShowIcons; +  	LLVoiceClientStatusObserver* mVoiceClientObserver;  	boost::signals2::connection mActiveVoiceChannelConnection; @@ -145,6 +147,7 @@ public:      /*virtual*/ S32 getLabelXPos();      /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );  	void hideSpeakingIndicator(); +	void setAvatarIconVisible(bool visible);  protected:  	friend class LLUICtrlFactory; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 33f7bc305c..7b9fd5c6c6 100755 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -864,6 +864,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)  	{  		LLDrawInfo& params = **i; +		gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);  		LLDrawPoolBump::bindBumpMap(params, bump_channel);  		pushBatch(params, mask, TRUE);  	} diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp index b50c81eedc..7f2363aadc 100644 --- a/indra/newview/llexperienceassociationresponder.cpp +++ b/indra/newview/llexperienceassociationresponder.cpp @@ -29,6 +29,7 @@  #include "llviewerprecompiledheaders.h"  #include "llexperienceassociationresponder.h"  #include "llexperiencecache.h" +#include "llviewerobjectlist.h"  #include "llviewerregion.h"  #include "llagent.h" @@ -47,7 +48,13 @@ void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& ob  void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)  { -    LLViewerRegion* region = gAgent.getRegion(); +    LLViewerObject* object = gObjectList.findObject(request["object-id"]); +    if (!object) +    { +        LL_WARNS() << "Failed to find object with ID " << request["object-id"] << " in fetchAssociatedExperience" << LL_ENDL; +        return; +    } +    LLViewerRegion* region = object->getRegion();      if (region)      {          std::string lookup_url=region->getCapability("GetMetadata");  diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp index ec6134a4b3..ee5d561927 100644 --- a/indra/newview/llexperiencelog.cpp +++ b/indra/newview/llexperiencelog.cpp @@ -112,6 +112,7 @@ void LLExperienceLog::handleExperienceMessage(LLSD& message)  	}  	message["Time"] = time_of_day;  	mEvents[day].append(message); +	mEventsToSave[day].append(message);  	mSignals(message);  } @@ -180,9 +181,8 @@ void LLExperienceLog::notify( LLSD& message )  void LLExperienceLog::saveEvents()  { -	eraseExpired();  	std::string filename = getFilename(); -	LLSD settings = LLSD::emptyMap().with("Events", mEvents); +	LLSD settings = LLSD::emptyMap().with("Events", mEventsToSave);  	settings["MaxDays"] = (int)mMaxDays;  	settings["Notify"] = mNotifyNewEvent; @@ -217,9 +217,8 @@ void LLExperienceLog::loadEvents()  	if(mMaxDays > 0 && settings.has("Events"))  	{  		mEvents = settings["Events"]; +		mEventsToSave = mEvents;  	} - -	eraseExpired();  }  LLExperienceLog::~LLExperienceLog() @@ -235,6 +234,26 @@ void LLExperienceLog::eraseExpired()  	}  } +bool LLExperienceLog::isNotExpired(std::string& date) +{ +	LLDate event_date; +	S32 month, day, year; +	S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day); +	if (matched != 3) return false; +	event_date.fromYMDHMS(year, month, day); +	const U32 seconds_in_day = 24 * 60 * 60; +	S32 curr_year = 0, curr_month = 0, curr_day = 0; + + +	LLDate curr_date = LLDate::now(); +	curr_date.split(&curr_year, &curr_month, &curr_day); +	curr_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0 + +	LLDate boundary_date =  LLDate(curr_date.secondsSinceEpoch() - seconds_in_day*getMaxDays()); +	return event_date >= boundary_date; + +} +  const LLSD& LLExperienceLog::getEvents() const  {  	return mEvents; @@ -248,10 +267,6 @@ void LLExperienceLog::clear()  void LLExperienceLog::setMaxDays( U32 val )  {  	mMaxDays = val; -	if(mMaxDays > 0) -	{ -		eraseExpired(); -	}  }  LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb ) diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h index 1e473e27d5..ac227db336 100644 --- a/indra/newview/llexperiencelog.h +++ b/indra/newview/llexperiencelog.h @@ -59,6 +59,8 @@ public:  	static void notify(LLSD& message);  	static std::string getFilename();  	static std::string getPermissionString(const LLSD& message, const std::string& base); +	void setEventsToSave(LLSD new_events){mEventsToSave = new_events; } +	bool isNotExpired(std::string& date);  protected:  	LLExperienceLog();  	void handleExperienceMessage(LLSD& message); @@ -68,7 +70,10 @@ protected:  	void saveEvents();  	void eraseExpired(); + +  	LLSD mEvents; +	LLSD mEventsToSave;  	callback_signal_t mSignals;  	callback_connection_t mNotifyConnection;  	U32 mMaxDays; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index f2b369a9ad..8f3eaaa207 100755 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -380,9 +380,11 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)  	mShowDragMarker(FALSE),  	mLandingTab(NULL),  	mLastTab(NULL), -	mTabsHighlightEnabled(TRUE) -  , mUpdateDropDownItems(true) -,	mRestoreOverflowMenu(false) +	mTabsHighlightEnabled(TRUE), +	mUpdateDropDownItems(true), +	mRestoreOverflowMenu(false), +	mGetPrevItems(true), +	mItemsChangedTimer()  {  	// Register callback for menus with current registrar (will be parent panel's registrar)  	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", @@ -659,6 +661,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)  			LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID());  		}  		updateButtons(); +		if (!mItemsChangedTimer.getStarted()) +		{ +			mItemsChangedTimer.start(); +		} +		else +		{ +			mItemsChangedTimer.reset(); +		} +  	}  } @@ -693,6 +704,21 @@ void LLFavoritesBarCtrl::draw()  		// Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)  		mShowDragMarker = FALSE;  	} +	if (mItemsChangedTimer.getStarted()) +	{ +		if (mItemsChangedTimer.getElapsedTimeF32() > 1.f) +		{ +			LLFavoritesOrderStorage::instance().saveFavoritesRecord(); +			mItemsChangedTimer.stop(); +		} +	} + +	if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired) +	{ +		LLFavoritesOrderStorage::instance().mUpdateRequired = false; +		mItemsChangedTimer.start(); +	} +  }  const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() @@ -723,6 +749,12 @@ void LLFavoritesBarCtrl::updateButtons()  		return;  	} +	if(mGetPrevItems) +	{ +		LLFavoritesOrderStorage::instance().mPrevFavorites = mItems; +		mGetPrevItems = false; +	} +  	const LLButton::Params& button_params = getButtonParams();  	if(mItems.empty()) @@ -844,6 +876,7 @@ void LLFavoritesBarCtrl::updateButtons()  	{  		mUpdateDropDownItems = false;  	} +  }  LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset) @@ -912,9 +945,11 @@ BOOL LLFavoritesBarCtrl::postBuild()  BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)  { +  	if (mFavoriteFolderId.isNull())  		return FALSE; +  	LLInventoryModel::cat_array_t cats;  	LLIsType is_type(LLAssetType::AT_LANDMARK); @@ -1411,6 +1446,7 @@ void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const  const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";  const S32 LLFavoritesOrderStorage::NO_INDEX = -1; +bool LLFavoritesOrderStorage::mSaveOnExit = false;  void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index)  { @@ -1447,6 +1483,7 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id)          LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL;  		onLandmarkLoaded(asset_id, lm);  	} +	return;  }  // static @@ -1482,13 +1519,16 @@ void LLFavoritesOrderStorage::destroyClass()  		LLFile::remove(old_filename);  	} -	if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) -	{ -		LLFavoritesOrderStorage::instance().saveFavoritesSLURLs(); -	} -	else +	std::string filename = getSavedOrderFileName(); +	file.open(filename.c_str()); +	if (file.is_open())  	{ -		LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser(); +		file.close(); +		LLFile::remove(filename); +		if(mSaveOnExit) +		{ +			LLFavoritesOrderStorage::instance().saveFavoritesRecord(true); +		}  	}  } @@ -1503,108 +1543,57 @@ std::string LLFavoritesOrderStorage::getSavedOrderFileName()  void LLFavoritesOrderStorage::load()  { -	// load per-resident sorting information  	std::string filename = getSavedOrderFileName(); -  	LLSD settings_llsd;  	llifstream file;  	file.open(filename.c_str());  	if (file.is_open())  	{  		LLSDSerialize::fromXML(settings_llsd, file); -        LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " -                                 << (settings_llsd.isMap() ? "" : "un") << "successfully" -                                 << LL_ENDL; -        file.close(); -	} -    else -    { -        LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL; -    } - -	for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); -		iter != settings_llsd.endMap(); ++iter) -	{ -		mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); +		LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " +	                                 << (settings_llsd.isMap() ? "" : "un") << "successfully" +	                                 << LL_ENDL; +		file.close(); +		mSaveOnExit = true; + +		for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); +			iter != settings_llsd.endMap(); ++iter) +		{ +			mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); +		}  	} -} - -void LLFavoritesOrderStorage::saveFavoritesSLURLs() -{ -	// Do not change the file if we are not logged in yet. -	if (!LLLoginInstance::getInstance()->authSuccess()) +	else  	{ -		LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL; -		return; +		filename = getStoredFavoritesFilename(); +		if (!filename.empty()) +		{ +			llifstream in_file; +			in_file.open(filename.c_str()); +			LLSD fav_llsd; +			LLSD user_llsd; +			if (in_file.is_open()) +			{ +				LLSDSerialize::fromXML(fav_llsd, in_file); +				LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " +												<< (fav_llsd.isMap() ? "" : "un") << "successfully" +												<< LL_ENDL; +				in_file.close(); +				user_llsd = fav_llsd[gAgentUsername]; + +				S32 index = 0; +				for (LLSD::array_iterator iter = user_llsd.beginArray(); +						iter != user_llsd.endArray(); ++iter) +				{ +					mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); +					index++; +				} +			} +			else +			{ +				LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; +			} +		}  	} - -	std::string filename = getStoredFavoritesFilename(); -    if (!filename.empty()) -    { -        llifstream in_file; -        in_file.open(filename.c_str()); -        LLSD fav_llsd; -        if (in_file.is_open()) -        { -            LLSDSerialize::fromXML(fav_llsd, in_file); -            LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " -                                     << (fav_llsd.isMap() ? "" : "un") << "successfully" -                                     << LL_ENDL; -            in_file.close(); -        } -        else -        { -            LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; -        } - -        const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); -        LLInventoryModel::cat_array_t cats; -        LLInventoryModel::item_array_t items; -        gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - -        LLSD user_llsd; -        for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) -        { -            LLSD value; -            value["name"] = (*it)->getName(); -            value["asset_id"] = (*it)->getAssetUUID(); - -            slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); -            if (slurl_iter != mSLURLs.end()) -            { -                LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) << ", SLURL=" <<  slurl_iter->second << ", value=" << value << LL_ENDL; -                value["slurl"] = slurl_iter->second; -                user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value; -            } -            else -            { -                LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL; -            } -        } - -        LLAvatarName av_name; -        LLAvatarNameCache::get( gAgentID, &av_name ); -        // Note : use the "John Doe" and not the "john.doe" version of the name  -        // as we'll compare it with the stored credentials in the login panel. -        fav_llsd[av_name.getUserName()] = user_llsd; - -        llofstream file; -        file.open(filename.c_str()); -        if ( file.is_open() ) -        { -            LLSDSerialize::toPrettyXML(fav_llsd, file); -            LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName() -                                     << "' to '" << filename << "' " -                                     << LL_ENDL; -            file.close(); -        } -        else -        { -            LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() -                                     << "' at '" << filename << "' " -                                     << LL_ENDL; -        } -    }  }  void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() @@ -1626,8 +1615,30 @@ void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()              // See saveFavoritesSLURLs() here above for the reason why.              if (fav_llsd.has(av_name.getUserName()))              { -                LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; -                fav_llsd.erase(av_name.getUserName()); +            	LLSD user_llsd = fav_llsd[av_name.getUserName()]; + +            	if (user_llsd.beginArray()->has("id")) +            	{ +            		for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter) +            		{ +            			LLSD value; +            			value["id"]= iter->get("id").asUUID(); +            			iter->assign(value); +            		} +            		fav_llsd[av_name.getUserName()] = user_llsd; +            		llofstream file; +            		file.open(filename.c_str()); +            		if ( file.is_open() ) +            		{ +            				LLSDSerialize::toPrettyXML(fav_llsd, file); +            				file.close(); +            		} +            	} +            	else +            	{ +            		LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; +            		fav_llsd.erase(av_name.getUserName()); +            	}              }              llofstream out_file; @@ -1648,20 +1659,20 @@ void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmar  	if (landmark)      {          LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL; -	LLVector3d pos_global; -	if (!landmark->getGlobalPos(pos_global)) -	{ -		// If global position was unknown on first getGlobalPos() call -		// it should be set for the subsequent calls. -		landmark->getGlobalPos(pos_global); -	} +        LLVector3d pos_global; +        if (!landmark->getGlobalPos(pos_global)) +        { +        	// If global position was unknown on first getGlobalPos() call +        	// it should be set for the subsequent calls. +        	landmark->getGlobalPos(pos_global); +        } -	if (!pos_global.isExactlyZero()) -	{ -        LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; -		LLLandmarkActions::getSLURLfromPosGlobal(pos_global, +        if (!pos_global.isExactlyZero()) +        { +        	LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; +        	LLLandmarkActions::getSLURLfromPosGlobal(pos_global,  			boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); -	} +        }      }  } @@ -1671,41 +1682,6 @@ void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::st  	mSLURLs[asset_id] = slurl;  } -void LLFavoritesOrderStorage::save() -{ -	if (mIsDirty) -    { -        // something changed, so save it -        std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName(); -        if (!filename.empty()) -        { -            LLSD settings_llsd; - -            for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) -            { -                settings_llsd[iter->first.asString()] = iter->second; -            } - -            llofstream file; -            file.open(filename.c_str()); -            if ( file.is_open() ) -            { -                LLSDSerialize::toPrettyXML(settings_llsd, file); -                LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL; -            } -            else -            { -                LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL; -            } -        } -        else -        { -            LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL; -        } -    } -} - -  void LLFavoritesOrderStorage::cleanup()  {  	// nothing to clean @@ -1720,7 +1696,7 @@ void LLFavoritesOrderStorage::cleanup()  	sort_index_map_t  aTempMap;  	//copy unremoved values from mSortIndexes to aTempMap -	std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),  +	std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),  		inserter(aTempMap, aTempMap.begin()),  		is_not_in_fav); @@ -1752,8 +1728,8 @@ void LLFavoritesOrderStorage::saveOrder()  void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items )  { -	int sortField = 0; +	int sortField = 0;  	// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field  	for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)  	{ @@ -1793,6 +1769,110 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it  	saveItemsOrder(items);  } +BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) +{ + +	LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); +	if (favorite_folder.isNull()) +			return FALSE; + +	LLInventoryModel::item_array_t items; +	LLInventoryModel::cat_array_t cats; + +	LLIsType is_type(LLAssetType::AT_LANDMARK); +	gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + +	std::sort(items.begin(), items.end(), LLFavoritesSort()); + +	if((items != mPrevFavorites) || pref_changed) +	{ +		std::string filename = getStoredFavoritesFilename(); +		if (!filename.empty()) +		{ +			llifstream in_file; +			in_file.open(filename.c_str()); +			LLSD fav_llsd; +			if (in_file.is_open()) +			{ +				LLSDSerialize::fromXML(fav_llsd, in_file); +				in_file.close(); +			} +			else +			{ +				LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; +			} + +			LLSD user_llsd; +			S32 fav_iter = 0; +			for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) +			{ +				LLSD value; +				if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) +				{ +					value["name"] = (*it)->getName(); +					value["asset_id"] = (*it)->getAssetUUID(); +					value["id"] = (*it)->getUUID(); +					slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); +					if (slurl_iter != mSLURLs.end()) +					{ +						value["slurl"] = slurl_iter->second; +						user_llsd[fav_iter] = value; +					} +					else +					{ +						getSLURL((*it)->getAssetUUID()); +						mUpdateRequired = true; +						return FALSE; +					} +				} +				else +				{ +					value["id"] = (*it)->getUUID(); +					user_llsd[fav_iter] = value; +				} + +				fav_iter ++; +			} + +			LLAvatarName av_name; +			LLAvatarNameCache::get( gAgentID, &av_name ); +			// Note : use the "John Doe" and not the "john.doe" version of the name +			// as we'll compare it with the stored credentials in the login panel. +			fav_llsd[av_name.getUserName()] = user_llsd; +			llofstream file; +			file.open(filename.c_str()); +			if ( file.is_open() ) +			{ +				LLSDSerialize::toPrettyXML(fav_llsd, file); +				file.close(); +				mSaveOnExit = false; +			} +			else +			{ +				LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() +												<< "' at '" << filename << "' " << LL_ENDL; +			} +		} + +		mPrevFavorites = items; +	} + +	return TRUE; + +} + +void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show) +{ +	if (show) +	{ +		saveFavoritesRecord(true); +	} +	else +	{ +		removeFavoritesRecordOfUser(); +	} +} +  void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)  {  	if (mTargetLandmarkId.isNull()) return; diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index a370724947..66fc8b2ae7 100755 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -105,8 +105,10 @@ protected:  	bool mUpdateDropDownItems;  	bool mRestoreOverflowMenu; -	LLUUID mSelectedItemID; +	bool mGetPrevItems; +	LLUUID mSelectedItemID; +	LLFrameTimer mItemsChangedTimer;  	LLUIImage* mImageDragIndication;  private: @@ -204,12 +206,23 @@ public:  	 * @see cleanup()  	 */  	static void destroyClass(); +	static std::string getStoredFavoritesFilename(); +	static std::string getSavedOrderFileName(); + +	BOOL saveFavoritesRecord(bool pref_changed = false); +	void showFavoritesOnLoginChanged(BOOL show); + +	LLInventoryModel::item_array_t mPrevFavorites; +  	const static S32 NO_INDEX; +	static bool mSaveOnExit; +	bool mUpdateRequired; +  private:  	friend class LLSingleton<LLFavoritesOrderStorage>; -	LLFavoritesOrderStorage() : mIsDirty(false) { load(); } -	~LLFavoritesOrderStorage() { save(); } +	LLFavoritesOrderStorage() : mIsDirty(false), mUpdateRequired(false){ load(); } +	~LLFavoritesOrderStorage() {}  	/**  	 * Removes sort indexes for items which are not in Favorites bar for now. @@ -217,13 +230,8 @@ private:  	void cleanup();  	const static std::string SORTING_DATA_FILE_NAME; -    std::string getSavedOrderFileName(); -    static std::string getStoredFavoritesFilename(); -     -	void load(); -	void save(); -	void saveFavoritesSLURLs(); +	void load();  	// Remove record of current user's favorites from file on disk.  	void removeFavoritesRecordOfUser(); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index e71daa6067..c5d637d1fc 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -34,10 +34,12 @@  // Viewer includes  #include "llagent.h"  #include "llagentui.h" -#include "llappviewer.h"  +#include "llappviewer.h" +#include "llnotificationsutil.h"  #include "llslurl.h"  #include "llvoiceclient.h"  #include "lluictrlfactory.h" +#include "llupdaterservice.h"  #include "llviewertexteditor.h"  #include "llviewercontrol.h"  #include "llviewerstats.h" @@ -99,9 +101,23 @@ public:  	/// separated so that we can programmatically access the same info.  	static LLSD getInfo();  	void onClickCopyToClipboard(); +	void onClickUpdateCheck(); + +	// checks state of updater service and starts a check outside of schedule. +	// subscribes callback for closest state update +	static void setUpdateListener();  private:  	void setSupportText(const std::string& server_release_notes_url); + +	// notifications for user requested checks +	static void showCheckUpdateNotification(S32 state); + +	// callback method for manual checks +	static bool callbackCheckUpdate(LLSD const & event); + +	// listener name for update checks +	static const std::string sCheckUpdateListenerName;  }; @@ -132,6 +148,9 @@ BOOL LLFloaterAbout::postBuild()  	getChild<LLUICtrl>("copy_btn")->setCommitCallback(  		boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this)); +	getChild<LLUICtrl>("update_btn")->setCommitCallback( +		boost::bind(&LLFloaterAbout::onClickUpdateCheck, this)); +  	static const LLUIColor about_color = LLUIColorTable::instance().getColor("TextFgReadOnlyColor");  	if (gAgent.getRegion()) @@ -235,6 +254,11 @@ void LLFloaterAbout::onClickCopyToClipboard()  	support_widget->deselect();  } +void LLFloaterAbout::onClickUpdateCheck() +{ +	setUpdateListener(); +} +  void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)  {  #if LL_WINDOWS @@ -256,6 +280,68 @@ void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)  }  ///---------------------------------------------------------------------------- +/// Floater About Update-check related functions +///---------------------------------------------------------------------------- + +const std::string LLFloaterAbout::sCheckUpdateListenerName = "LLUpdateNotificationListener"; + +void LLFloaterAbout::showCheckUpdateNotification(S32 state) +{ +	switch (state) +	{ +	case LLUpdaterService::UP_TO_DATE: +		LLNotificationsUtil::add("UpdateViewerUpToDate"); +		break; +	case LLUpdaterService::DOWNLOADING: +	case LLUpdaterService::INSTALLING: +		LLNotificationsUtil::add("UpdateDownloadInProgress"); +		break; +	case LLUpdaterService::TERMINAL: +		// download complete, user triggered check after download pop-up appeared +		LLNotificationsUtil::add("UpdateDownloadComplete"); +		break; +	default: +		LLNotificationsUtil::add("UpdateCheckError"); +		break; +	} +} + +bool LLFloaterAbout::callbackCheckUpdate(LLSD const & event) +{ +	if (!event.has("payload")) +	{ +		return false; +	} + +	LLSD payload = event["payload"]; +	if (payload.has("type") && payload["type"].asInteger() == LLUpdaterService::STATE_CHANGE) +	{ +		LLEventPumps::instance().obtain("mainlooprepeater").stopListening(sCheckUpdateListenerName); +		showCheckUpdateNotification(payload["state"].asInteger()); +	} +	return false; +} + +void LLFloaterAbout::setUpdateListener() +{ +	LLUpdaterService update_service; +	S32 service_state = update_service.getState(); +	// Note: Do not set state listener before forceCheck() since it set's new state +	if (update_service.forceCheck() || service_state == LLUpdaterService::CHECKING_FOR_UPDATE) +	{ +		LLEventPump& mainloop(LLEventPumps::instance().obtain("mainlooprepeater")); +		if (mainloop.getListener(sCheckUpdateListenerName) == LLBoundListener()) // dummy listener +		{ +			mainloop.listen(sCheckUpdateListenerName, boost::bind(&callbackCheckUpdate, _1)); +		} +	} +	else +	{ +		showCheckUpdateNotification(service_state); +	} +} + +///----------------------------------------------------------------------------  /// LLFloaterAboutUtil  ///----------------------------------------------------------------------------  void LLFloaterAboutUtil::registerFloater() @@ -265,6 +351,11 @@ void LLFloaterAboutUtil::registerFloater()  } +void LLFloaterAboutUtil::checkUpdatesAndNotify() +{ +	LLFloaterAbout::setUpdateListener(); +} +  ///----------------------------------------------------------------------------  /// Class LLServerReleaseNotesURLFetcher implementation  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h index 8fc1aa4f29..be34b631cc 100755 --- a/indra/newview/llfloaterabout.h +++ b/indra/newview/llfloaterabout.h @@ -30,6 +30,9 @@  namespace LLFloaterAboutUtil  {  	void registerFloater(); + +	// Support for user initialized update/state checks +	void checkUpdatesAndNotify();  }  #endif // LL_LLFLOATERABOUT_H diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 34904cf7ed..957c91b226 100755 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -32,6 +32,7 @@  #include "llavataractions.h"  #include "llfloaterbump.h" +#include "llfloaterreg.h"  #include "llfloaterreporter.h"  #include "llmutelist.h"  #include "llpanelblockedlist.h" @@ -87,11 +88,11 @@ BOOL LLFloaterBump::postBuild()  // virtual  void LLFloaterBump::onOpen(const LLSD& key)  { -	mNames.clear(); -	mList->deleteAllItems(); -  	if (gMeanCollisionList.empty())  	{ +		mNames.clear(); +		mList->deleteAllItems(); +  		std::string none_detected = getString("none_detected");  		LLSD row;  		row["columns"][0]["value"] = none_detected; @@ -100,12 +101,20 @@ void LLFloaterBump::onOpen(const LLSD& key)  	}  	else  	{ -		for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); -			 iter != gMeanCollisionList.end(); ++iter) -		{ -			LLMeanCollisionData *mcd = *iter; -			add(mList, mcd); -		} +		populateCollisionList(); +	} +} + +void LLFloaterBump::populateCollisionList() +{ +	mNames.clear(); +	mList->deleteAllItems(); + +	for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); +				 iter != gMeanCollisionList.end(); ++iter) +	{ +		LLMeanCollisionData *mcd = *iter; +		add(mList, mcd);  	}  } @@ -247,3 +256,8 @@ void LLFloaterBump::inviteToGroup()  {  	LLAvatarActions::inviteToGroup(mItemUUID);  } + +LLFloaterBump* LLFloaterBump::getInstance() +{ +	return LLFloaterReg::getTypedInstance<LLFloaterBump>("bumps"); +} diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h index 11b7db9fee..ce52c75255 100755 --- a/indra/newview/llfloaterbump.h +++ b/indra/newview/llfloaterbump.h @@ -46,6 +46,10 @@ public:  	/*virtual*/	BOOL postBuild();  	/*virtual*/ void onOpen(const LLSD& key); +	static LLFloaterBump* getInstance(); + +	void populateCollisionList(); +  	void startIM();  	void startCall();  	void reportAbuse(); diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp index 3a2047cfef..da85d378b2 100644 --- a/indra/newview/llfloaterfacebook.cpp +++ b/indra/newview/llfloaterfacebook.cpp @@ -64,9 +64,9 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo  const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";  const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare"; -const S32 MAX_QUALITY = 100;        // Max quality value for jpeg images -const S32 MIN_QUALITY = 0;          // Min quality value for jpeg images -const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook +const S32 MAX_QUALITY = 100;         // Max quality value for jpeg images +const S32 MIN_QUALITY = 0;           // Min quality value for jpeg images +const S32 TARGET_DATA_SIZE = 950000; // Size of the image (compressed) we're trying to send to Facebook  std::string get_map_url()  { diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index ab57e8c170..0a5a6e8e13 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -261,6 +261,8 @@ BOOL LLFloaterIMContainer::postBuild()  	mInitialized = true; +	mIsFirstOpen = true; +  	// Add callbacks:  	// We'll take care of view updates on idle  	gIdleCallbacks.addFunction(idle, this); @@ -636,14 +638,16 @@ void LLFloaterIMContainer::setVisible(BOOL visible)  	{  		// Make sure we have the Nearby Chat present when showing the conversation container  		nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); -		if (nearby_chat == NULL) +		if ((nearby_chat == NULL) || mIsFirstOpen)  		{ +			 mIsFirstOpen = false;  			// If not found, force the creation of the nearby chat conversation panel  			// *TODO: find a way to move this to XML as a default panel or something like that  			LLSD name("nearby_chat");  			LLFloaterReg::toggleInstanceOrBringToFront(name);              selectConversationPair(LLUUID(NULL), false, false);  		} +  		flashConversationItemWidget(mSelectedSession,false);  		LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession); @@ -920,6 +924,11 @@ void LLFloaterIMContainer::onCustomAction(const LLSD& userdata)  	{  		setSortOrderParticipants(LLConversationFilter::SO_DISTANCE);  	} +	if ("view_icons" == command) +	{ +		gSavedSettings.setBOOL("ChatShowIcons", !(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL("ChatShowIcons") && gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +	}  	if ("chat_preferences" == command)  	{  		LLFloaterPreference * floater_prefp = LLFloaterReg::showTypedInstance<LLFloaterPreference>("preferences"); @@ -970,6 +979,10 @@ BOOL LLFloaterIMContainer::isActionChecked(const LLSD& userdata)  	{  		return (order.getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE);  	} +	if ("view_icons" == command) +	{ +		return gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride"); +	}  	if ("Translating.Enabled" == command)  	{  		return gSavedPerAccountSettings.getBOOL("TranslatingEnabled"); @@ -1216,7 +1229,22 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,          {  			if (selectedIDS.size() > 0)  			{ -				LLAvatarActions::viewChatHistory(selectedIDS.front()); +				if(conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP) +				{ +					LLFloaterReg::showInstance("preview_conversation", conversationItem->getUUID(), true); +				} +				else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC) +				{ +					LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(conversationItem->getUUID())); +					if(conv) +					{ +						LLFloaterReg::showInstance("preview_conversation", conv->getSessionID(), true); +					} +				} +				else +				{ +					LLAvatarActions::viewChatHistory(selectedIDS.front()); +				}  			}          }          else @@ -1316,6 +1344,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)  			{  				return LLLogChat::isNearbyTranscriptExist();  			} +			else if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_AD_HOC) +			{ +				const LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(uuids.front())); +				if(conv) +				{ +					return LLLogChat::isAdHocTranscriptExist(conv->getHistoryFileName()); +				} +				return false; +			}  			else  			{  				bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP); @@ -1881,22 +1918,28 @@ bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid)  		return false;  	} -	if (!gdatap->mMembers.size()) +	if (gdatap->mPendingBanRequest)  	{  		return false;  	} -	LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid)); -	if (mi == gdatap->mMembers.end()) +	if (gdatap->isRoleMemberDataComplete())  	{ -		return false; -	} +		if (!gdatap->mMembers.size()) +		{ +			return false; +		} -	LLGroupMemberData* member_data = (*mi).second; -	// Is the member an owner? -	if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) -	{ -		return false; +		LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid)); +		if (mi != gdatap->mMembers.end()) +		{ +			LLGroupMemberData* member_data = (*mi).second; +			// Is the member an owner? +			if (member_data && member_data->isInRole(gdatap->mOwnerRole)) +			{ +				return false; +			} +		}  	}  	if(	gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) && @@ -1924,20 +1967,8 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)  		LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;  		return;  	} -	std::vector<LLUUID> ids; -	ids.push_back(participant_uuid); - -	LLGroupBanData ban_data; -	gdatap->createBanEntry(participant_uuid, ban_data); -	LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids); -	LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids); -	LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid); -	LLSD args; -	std::string name; -	gCacheName->getFullName(participant_uuid, name); -	args["AVATAR_NAME"] = name; -	args["GROUP_NAME"] = gdatap->mName; -	LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); + +	gdatap->banMemberById(participant_uuid);  } diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index f21c0b9947..60cef83d9a 100755 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -193,6 +193,8 @@ private:  	bool mInitialized;  	bool mIsFirstLaunch; +	bool mIsFirstOpen; +  	LLUUID mSelectedSession;  	std::string mGeneralTitle; diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index b7fff6cae3..ee3d633dd0 100755 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -326,7 +326,21 @@ void LLFloaterJoystick::onClickOK(void *joy_panel)  	}  } +void LLFloaterJoystick::onClickCloseBtn(bool app_quitting) +{ +	cancel(); +	closeFloater(app_quitting); +} +  void LLFloaterJoystick::setSNDefaults()  {  	LLViewerJoystick::getInstance()->setSNDefaults();  } + +void LLFloaterJoystick::onClose(bool app_quitting) +{ +	if (app_quitting) +	{ +		cancel(); +	} +} diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 9c3752540d..a1b5951389 100755 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -45,6 +45,11 @@ public:  	virtual void draw();  	static  void setSNDefaults(); +protected: + +	void onClose(bool app_quitting); +	void onClickCloseBtn(bool app_quitting); +  private:  	LLFloaterJoystick(const LLSD& data); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index ce32aeda94..f9fd5069af 100755 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2439,6 +2439,8 @@ void LLPanelLandAccess::refresh()  			mListAccess->clearSortOrder();  			mListAccess->deleteAllItems();  			S32 count = parcel->mAccessList.size(); +			getChild<LLUICtrl>("AllowedText")->setTextArg("[COUNT]", llformat("%d",count)); +  			getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));  			getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); @@ -2484,6 +2486,7 @@ void LLPanelLandAccess::refresh()  			mListBanned->clearSortOrder();  			mListBanned->deleteAllItems();  			S32 count = parcel->mBanList.size(); +			getChild<LLUICtrl>("BanCheck")->setTextArg("[COUNT]", llformat("%d",count));  			getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));  			getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a2a1dfbdb8..fea4e57d13 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -26,8 +26,35 @@  #include "llviewerprecompiledheaders.h" -#include "llmodelloader.h" -#include "lldaeloader.h" +#if LL_MSVC +#pragma warning (disable : 4263) +#pragma warning (disable : 4264) +#endif +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" +#if LL_MSVC +#pragma warning (default : 4263) +#pragma warning (default : 4264) +#endif  #include "llfloatermodelpreview.h" @@ -85,15 +112,14 @@  #include "llanimationstates.h"  #include "llviewernetwork.h"  #include "llviewershadermgr.h" -  #include "glod/glod.h" -#include <boost/algorithm/string.hpp> + +const S32 SLM_SUPPORTED_VERSION = 3;  //static  S32 LLFloaterModelPreview::sUploadAmount = 10;  LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -bool LLModelPreview::sIgnoreLoadedCallback = false; +std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;  // "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01  // But according to the UI spec for upload model floater, this parameter @@ -173,37 +199,190 @@ std::string lod_label_name[NUM_LOD+1] =  	"I went off the end of the lod_label_name array.  Me so smart."  }; -BOOL stop_gloderror() +std::string colladaVersion[VERSIONTYPE_COUNT+1] =   { -	GLuint error = glodGetError(); +	"1.4.0", +	"1.4.1", +	"Unsupported" +}; -	if (error != GLOD_NO_ERROR) + +#define LL_DEGENERACY_TOLERANCE  1e-7f + +inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b) +{ +    volatile F32 p0 = a[0] * b[0]; +    volatile F32 p1 = a[1] * b[1]; +    volatile F32 p2 = a[2] * b[2]; +    return p0 + p1 + p2; +} + +bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE) +{ +        // small area check +        { +                LLVector4a edge1; edge1.setSub( a, b ); +                LLVector4a edge2; edge2.setSub( a, c ); +                ////////////////////////////////////////////////////////////////////////// +                /// Linden Modified +                ////////////////////////////////////////////////////////////////////////// + +                // If no one edge is more than 10x longer than any other edge, we weaken +                // the tolerance by a factor of 1e-4f. + +                LLVector4a edge3; edge3.setSub( c, b ); +				const F32 len1sq = edge1.dot3(edge1).getF32(); +                const F32 len2sq = edge2.dot3(edge2).getF32(); +                const F32 len3sq = edge3.dot3(edge3).getF32(); +                bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); +                bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); +                bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); +                if ( abOK && acOK && cbOK ) +                { +                        tolerance *= 1e-4f; +                } + +                ////////////////////////////////////////////////////////////////////////// +                /// End Modified +                ////////////////////////////////////////////////////////////////////////// + +                LLVector4a cross; cross.setCross3( edge1, edge2 ); + +                LLVector4a edge1b; edge1b.setSub( b, a ); +                LLVector4a edge2b; edge2b.setSub( b, c ); +                LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); + +                if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) +                { +                        return true; +                } +        } + +        // point triangle distance check +        { +                LLVector4a Q; Q.setSub(a, b); +                LLVector4a R; R.setSub(c, b); + +                const F32 QQ = dot3fpu(Q, Q); +                const F32 RR = dot3fpu(R, R); +                const F32 QR = dot3fpu(R, Q); + +                volatile F32 QQRR = QQ * RR; +                volatile F32 QRQR = QR * QR; +                F32 Det = (QQRR - QRQR); + +                if( Det == 0.0f ) +                { +                        return true; +                } +        } + +        return false; +} + +bool validate_face(const LLVolumeFace& face) +{ + +	for (U32 v = 0; v < face.mNumVertices; v++)  	{ -		LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; -		return TRUE; +		if(face.mPositions && !face.mPositions[v].isFinite3()) +		{ +			LL_WARNS() << "NaN position data in face found!" << LL_ENDL; +			return false; +		} + +		if(face.mNormals && !face.mNormals[v].isFinite3()) +		{ +			LL_WARNS() << "NaN normal data in face found!" << LL_ENDL; +			return false; +		}  	} -	return FALSE; +	for (U32 i = 0; i < face.mNumIndices; ++i) +	{ +		if (face.mIndices[i] >= face.mNumVertices) +		{ +			LL_WARNS() << "Face has invalid index." << LL_ENDL; +			return false; +		} +	} + +	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) +	{ +		LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; +		return false; +	} + + +	/*const LLVector4a scale(0.5f); + + +	for (U32 i = 0; i < face.mNumIndices; i+=3) +	{ +		U16 idx1 = face.mIndices[i]; +		U16 idx2 = face.mIndices[i+1]; +		U16 idx3 = face.mIndices[i+2]; + +		LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); +		LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); +		LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); + +		if (ll_is_degenerate(v1,v2,v3)) +		{ +			LL_WARNS() << "Degenerate face found!" << LL_ENDL; +			return false; +		} +	}*/ +	return true;  } -LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) +bool validate_model(const LLModel* mdl)  { -	LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); +	if (mdl->getNumVolumeFaces() == 0) +	{ +		LL_WARNS() << "Model has no faces!" << LL_ENDL; +		return false; +	} -	if (texture) +	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)  	{ -		if (texture->getDiscardLevel() > -1) +		if (mdl->getVolumeFace(i).mNumVertices == 0) +		{ +			LL_WARNS() << "Face has no vertices." << LL_ENDL; +			return false; +		} + +		if (mdl->getVolumeFace(i).mNumIndices == 0)  		{ -			gGL.getTexUnit(0)->bind(texture, true); -			return texture; +			LL_WARNS() << "Face has no indices." << LL_ENDL; +			return false; +		} + +		if (!validate_face(mdl->getVolumeFace(i))) +		{ +			return false;  		}  	} -	return NULL; +	return true;  } +BOOL stop_gloderror() +{ +	GLuint error = glodGetError(); + +	if (error != GLOD_NO_ERROR) +	{ +		LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; +		return TRUE; +	} + +	return FALSE; +} + +  LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) -: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) +	: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)  	{  		mMP = mp;  		mLOD = lod; @@ -214,29 +393,6 @@ void LLMeshFilePicker::notify(const std::string& filename)  	mMP->loadModel(mFile, mLOD);  } -void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) -{ -    LLModelLoader::scene::iterator base_iter = scene.begin(); -    bool found = false; -    while (!found && (base_iter != scene.end())) -    { -        matOut = base_iter->first; - -        LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); -        while (!found && (base_instance_iter != base_iter->second.end())) -        { -		    LLModelInstance& base_instance = *base_instance_iter++;					    		     -            LLModel* base_model = base_instance.mModel; -          -            if (base_model && (base_model->mLabel == name_to_match)) -            { -                baseModelOut = base_model; -                return; -            } -        } -        base_iter++; -    } -}  //-----------------------------------------------------------------------------  // LLFloaterModelPreview() @@ -457,11 +613,6 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option)  void LLFloaterModelPreview::loadModel(S32 lod)  {  	mModelPreview->mLoading = true; -	if (lod == LLModel::LOD_PHYSICS) -	{ -		// loading physics from file -		mModelPreview->mPhysicsSearchLOD = lod; -	}  	(new LLMeshFilePicker(mModelPreview, lod))->getFile();  } @@ -600,6 +751,8 @@ void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)  void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)  {  	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; +	if (fp->mModelPreview->mHasBrokenModel) +		return;  	fp->mModelPreview->genLODs();  } @@ -640,9 +793,9 @@ void LLFloaterModelPreview::draw()  			childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));  		}  		else -		if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL ) -		{ -			childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL))); +		if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING ) +		{		 +			childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));  		}  		else  		if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING ) @@ -794,16 +947,9 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)  /*virtual*/  void LLFloaterModelPreview::onOpen(const LLSD& key)  { -	LLModelPreview::sIgnoreLoadedCallback = false;  	requestAgentUploadPermissions();  } -/*virtual*/ -void LLFloaterModelPreview::onClose(bool app_quitting) -{ -	LLModelPreview::sIgnoreLoadedCallback = true; -} -  //static  void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)  { @@ -1164,6 +1310,1830 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl  }  //----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,  +							  std::deque<std::string>& jointsFromNodes ) +: mJointList( jointMap ) +, mJointsFromNode( jointsFromNodes ) +, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0) +{ +	mJointMap["mPelvis"] = "mPelvis"; +	mJointMap["mTorso"] = "mTorso"; +	mJointMap["mChest"] = "mChest"; +	mJointMap["mNeck"] = "mNeck"; +	mJointMap["mHead"] = "mHead"; +	mJointMap["mSkull"] = "mSkull"; +	mJointMap["mEyeRight"] = "mEyeRight"; +	mJointMap["mEyeLeft"] = "mEyeLeft"; +	mJointMap["mCollarLeft"] = "mCollarLeft"; +	mJointMap["mShoulderLeft"] = "mShoulderLeft"; +	mJointMap["mElbowLeft"] = "mElbowLeft"; +	mJointMap["mWristLeft"] = "mWristLeft"; +	mJointMap["mCollarRight"] = "mCollarRight"; +	mJointMap["mShoulderRight"] = "mShoulderRight"; +	mJointMap["mElbowRight"] = "mElbowRight"; +	mJointMap["mWristRight"] = "mWristRight"; +	mJointMap["mHipRight"] = "mHipRight"; +	mJointMap["mKneeRight"] = "mKneeRight"; +	mJointMap["mAnkleRight"] = "mAnkleRight"; +	mJointMap["mFootRight"] = "mFootRight"; +	mJointMap["mToeRight"] = "mToeRight"; +	mJointMap["mHipLeft"] = "mHipLeft"; +	mJointMap["mKneeLeft"] = "mKneeLeft"; +	mJointMap["mAnkleLeft"] = "mAnkleLeft"; +	mJointMap["mFootLeft"] = "mFootLeft"; +	mJointMap["mToeLeft"] = "mToeLeft"; + +	mJointMap["avatar_mPelvis"] = "mPelvis"; +	mJointMap["avatar_mTorso"] = "mTorso"; +	mJointMap["avatar_mChest"] = "mChest"; +	mJointMap["avatar_mNeck"] = "mNeck"; +	mJointMap["avatar_mHead"] = "mHead"; +	mJointMap["avatar_mSkull"] = "mSkull"; +	mJointMap["avatar_mEyeRight"] = "mEyeRight"; +	mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; +	mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; +	mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; +	mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; +	mJointMap["avatar_mWristLeft"] = "mWristLeft"; +	mJointMap["avatar_mCollarRight"] = "mCollarRight"; +	mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; +	mJointMap["avatar_mElbowRight"] = "mElbowRight"; +	mJointMap["avatar_mWristRight"] = "mWristRight"; +	mJointMap["avatar_mHipRight"] = "mHipRight"; +	mJointMap["avatar_mKneeRight"] = "mKneeRight"; +	mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; +	mJointMap["avatar_mFootRight"] = "mFootRight"; +	mJointMap["avatar_mToeRight"] = "mToeRight"; +	mJointMap["avatar_mHipLeft"] = "mHipLeft"; +	mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; +	mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; +	mJointMap["avatar_mFootLeft"] = "mFootLeft"; +	mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + +	mJointMap["hip"] = "mPelvis"; +	mJointMap["abdomen"] = "mTorso"; +	mJointMap["chest"] = "mChest"; +	mJointMap["neck"] = "mNeck"; +	mJointMap["head"] = "mHead"; +	mJointMap["figureHair"] = "mSkull"; +	mJointMap["lCollar"] = "mCollarLeft"; +	mJointMap["lShldr"] = "mShoulderLeft"; +	mJointMap["lForeArm"] = "mElbowLeft"; +	mJointMap["lHand"] = "mWristLeft"; +	mJointMap["rCollar"] = "mCollarRight"; +	mJointMap["rShldr"] = "mShoulderRight"; +	mJointMap["rForeArm"] = "mElbowRight"; +	mJointMap["rHand"] = "mWristRight"; +	mJointMap["rThigh"] = "mHipRight"; +	mJointMap["rShin"] = "mKneeRight"; +	mJointMap["rFoot"] = "mFootRight"; +	mJointMap["lThigh"] = "mHipLeft"; +	mJointMap["lShin"] = "mKneeLeft"; +	mJointMap["lFoot"] = "mFootLeft"; + +	if (mPreview) +	{ +		//only try to load from slm if viewer is configured to do so and this is the  +		//initial model load (not an LoD or physics shape) +		mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty(); +		mPreview->setLoadState(STARTING); +	} +	else +	{ +		mTrySLM = false; +	} + +	assert_main_thread(); +	sActiveLoaderList.push_back(this) ; +} + +LLModelLoader::~LLModelLoader() +{ +	assert_main_thread(); +	sActiveLoaderList.remove(this); +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ +	LLVector4a box[] = +	{ +		LLVector4a(-1, 1,-1), +		LLVector4a(-1, 1, 1), +		LLVector4a(-1,-1,-1), +		LLVector4a(-1,-1, 1), +		LLVector4a( 1, 1,-1), +		LLVector4a( 1, 1, 1), +		LLVector4a( 1,-1,-1), +		LLVector4a( 1,-1, 1), +	}; + +	for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) +	{ +		const LLVolumeFace& face = model->getVolumeFace(j); + +		LLVector4a center; +		center.setAdd(face.mExtents[0], face.mExtents[1]); +		center.mul(0.5f); +		LLVector4a size; +		size.setSub(face.mExtents[1],face.mExtents[0]); +		size.mul(0.5f); + +		for (U32 i = 0; i < 8; i++) +		{ +			LLVector4a t; +			t.setMul(size, box[i]); +			t.add(center); + +			LLVector4a v; + +			mat.affineTransform(t, v); + +			if (first_transform) +			{ +				first_transform = FALSE; +				min = max = v; +			} +			else +			{ +				update_min_max(min, max, v); +			} +		} +	} +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ +	LLVector4a mina, maxa; +	LLMatrix4a mata; + +	mata.loadu(mat); +	mina.load3(min.mV); +	maxa.load3(max.mV); + +	stretch_extents(model, mata, mina, maxa, first_transform); + +	min.set(mina.getF32ptr()); +	max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ +	doLoadModel(); +	doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); +} + +bool LLModelLoader::doLoadModel() +{ +	//first, look for a .slm file of the same name that was modified later +	//than the .dae + +	if (mTrySLM) +	{ +		std::string filename = mFilename; +			 +		std::string::size_type i = filename.rfind("."); +		if (i != std::string::npos) +		{ +			filename.replace(i, filename.size()-1, ".slm"); +			llstat slm_status; +			if (LLFile::stat(filename, &slm_status) == 0) +			{ //slm file exists +				llstat dae_status; +				if (LLFile::stat(mFilename, &dae_status) != 0 || +					dae_status.st_mtime < slm_status.st_mtime) +				{ +					if (loadFromSLM(filename)) +					{ //slm successfully loaded, if this fails, fall through and +						//try loading from dae + +						mLod = -1; //successfully loading from an slm implicitly sets all  +									//LoDs +						return true; +					} +				} +			}	 +		} +	} + +	//no suitable slm exists, load from the .dae file +	DAE dae; +	domCOLLADA* dom = dae.open(mFilename); +	 +	if (!dom) +	{ +		LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL; +		setLoadState( ERROR_PARSING ); +		return false; +	} +	//Dom version +	daeString domVersion = dae.getDomVersion(); +	std::string sldom(domVersion); +	LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL; +	//Dae version +	domVersionType docVersion = dom->getVersion(); +	//0=1.4 +	//1=1.4.1 +	//2=Currently unsupported, however may work +	if (docVersion > 1 )  +	{  +		docVersion = VERSIONTYPE_COUNT; +	} +	LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL; +	 +	 +	daeDatabase* db = dae.getDatabase(); +	 +	daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); +	 +	daeDocument* doc = dae.getDoc(mFilename); +	if (!doc) +	{ +		LL_WARNS() << "can't find internal doc" << LL_ENDL; +		return false; +	} +	 +	daeElement* root = doc->getDomRoot(); +	if (!root) +	{ +		LL_WARNS() << "document has no root" << LL_ENDL; +		return false; +	} +	 +	//Verify some basic properties of the dae +	//1. Basic validity check on controller  +	U32 controllerCount = (int) db->getElementCount( NULL, "controller" ); +	bool result = false; +	for ( int i=0; i<controllerCount; ++i ) +	{ +		domController* pController = NULL; +		db->getElement( (daeElement**) &pController, i , NULL, "controller" ); +		result = mPreview->verifyController( pController ); +		if (!result) +		{ +			setLoadState( ERROR_PARSING ); +			return true; +		} +	} + + +	//get unit scale +	mTransform.setIdentity(); +	 +	domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); +	 +	if (unit) +	{ +		F32 meter = unit->getMeter(); +		mTransform.mMatrix[0][0] = meter; +		mTransform.mMatrix[1][1] = meter; +		mTransform.mMatrix[2][2] = meter; +	} +	 +	//get up axis rotation +	LLMatrix4 rotation; +	 +	domUpAxisType up = UPAXISTYPE_Y_UP;  // default is Y_UP +	domAsset::domUp_axis* up_axis = +	daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); +	 +	if (up_axis) +	{ +		up = up_axis->getValue(); +	} +	 +	if (up == UPAXISTYPE_X_UP) +	{ +		rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); +	} +	else if (up == UPAXISTYPE_Y_UP) +	{ +		rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); +	} +	 +	rotation *= mTransform; +	mTransform = rotation; +	 +	 +	for (daeInt idx = 0; idx < count; ++idx) +	{ //build map of domEntities to LLModel +		domMesh* mesh = NULL; +		db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); +		 +		if (mesh) +		{ +			LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh); +			 +			if(model->getStatus() != LLModel::NO_ERRORS) +			{ +				setLoadState(ERROR_PARSING + model->getStatus()) ; +				return false; //abort +			} + +			if (model.notNull() && validate_model(model)) +			{ +				mModelList.push_back(model); +				mModel[mesh] = model; +			} +			else +			{ +				mPreview->mHasBrokenModel = true; +			} +		} +	} +	 +	count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); +	for (daeInt idx = 0; idx < count; ++idx) +	{ //add skinned meshes as instances +		domSkin* skin = NULL; +		db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); +		 +		if (skin) +		{ +			domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()); +			 +			if (geom) +			{ +				domMesh* mesh = geom->getMesh(); +				if (mesh) +				{ +					LLModel* model = mModel[mesh]; +					if (model) +					{ +						LLVector3 mesh_scale_vector; +						LLVector3 mesh_translation_vector; +						model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); +						 +						LLMatrix4 normalized_transformation; +						normalized_transformation.setTranslation(mesh_translation_vector); +						 +						LLMatrix4 mesh_scale; +						mesh_scale.initScale(mesh_scale_vector); +						mesh_scale *= normalized_transformation; +						normalized_transformation = mesh_scale; +						 +						glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); +						inv_mat = inv_mat.inverse(); +						LLMatrix4 inverse_normalized_transformation(inv_mat.m); +						 +						domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); +						 +						if (bind_mat) +						{ //get bind shape matrix +							domFloat4x4& dom_value = bind_mat->getValue(); +							 +							LLMeshSkinInfo& skin_info = model->mSkinInfo; + +							for (int i = 0; i < 4; i++) +							{ +								for(int j = 0; j < 4; j++) +								{ +									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; +								} +							} +							 +							LLMatrix4 trans = normalized_transformation; +							trans *= skin_info.mBindShapeMatrix; +							skin_info.mBindShapeMatrix = trans;							 +						} +										 +											 +						//Some collada setup for accessing the skeleton +						daeElement* pElement = 0; +						dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); +						 +						//Try to get at the skeletal instance controller +						domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); +						bool missingSkeletonOrScene = false; +						 +						//If no skeleton, do a breadth-first search to get at specific joints +						bool rootNode = false; +						 +						//Need to test for a skeleton that does not have a root node +						//This occurs when your instance controller does not have an associated scene  +						if ( pSkeleton ) +						{ +							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); +							if ( pSkeletonRootNode ) +							{ +								rootNode = true; +							} + +						} +						if ( !pSkeleton || !rootNode ) +						{ +							daeElement* pScene = root->getDescendant("visual_scene"); +							if ( !pScene ) +							{ +								LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL; +								missingSkeletonOrScene = true; +							} +							else +							{ +								//Get the children at this level +								daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); +								S32 childCount = children.getCount(); +								 +								//Process any children that are joints +								//Not all children are joints, some code be ambient lights, cameras, geometry etc.. +								for (S32 i = 0; i < childCount; ++i) +								{ +									domNode* pNode = daeSafeCast<domNode>(children[i]); +									if ( isNodeAJoint( pNode ) ) +									{ +										processJointNode( pNode, mJointList ); +									} +								} +							} +						} +						else +							//Has Skeleton +						{ +							//Get the root node of the skeleton +							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); +							if ( pSkeletonRootNode ) +							{ +								//Once we have the root node - start acccessing it's joint components +								const int jointCnt = mJointMap.size(); +								std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin(); +								 +								//Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. +								for ( int i=0; i<jointCnt; ++i, ++jointIt ) +								{ +									//Build a joint for the resolver to work with +									char str[64]={0}; +									sprintf(str,"./%s",(*jointIt).first.c_str() ); +									//LL_WARNS()<<"Joint "<< str <<LL_ENDL; +									 +									//Setup the resolver +                                    daeSIDResolver resolver( pSkeletonRootNode, str ); +									 +                                    //Look for the joint +                                    domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); +                                    if ( pJoint ) +                                    { +										//Pull out the translate id and store it in the jointTranslations map +										daeSIDResolver jointResolverA( pJoint, "./translate" ); +										domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); +										daeSIDResolver jointResolverB( pJoint, "./location" ); +										domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); +										 +										LLMatrix4 workingTransform; +										 +										//Translation via SID +										if ( pTranslateA ) +										{ +											extractTranslation( pTranslateA, workingTransform ); +										} +										else +										if ( pTranslateB ) +										{ +											extractTranslation( pTranslateB, workingTransform ); +										} +										else +										{ +											//Translation via child from element +											daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); +											if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) +											{ +												LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; +												missingSkeletonOrScene = true; +											} +											else +											if ( pTranslateElement ) +											{ +												extractTranslationViaElement( pTranslateElement, workingTransform ); +											} +											else +											{ +												extractTranslationViaSID( pJoint, workingTransform ); +											} + +										} +										 +										//Store the joint transform w/respect to it's name. +										mJointList[(*jointIt).second.c_str()] = workingTransform; +                                    } +								} +								 +								//If anything failed in regards to extracting the skeleton, joints or translation id, +								//mention it +								if ( missingSkeletonOrScene  ) +								{ +									LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; +								} +							}//got skeleton? +						} +						 +						 +						domSkin::domJoints* joints = skin->getJoints(); +						 +						domInputLocal_Array& joint_input = joints->getInput_array(); +						 +						for (size_t i = 0; i < joint_input.getCount(); ++i) +						{ +							domInputLocal* input = joint_input.get(i); +							xsNMTOKEN semantic = input->getSemantic(); +							 +							if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) +							{ //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames +								daeElement* elem = input->getSource().getElement(); +								 +								domSource* source = daeSafeCast<domSource>(elem); +								if (source) +								{ +									 +									 +									domName_array* names_source = source->getName_array(); +									 +									if (names_source) +									{ +										domListOfNames &names = names_source->getValue(); +										 +										for (size_t j = 0; j < names.getCount(); ++j) +										{ +											std::string name(names.get(j)); +											if (mJointMap.find(name) != mJointMap.end()) +											{ +												name = mJointMap[name]; +											} +											model->mSkinInfo.mJointNames.push_back(name); +											model->mSkinInfo.mJointMap[name] = j; +										} +									} +									else +									{ +										domIDREF_array* names_source = source->getIDREF_array(); +										if (names_source) +										{ +											xsIDREFS& names = names_source->getValue(); +											 +											for (size_t j = 0; j < names.getCount(); ++j) +											{ +												std::string name(names.get(j).getID()); +												if (mJointMap.find(name) != mJointMap.end()) +												{ +													name = mJointMap[name]; +												} +												model->mSkinInfo.mJointNames.push_back(name); +												model->mSkinInfo.mJointMap[name] = j; +											} +										} +									} +								} +							} +							else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) +							{ //found inv_bind_matrix array, fill model->mInvBindMatrix +								domSource* source = daeSafeCast<domSource>(input->getSource().getElement()); +								if (source) +								{ +									domFloat_array* t = source->getFloat_array(); +									if (t) +									{ +										domListOfFloats& transform = t->getValue(); +										S32 count = transform.getCount()/16; +										 +										for (S32 k = 0; k < count; ++k) +										{ +											LLMatrix4 mat; +											 +											for (int i = 0; i < 4; i++) +											{ +												for(int j = 0; j < 4; j++) +												{ +													mat.mMatrix[i][j] = transform[k*16 + i + j*4]; +												} +											} +											 +											model->mSkinInfo.mInvBindMatrix.push_back(mat);											 +										} +									} +								} +							} +						} +						 +						//Now that we've parsed the joint array, let's determine if we have a full rig +						//(which means we have all the joint sthat are required for an avatar versus +						//a skinned asset attached to a node in a file that contains an entire skeleton, +						//but does not use the skeleton).						 +						buildJointToNodeMappingFromScene( root ); +						mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); +										 +						if ( !missingSkeletonOrScene ) +						{ +							//Set the joint translations on the avatar - if it's a full mapping +							//The joints are reset in the dtor +							if ( mPreview->getRigWithSceneParity() ) +							{	 +								std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin(); +								std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end(); +								for (;masterJointIt!=masterJointItEnd;++masterJointIt ) +								{ +									std::string lookingForJoint = (*masterJointIt).first.c_str(); +									 +									if ( mJointList.find( lookingForJoint ) != mJointList.end() ) +									{ +										//LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL; +										LLMatrix4 jointTransform = mJointList[lookingForJoint]; +										LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint ); +										if ( pJoint ) +										{    +											LLUUID fake_mesh_id; +											fake_mesh_id.generate(); +											pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString()); +										} +										else +										{ +											//Most likely an error in the asset. +											LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; +										} +									} +								} +							} +						} //missingSkeletonOrScene +						 +						 +						//We need to construct the alternate bind matrix (which contains the new joint positions) +						//in the same order as they were stored in the joint buffer. The joints associated +						//with the skeleton are not stored in the same order as they are in the exported joint buffer. +						//This remaps the skeletal joints to be in the same order as the joints stored in the model. +						std::vector<std::string> :: const_iterator jointIt  = model->mSkinInfo.mJointNames.begin(); +						const int jointCnt = model->mSkinInfo.mJointNames.size(); +						for ( int i=0; i<jointCnt; ++i, ++jointIt ) +						{ +							std::string lookingForJoint = (*jointIt).c_str(); +							//Look for the joint xform that we extracted from the skeleton, using the jointIt as the key +							//and store it in the alternate bind matrix +							if ( mJointList.find( lookingForJoint ) != mJointList.end() ) +							{ +								LLMatrix4 jointTransform = mJointList[lookingForJoint]; +								LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; +								newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); +								model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); +							} +							else +							{ +								LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL; +							} +						} +						 +						//grab raw position array +						 +						domVertices* verts = mesh->getVertices(); +						if (verts) +						{ +							domInputLocal_Array& inputs = verts->getInput_array(); +							for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) +							{ +								if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) +								{ +									domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); +									if (pos_source) +									{ +										domFloat_array* pos_array = pos_source->getFloat_array(); +										if (pos_array) +										{ +											domListOfFloats& pos = pos_array->getValue(); +											 +											for (size_t j = 0; j < pos.getCount(); j += 3) +											{ +												if (pos.getCount() <= j+2) +												{ +													LL_ERRS() << "Invalid position array size." << LL_ENDL; +												} +												 +												LLVector3 v(pos[j], pos[j+1], pos[j+2]); +												 +												//transform from COLLADA space to volume space +												v = v * inverse_normalized_transformation; +												 +												model->mPosition.push_back(v); +											} +										} +									} +								} +							} +						} +						 +						//grab skin weights array +						domSkin::domVertex_weights* weights = skin->getVertex_weights(); +						if (weights) +						{ +							domInputLocalOffset_Array& inputs = weights->getInput_array(); +							domFloat_array* vertex_weights = NULL; +							for (size_t i = 0; i < inputs.getCount(); ++i) +							{ +								if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) +								{ +									domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); +									if (weight_source) +									{ +										vertex_weights = weight_source->getFloat_array(); +									} +								} +							} +							 +							if (vertex_weights) +							{ +								domListOfFloats& w = vertex_weights->getValue(); +								domListOfUInts& vcount = weights->getVcount()->getValue(); +								domListOfInts& v = weights->getV()->getValue(); +								 +								U32 c_idx = 0; +								for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) +								{ //for each vertex +									daeUInt count = vcount[vc_idx]; +									 +									//create list of weights that influence this vertex +									LLModel::weight_list weight_list; +									 +									for (daeUInt i = 0; i < count; ++i) +									{ //for each weight +										daeInt joint_idx = v[c_idx++]; +										daeInt weight_idx = v[c_idx++]; +										 +										if (joint_idx == -1) +										{ +											//ignore bindings to bind_shape_matrix +											continue; +										} +										 +										F32 weight_value = w[weight_idx]; +										 +										weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); +									} +									 +									//sort by joint weight +									std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); +									 +									std::vector<LLModel::JointWeight> wght; +									 +									F32 total = 0.f; +									 +									for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) +									{ //take up to 4 most significant weights +										if (weight_list[i].mWeight > 0.f) +										{ +											wght.push_back( weight_list[i] ); +											total += weight_list[i].mWeight; +										} +									} +									 +									F32 scale = 1.f/total; +									if (scale != 1.f) +									{ //normalize weights +										for (U32 i = 0; i < wght.size(); ++i) +										{ +											wght[i].mWeight *= scale; +										} +									} +									 +									model->mSkinWeights[model->mPosition[vc_idx]] = wght; +								} +								 +								//add instance to scene for this model +								 +								LLMatrix4 transformation = mTransform; +								// adjust the transformation to compensate for mesh normalization +								 +								LLMatrix4 mesh_translation; +								mesh_translation.setTranslation(mesh_translation_vector); +								mesh_translation *= transformation; +								transformation = mesh_translation; +								 +								LLMatrix4 mesh_scale; +								mesh_scale.initScale(mesh_scale_vector); +								mesh_scale *= transformation; +								transformation = mesh_scale; +								 +								std::map<std::string, LLImportMaterial> materials; +								for (U32 i = 0; i < model->mMaterialList.size(); ++i) +								{ +									materials[model->mMaterialList[i]] = LLImportMaterial(); +								} +								mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); +								stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); +							} +						} +					} +				} +			} +		} +	} +	 +	daeElement* scene = root->getDescendant("visual_scene"); +	 +	if (!scene) +	{ +		LL_WARNS() << "document has no visual_scene" << LL_ENDL; +		setLoadState( ERROR_PARSING ); +		return true; +	} +	 +	setLoadState( DONE ); + +	bool badElement = false; +	 +	processElement( scene, badElement ); +	 +	if ( badElement ) +	{ +		setLoadState( ERROR_PARSING ); +	} +	 +	return true; +} + +void LLModelLoader::setLoadState(U32 state) +{ +	if (mPreview) +	{ +		mPreview->setLoadState(state); +	} +} + +bool LLModelLoader::loadFromSLM(const std::string& filename) +{  +	//only need to populate mScene with data from slm +	llstat stat; + +	if (LLFile::stat(filename, &stat)) +	{ //file does not exist +		return false; +	} + +	S32 file_size = (S32) stat.st_size; +	 +	llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary); +	LLSD data; +	LLSDSerialize::fromBinary(data, ifstream, file_size); +	ifstream.close(); + +	//build model list for each LoD +	model_list model[LLModel::NUM_LODS]; + +	if (data["version"].asInteger() != SLM_SUPPORTED_VERSION) +	{  //unsupported version +		return false; +	} + +	LLSD& mesh = data["mesh"]; + +	LLVolumeParams volume_params; +	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + +	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) +	{ +		for (U32 i = 0; i < mesh.size(); ++i) +		{ +			std::stringstream str(mesh[i].asString()); +			LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod); +			if (loaded_model->loadModel(str)) +			{ +				loaded_model->mLocalID = i; +				model[lod].push_back(loaded_model); + +				if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) +				{  +					//check to see if rig is valid					 +					mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );					 +				} +			} +		} +	}	 + +	if (model[LLModel::LOD_HIGH].empty()) +	{ //failed to load high lod +		return false; +	} + +	// Set name. +	std::string name = data["name"]; +	if (!name.empty()) +	{ +		model[LLModel::LOD_HIGH][0]->mLabel = name; +	} +	 + +	//load instance list +	model_instance_list instance_list; + +	LLSD& instance = data["instance"]; + +	for (U32 i = 0; i < instance.size(); ++i) +	{ +		//deserialize instance list +		instance_list.push_back(LLModelInstance(instance[i])); + +		//match up model instance pointers +		S32 idx = instance_list[i].mLocalMeshID; + +		for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) +		{ +			if (model[lod].size() > idx) +			{ +				instance_list[i].mLOD[lod] = model[lod][idx]; +			} +			else if (!model[lod].empty()) +			{ +				// slm load failed - indexes are corrupted +				return false; +			} +		} + +		instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; +	} + + +	//convert instance_list to mScene +	mFirstTransform = TRUE; +	for (U32 i = 0; i < instance_list.size(); ++i) +	{ +		LLModelInstance& cur_instance = instance_list[i]; +		mScene[cur_instance.mTransform].push_back(cur_instance); +		stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); +	} +	 +	setLoadState( DONE ); + +	return true; +} + +//static +bool LLModelLoader::isAlive(LLModelLoader* loader) +{ +	if(!loader) +	{ +		return false ; +	} + +	std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ; +	for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ; +	 +	return *iter == loader ; +} + +void LLModelLoader::loadModelCallback() +{ +	assert_main_thread(); + +	if (mPreview) +	{ +		mPreview->loadModelCallback(mLod);	 +	} + +	while (!isStopped()) +	{ //wait until this thread is stopped before deleting self +		apr_sleep(100); +	} + +	//doubel check if "this" is valid before deleting it, in case it is aborted during running. +	if(!isAlive(this)) +	{ +		return ; +	} + +	//generate BBox here if non-valide model in scene was detected +	if (mPreview->mHasBrokenModel) +	{ +		mPreview->genModelBBox(); +	} + +	//cleanup model loader +	if (mPreview) +	{ +		mPreview->mModelLoader = NULL; +	} + +	delete this; +} +//----------------------------------------------------------------------------- +// buildJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot ) +{ +	daeElement* pScene = pRoot->getDescendant("visual_scene"); +	if ( pScene ) +	{ +		daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); +		S32 childCount = children.getCount(); +		for (S32 i = 0; i < childCount; ++i) +		{ +			domNode* pNode = daeSafeCast<domNode>(children[i]); +			processJointToNodeMapping( pNode );			 +		} +	} +} +//----------------------------------------------------------------------------- +// processJointToNodeMapping() +//----------------------------------------------------------------------------- +void LLModelLoader::processJointToNodeMapping( domNode* pNode ) +{ +	if ( isNodeAJoint( pNode ) ) +	{ +		//1.Store the parent +		std::string nodeName = pNode->getName(); +		if ( !nodeName.empty() ) +		{ +			mJointsFromNode.push_front( pNode->getName() ); +		} +		//2. Handle the kiddo's +		processChildJoints( pNode ); +	} +	else +	{ +		//Determine if the're any children wrt to this failed node. +		//This occurs when an armature is exported and ends up being what essentially amounts to +		//as the root for the visual_scene +		if ( pNode )  +		{ +			processChildJoints( pNode ); +		} +		else  +		{ +			LL_INFOS()<<"Node is NULL"<<LL_ENDL; +		} + +	} +} +//----------------------------------------------------------------------------- +// processChildJoint() +//----------------------------------------------------------------------------- +void LLModelLoader::processChildJoints( domNode* pParentNode ) +{	 +	daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren(); +	S32 childOfChildCount = childOfChild.getCount(); +	for (S32 i = 0; i < childOfChildCount; ++i) +	{ +		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); +		if ( pChildNode ) +		{ +			processJointToNodeMapping( pChildNode ); +		} +	} +} + +//----------------------------------------------------------------------------- +// critiqueRigForUploadApplicability() +//----------------------------------------------------------------------------- +void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ) +{ +	critiqueJointToNodeMappingFromScene(); +	 +	//Determines the following use cases for a rig: +	//1. It is suitable for upload with skin weights & joint positions, or +	//2. It is suitable for upload as standard av with just skin weights +	 +	bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); +	bool isRigLegacyOK			 = isRigLegacy( jointListFromAsset ); + +	//It's OK that both could end up being true, both default to false +	if ( isJointPositionUploadOK ) +	{ +		setRigValidForJointPositionUpload( true ); +	} + +	if ( isRigLegacyOK)  +	{	 +		setLegacyRigValid( true ); +	} + +} +//----------------------------------------------------------------------------- +// critiqueJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLModelPreview::critiqueJointToNodeMappingFromScene( void  ) +{ +	//Do the actual nodes back the joint listing from the dae? +	//if yes then this is a fully rigged asset, otherwise it's just a partial rig +	 +	std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin(); +	std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end(); +	bool result = true; + +	if ( !mJointsFromNode.empty() ) +	{ +		for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt ) +		{ +			std::string name = *jointsFromNodeIt; +			if ( mJointTransformMap.find( name ) != mJointTransformMap.end() ) +			{ +				continue; +			} +			else +			{ +				LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL; +				result = false;				 +			} +		} +	} +	else +	{ +		result = false; +	} + +	//Determines the following use cases for a rig: +	//1. Full av rig  w/1-1 mapping from the scene and joint array +	//2. Partial rig but w/o parity between the scene and joint array +	if ( result ) +	{		 +		setRigWithSceneParity( true ); +	}	 +} +//----------------------------------------------------------------------------- +// isRigLegacy() +//----------------------------------------------------------------------------- +bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) +{ +	//No joints in asset +	if ( jointListFromAsset.size() == 0 ) +	{ +		return false; +	} + +	bool result = false; + +	std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();	 +	std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); +	 +	std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();	 +	std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); +	 +	for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) +	{ +		result = false; +		modelJointIt = jointListFromAsset.begin(); + +		for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) +		{ +			if ( *masterJointIt == *modelJointIt ) +			{ +				result = true; +				break; +			}			 +		}		 +		if ( !result ) +		{ +			LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; +			break; +		} +	}	 +	return result; +} +//----------------------------------------------------------------------------- +// isRigSuitableForJointPositionUpload() +//----------------------------------------------------------------------------- +bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ) +{ +	bool result = false; + +	std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();	 +	std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end(); +	 +	std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();	 +	std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); +	 +	for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) +	{ +		result = false; +		modelJointIt = jointListFromAsset.begin(); + +		for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) +		{ +			if ( *masterJointIt == *modelJointIt ) +			{ +				result = true; +				break; +			}			 +		}		 +		if ( !result ) +		{ +			LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; +			break; +		} +	}	 +	return result; +} + + +//called in the main thread +void LLModelLoader::loadTextures() +{ +	BOOL is_paused = isPaused() ; +	pause() ; //pause the loader  + +	for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) +	{ +		for(U32 i = 0 ; i < iter->second.size(); i++) +		{ +			for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin(); +				j != iter->second[i].mMaterial.end(); ++j) +			{ +				LLImportMaterial& material = j->second; + +				if(!material.mDiffuseMapFilename.empty()) +				{ +					material.mDiffuseMap =  +						LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); +					material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); +					material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX); +					mNumOfFetchingTextures++ ; +				} +			} +		} +	} + +	if(!is_paused) +	{ +		unpause() ; +	} +} + +//----------------------------------------------------------------------------- +// isNodeAJoint() +//----------------------------------------------------------------------------- +bool LLModelLoader::isNodeAJoint( domNode* pNode ) +{ +	if ( !pNode ) +	{ +		LL_INFOS()<<"Created node is NULL"<<LL_ENDL; +		return false; +	} +	 +	if ( pNode->getName() == NULL ) +	{ +		LL_INFOS()<<"Parsed node has no name "<<LL_ENDL; +		//Attempt to write the node id, if possible (aids in debugging the visual scene) +		if ( pNode->getId() ) +		{ +			LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL; +		} +		return false; +	} + +	if ( mJointMap.find( pNode->getName() )  != mJointMap.end() ) +	{ +		return true; +	} + +	return false; +} +//----------------------------------------------------------------------------- +// verifyCount +//----------------------------------------------------------------------------- +bool LLModelPreview::verifyCount( int expected, int result ) +{ +	if ( expected != result ) +	{ +		LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL; +		return false; +	} +	return true; +} +//----------------------------------------------------------------------------- +// verifyController +//----------------------------------------------------------------------------- +bool LLModelPreview::verifyController( domController* pController ) +{	 + +	bool result = true; + +	domSkin* pSkin = pController->getSkin(); + +	if ( pSkin ) +	{ +		xsAnyURI & uri = pSkin->getSource(); +		domElement* pElement = uri.getElement(); + +		if ( !pElement ) +		{ +			LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL; +			return false; +		} + +		daeString type_str = pElement->getTypeName(); +		if ( stricmp(type_str, "geometry") == 0 ) +		{	 +			//Skin is reference directly by geometry and get the vertex count from skin +			domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights(); +			U32 vertexWeightsCount = pVertexWeights->getCount(); +			domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement(); +			domMesh* pMesh = pGeometry->getMesh();				 +			 +			if ( pMesh ) +			{ +				//Get vertex count from geometry +				domVertices* pVertices = pMesh->getVertices(); +				if ( !pVertices ) +				{  +					LL_INFOS()<<"No vertices!"<<LL_ENDL; +					return false; +				} + +				if ( pVertices ) +				{ +					xsAnyURI src = pVertices->getInput_array()[0]->getSource(); +					domSource* pSource = (domSource*) (domElement*) src.getElement(); +					U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount(); +					result = verifyCount( verticesCount, vertexWeightsCount ); +					if ( !result ) +					{ +						return result; +					} +				} +			}	 + +			U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount(); +			result = verifyCount( vcountCount, vertexWeightsCount );	 +			if ( !result ) +			{ +				return result; +			} + +			domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array(); +			U32 sum = 0; +			for (size_t i=0; i<vcountCount; i++) +			{ +				sum += pVertexWeights->getVcount()->getValue()[i]; +			} +			result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() ); +		} +	} +	 +	return result; +} + +//----------------------------------------------------------------------------- +// extractTranslation() +//----------------------------------------------------------------------------- +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ +	domFloat3 jointTrans = pTranslate->getValue(); +	LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); +	transform.setTranslation( singleJointTranslation ); +} +//----------------------------------------------------------------------------- +// extractTranslationViaElement() +//----------------------------------------------------------------------------- +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) +{ +	if ( pTranslateElement ) +	{ +		domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement ); +		domFloat3 translateChild = pTranslateChild->getValue(); +		LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); +		transform.setTranslation( singleJointTranslation ); +	}	 +} +//----------------------------------------------------------------------------- +// extractTranslationViaSID() +//----------------------------------------------------------------------------- +void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ) +{ +	if ( pElement ) +	{	 +		daeSIDResolver resolver( pElement, "./transform" ); +		domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() ); +		//We are only extracting out the translational component atm +		LLMatrix4 workingTransform; +		if ( pMatrix ) +		{ +			domFloat4x4 domArray = pMatrix->getValue();									 +			for ( int i = 0; i < 4; i++ ) +			{ +				for( int j = 0; j < 4; j++ ) +				{ +					workingTransform.mMatrix[i][j] = domArray[i + j*4]; +				} +			} +			LLVector3 trans = workingTransform.getTranslation(); +			transform.setTranslation( trans );	 +		} +	} +	else +	{ +		LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL; +	} +} +//----------------------------------------------------------------------------- +// processJointNode() +//----------------------------------------------------------------------------- +void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms ) +{ +	if (pNode->getName() == NULL) +	{ +		LL_WARNS() << "nameless node, can't process" << LL_ENDL; +		return; +	} + +	//LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL; + +	//1. handle the incoming node - extract out translation via SID or element + +	LLMatrix4 workingTransform; + +	//Pull out the translate id and store it in the jointTranslations map +	daeSIDResolver jointResolverA( pNode, "./translate" ); +	domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); +	daeSIDResolver jointResolverB( pNode, "./location" ); +	domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); + +	//Translation via SID was successful +	if ( pTranslateA ) +	{ +		extractTranslation( pTranslateA, workingTransform ); +	} +	else +	if ( pTranslateB ) +	{ +		extractTranslation( pTranslateB, workingTransform ); +	} +	else +	{ +		//Translation via child from element +		daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); +		if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) +		{ +			//LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; +			daeSIDResolver jointResolver( pNode, "./matrix" ); +			domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() ); +			if ( pMatrix ) +			{ +				//LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; +				domFloat4x4 domArray = pMatrix->getValue();									 +				for ( int i = 0; i < 4; i++ ) +				{ +					for( int j = 0; j < 4; j++ ) +					{ +						workingTransform.mMatrix[i][j] = domArray[i + j*4]; +					} +				} +			} +			else +			{ +				LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL; +			} +		} +		else +		{ +			extractTranslationViaElement( pTranslateElement, workingTransform ); +		} +	} + +	//Store the working transform relative to the nodes name. +	jointTransforms[ pNode->getName() ] = workingTransform; + +	//2. handle the nodes children + +	//Gather and handle the incoming nodes children +	daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren(); +	S32 childOfChildCount = childOfChild.getCount(); + +	for (S32 i = 0; i < childOfChildCount; ++i) +	{ +		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); +		if ( pChildNode ) +		{ +			processJointNode( pChildNode, jointTransforms ); +		} +	} +} +//----------------------------------------------------------------------------- +// getChildFromElement() +//----------------------------------------------------------------------------- +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ +    daeElement* pChildOfElement = pElement->getChild( name.c_str() ); +	if ( pChildOfElement ) +	{ +		return pChildOfElement; +	} +	LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; +    return NULL; +} + +void LLModelLoader::processElement( daeElement* element, bool& badElement ) +{ +	LLMatrix4 saved_transform = mTransform; + +	domTranslate* translate = daeSafeCast<domTranslate>(element); +	if (translate) +	{ +		domFloat3 dom_value = translate->getValue(); + +		LLMatrix4 translation; +		translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + +		translation *= mTransform; +		mTransform = translation; +	} + +	domRotate* rotate = daeSafeCast<domRotate>(element); +	if (rotate) +	{ +		domFloat4 dom_value = rotate->getValue(); + +		LLMatrix4 rotation; +		rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + +		rotation *= mTransform; +		mTransform = rotation; +	} + +	domScale* scale = daeSafeCast<domScale>(element); +	if (scale) +	{ +		domFloat3 dom_value = scale->getValue(); + + +		LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]); +		scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes +		LLMatrix4 scaling; +		scaling.initScale(scale_vector); + +		scaling *= mTransform; +		mTransform = scaling; +	} + +	domMatrix* matrix = daeSafeCast<domMatrix>(element); +	if (matrix) +	{ +		domFloat4x4 dom_value = matrix->getValue(); + +		LLMatrix4 matrix_transform; + +		for (int i = 0; i < 4; i++) +		{ +			for(int j = 0; j < 4; j++) +			{ +				matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; +			} +		} + +		matrix_transform *= mTransform; +		mTransform = matrix_transform; +	} + +	domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); +	if (instance_geo) +	{ +		domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); +		if (geo) +		{ +			domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); +			if (mesh) +			{ +				LLModel* model = mModel[mesh]; +				if (model) +				{ +					LLMatrix4 transformation = mTransform; + +					if (mTransform.determinant() < 0) +					{ //negative scales are not supported +						LL_INFOS() << "Negative scale detected, unsupported transform.  domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL; +						badElement = true; +					} +					 +					std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo); + +					// adjust the transformation to compensate for mesh normalization +					LLVector3 mesh_scale_vector; +					LLVector3 mesh_translation_vector; +					model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + +					LLMatrix4 mesh_translation; +					mesh_translation.setTranslation(mesh_translation_vector); +					mesh_translation *= transformation; +					transformation = mesh_translation; + +					LLMatrix4 mesh_scale; +					mesh_scale.initScale(mesh_scale_vector); +					mesh_scale *= transformation; +					transformation = mesh_scale; + +					std::string label = getElementLabel(instance_geo); +					mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); + +					stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); +				} +			} +		} +		else  +		{ +			LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL; +			badElement = true;			 +		} + +	} + +	domInstance_node* instance_node = daeSafeCast<domInstance_node>(element); +	if (instance_node) +	{ +		daeElement* instance = instance_node->getUrl().getElement(); +		if (instance) +		{ +			processElement(instance,badElement); +		} +	} + +	//process children +	daeTArray< daeSmartRef<daeElement> > children = element->getChildren(); +	int childCount = children.getCount(); +	for (S32 i = 0; i < childCount; i++) +	{ +		processElement(children[i],badElement); +	} + +	domNode* node = daeSafeCast<domNode>(element); +	if (node) +	{ //this element was a node, restore transform before processiing siblings +		mTransform = saved_transform; +	} +} + +std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ +	std::map<std::string, LLImportMaterial> materials; +	for (int i = 0; i < model->mMaterialList.size(); i++) +	{ +		LLImportMaterial import_material; + +		domInstance_material* instance_mat = NULL; + +		domBind_material::domTechnique_common* technique = +		daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + +		if (technique) +		{ +			daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>(); +			for (int j = 0; j < inst_materials.getCount(); j++) +			{ +				std::string symbol(inst_materials[j]->getSymbol()); + +				if (symbol == model->mMaterialList[i]) // found the binding +				{ +					instance_mat = inst_materials[j]; +				} +			} +		} + +		if (instance_mat) +		{ +			domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement()); +			if (material) +			{ +				domInstance_effect* instance_effect = +				daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); +				if (instance_effect) +				{ +					domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement()); +					if (effect) +					{ +						domProfile_COMMON* profile = +						daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); +						if (profile) +						{ +							import_material = profileToMaterial(profile); +						} +					} +				} +			} +		} + +		import_material.mBinding = model->mMaterialList[i]; +		materials[model->mMaterialList[i]] = import_material; +	} + +	return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ +	LLImportMaterial mat; +	mat.mFullbright = FALSE; + +	daeElement* diffuse = material->getDescendant("diffuse"); +	if (diffuse) +	{ +		domCommon_color_or_texture_type_complexType::domTexture* texture = +		daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture")); +		if (texture) +		{ +			domCommon_newparam_type_Array newparams = material->getNewparam_array(); +			for (S32 i = 0; i < newparams.getCount(); i++) +			{ +				domFx_surface_common* surface = newparams[i]->getSurface(); +				if (surface) +				{ +					domFx_surface_init_common* init = surface->getFx_surface_init_common(); +					if (init) +					{ +						domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + +						if (init_from.getCount() > i) +						{ +							domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement()); +							if (image) +							{ +								// we only support init_from now - embedded data will come later +								domImage::domInit_from* init = image->getInit_from(); +								if (init) +								{									 +									mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); +									mat.mDiffuseMapLabel = getElementLabel(material); +								} +							} +						} +					} +				} +			} +		} + +		domCommon_color_or_texture_type_complexType::domColor* color = +		daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color")); +		if (color) +		{ +			domFx_color_common domfx_color = color->getValue(); +			LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); +			mat.mDiffuseColor = value; +		} +	} + +	daeElement* emission = material->getDescendant("emission"); +	if (emission) +	{ +		LLColor4 emission_color = getDaeColor(emission); +		if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) +		{ +			mat.mFullbright = TRUE; +		} +	} + +	return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ +	// if we have a name attribute, use it +	std::string name = element->getAttribute("name"); +	if (name.length()) +	{ +		return name; +	} + +	// if we have an ID attribute, use it +	if (element->getID()) +	{ +		return std::string(element->getID()); +	} + +	// if we have a parent, use it +	daeElement* parent = element->getParent(); +	if (parent) +	{ +		// if parent has a name, use it +		std::string name = parent->getAttribute("name"); +		if (name.length()) +		{ +			return name; +		} + +		// if parent has an ID, use it +		if (parent->getID()) +		{ +			return std::string(parent->getID()); +		} +	} + +	// try to use our type +	daeString element_name = element->getElementName(); +	if (element_name) +	{ +		return std::string(element_name); +	} + +	// if all else fails, use "object" +	return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ +	LLColor4 value; +	domCommon_color_or_texture_type_complexType::domColor* color = +	daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color")); +	if (color) +	{ +		domFx_color_common domfx_color = color->getValue(); +		value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); +	} + +	return value; +} + +//-----------------------------------------------------------------------------  // LLModelPreview  //----------------------------------------------------------------------------- @@ -1172,11 +3142,10 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)  , mPelvisZOffset( 0.0f )  , mLegacyRigValid( false )  , mRigValidJointUpload( false ) -, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )  , mResetJoints( false ) -, mModelNoErrors( true )  , mRigParityWithScene( false )  , mLastJointUpdate( false ) +, mHasBrokenModel( false )  {  	mNeedsUpdate = TRUE;  	mCameraDistance = 0.f; @@ -1219,20 +3188,51 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)  	glodInit(); +	//move into joint mapper class +	//1. joints for joint offset verification +	mMasterJointList.push_front("mPelvis"); +	mMasterJointList.push_front("mTorso"); +	mMasterJointList.push_front("mChest"); +	mMasterJointList.push_front("mNeck"); +	mMasterJointList.push_front("mHead"); +	mMasterJointList.push_front("mCollarLeft"); +	mMasterJointList.push_front("mShoulderLeft"); +	mMasterJointList.push_front("mElbowLeft"); +	mMasterJointList.push_front("mWristLeft"); +	mMasterJointList.push_front("mCollarRight"); +	mMasterJointList.push_front("mShoulderRight"); +	mMasterJointList.push_front("mElbowRight"); +	mMasterJointList.push_front("mWristRight"); +	mMasterJointList.push_front("mHipRight"); +	mMasterJointList.push_front("mKneeRight"); +	mMasterJointList.push_front("mFootRight"); +	mMasterJointList.push_front("mHipLeft"); +	mMasterJointList.push_front("mKneeLeft"); +	mMasterJointList.push_front("mFootLeft"); +	//2. legacy joint list - used to verify rigs that will not be using joint offsets +	mMasterLegacyJointList.push_front("mPelvis"); +	mMasterLegacyJointList.push_front("mTorso"); +	mMasterLegacyJointList.push_front("mChest"); +	mMasterLegacyJointList.push_front("mNeck"); +	mMasterLegacyJointList.push_front("mHead"); +	mMasterLegacyJointList.push_front("mHipRight"); +	mMasterLegacyJointList.push_front("mKneeRight"); +	mMasterLegacyJointList.push_front("mFootRight"); +	mMasterLegacyJointList.push_front("mHipLeft"); +	mMasterLegacyJointList.push_front("mKneeLeft"); +	mMasterLegacyJointList.push_front("mFootLeft"); +  	createPreviewAvatar();  }  LLModelPreview::~LLModelPreview()  { -	// glod apparently has internal mem alignment issues that are angering -	// the heap-check code in windows, these should be hunted down in that -	// TP code, if possible -	// -	// kernel32.dll!HeapFree()  + 0x14 bytes	 -	// msvcr100.dll!free(void * pBlock)  Line 51	C -	// glod.dll!glodGetGroupParameteriv()  + 0x119 bytes	 -	// glod.dll!glodShutdown()  + 0x77 bytes	 -	// +	if (mModelLoader) +	{ +		mModelLoader->mPreview = NULL; +		mModelLoader = NULL; +	} +	//*HACK : *TODO : turn this back on when we understand why this crashes  	//glodShutdown();  } @@ -1302,9 +3302,7 @@ U32 LLModelPreview::calcResourceCost()  					   decomp,  					   mFMP->childGetValue("upload_skin").asBoolean(),  					   mFMP->childGetValue("upload_joints").asBoolean(), -					   TRUE, -						FALSE, -						instance.mModel->mSubmodelID); +					   TRUE);  			num_hulls += decomp.mHull.size();  			for (U32 i = 0; i < decomp.mHull.size(); ++i) @@ -1371,12 +3369,29 @@ void LLModelPreview::rebuildUploadData()  	F32 max_scale = 0.f; -	BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); -	BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); +	//reorder materials to match mBaseModel +	for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +	{ +		if (mBaseModel.size() == mModel[i].size()) +		{ +			for (U32 j = 0; j < mBaseModel.size(); ++j) +			{ +				 +				int refFaceCnt = 0; +				int modelFaceCnt = 0; +				 +				if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) +				{ +					setLoadState( LLModelLoader::ERROR_MATERIALS ); +					mFMP->childDisable( "calculate_btn" ); +				} +			} +		} +	}  	for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)  	{ //for each transform in scene -		LLMatrix4 mat		= iter->first; +		LLMatrix4 mat = iter->first;  		// compute position  		LLVector3 position = LLVector3(0, 0, 0) * mat; @@ -1393,171 +3408,38 @@ void LLModelPreview::rebuildUploadData()  		mat *= scale_mat; -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) -		{ //for each instance with said transform applied  -			LLModelInstance instance = *model_iter++; +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) +		{ //for each instance with said transform applied +			LLModelInstance instance = *model_iter;  			LLModel* base_model = instance.mModel; -			if (base_model && !requested_name.empty()) +			if (base_model)  			{  				base_model->mRequestedLabel = requested_name;  				base_model->mMetric = metric;  			} -			for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) -			{ -				LLModel* lod_model = NULL; -				if (!legacyMatching) +			S32 idx = 0; +			for (idx = 0; idx < mBaseModel.size(); ++idx) +			{  //find reference instance for this model +				if (mBaseModel[idx] == base_model)  				{ -					// Fill LOD slots by finding matching meshes by label with name extensions -					// in the appropriate scene for each LOD. This fixes all kinds of issues -					// where the indexed method below fails in spectacular fashion. -					// If you don't take the time to name your LOD and PHYS meshes -					// with the name of their corresponding mesh in the HIGH LOD, -					// then the indexed method will be attempted below. - -					LLMatrix4 transform; - -					std::string name_to_match = instance.mLabel; -					llassert(!name_to_match.empty()); - -					int extensionLOD; -					if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) -					{ -						extensionLOD = i; -					} -					else -					{ -						//Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for -						extensionLOD = mPhysicsSearchLOD; -					} - -					std::string toAdd; -					switch (extensionLOD) -					{ -					case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; -					case LLModel::LOD_LOW:      toAdd = "_LOD1"; break; -					case LLModel::LOD_MEDIUM:   toAdd = "_LOD2"; break; -					case LLModel::LOD_PHYSICS:  toAdd = "_PHYS"; break; -					case LLModel::LOD_HIGH:                      break; -					} - -					if (name_to_match.find(toAdd) == -1) -					{ -						name_to_match += toAdd; -					} - -					FindModel(mScene[i], name_to_match, lod_model, transform); - -					if (!lod_model && i != LLModel::LOD_PHYSICS) -					{ -						if (importerDebug) -						{ -							LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; -						} - -						int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; -						while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) -						{ -							std::string name_to_match = instance.mLabel; -							llassert(!name_to_match.empty()); - -							std::string toAdd; -							switch (searchLOD) -							{ -							case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; -							case LLModel::LOD_LOW:      toAdd = "_LOD1"; break; -							case LLModel::LOD_MEDIUM:   toAdd = "_LOD2"; break; -							case LLModel::LOD_PHYSICS:  toAdd = "_PHYS"; break; -							case LLModel::LOD_HIGH:                      break; -							} - -							if (name_to_match.find(toAdd) == -1) -							{ -								name_to_match += toAdd; -							} - -							// See if we can find an appropriately named model in LOD 'searchLOD' -							// -							FindModel(mScene[searchLOD], name_to_match, lod_model, transform); -							searchLOD++; -						} -					} +					break;  				} -				else -				{ -					// Use old method of index-based association -					U32 idx = 0; -					for (idx = 0; idx < mBaseModel.size(); ++idx) -					{ -						// find reference instance for this model -						if (mBaseModel[idx] == base_model) -						{ -							if (importerDebug) -							{ -								LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; -							} -							break; -						} -					} +			} -					// If the model list for the current LOD includes that index... -					// +			if(idx < mBaseModel.size()) +			{ +				for (U32 i = 0; i < LLModel::NUM_LODS; i++) +				{ //fill LOD slots based on reference model index  					if (mModel[i].size() > idx)  					{ -						// Assign that index from the model list for our LOD as the LOD model for this instance -						// -						lod_model = mModel[i][idx]; -						if (importerDebug) -						{ -							LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL; -						} -					} -					else if (importerDebug) -					{ -						LL_INFOS() << "List of models does not include index " << idx << LL_ENDL; +						instance.mLOD[i] = mModel[i][idx];  					} -				} - -				if (lod_model) -				{ -					if (importerDebug) -					{ -						if (i == LLModel::LOD_PHYSICS) -						{ -							LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; -						} -						else -						{ -							LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; -						} -					} -					instance.mLOD[i] = lod_model; -				} -				else if (importerDebug) -				{ -					LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL; -				} -			} - -			LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; -			if (!high_lod_model) -			{ -				setLoadState( LLModelLoader::ERROR_MATERIALS ); -				mFMP->childDisable( "calculate_btn" ); -			} -			else -			{ -				for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) -				{				 -					int refFaceCnt = 0; -					int modelFaceCnt = 0; -					llassert(instance.mLOD[i]); -					if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) +					else  					{ -						setLoadState( LLModelLoader::ERROR_MATERIALS ); -						mFMP->childDisable( "calculate_btn" ); +						instance.mLOD[i] = NULL;  					}  				}  			} @@ -1566,34 +3448,6 @@ void LLModelPreview::rebuildUploadData()  		}  	} -	for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++) -	{ -		// Search for models that are not included into upload data -		// If we found any, that means something we loaded is not a sub-model. -		for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) -		{ -			bool found_model = false; -			for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) -			{ -				LLModelInstance& instance = *iter; -				if (instance.mLOD[lod] == mModel[lod][model_ind]) -				{ -					found_model = true; -					break; -				} -			} -			if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) -			{ -				if (importerDebug) -				{ -					LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." <<  LL_ENDL; -				} -				setLoadState( LLModelLoader::ERROR_MATERIALS ); -				mFMP->childDisable( "calculate_btn" ); -			} -		} -	} -  	F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale;  	F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); @@ -1660,6 +3514,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw  			meshes.insert(instance.mModel);  			std::stringstream str; +  			LLModel::Decomposition& decomp =  				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?   				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :  @@ -1672,8 +3527,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw  				instance.mLOD[LLModel::LOD_LOW],   				instance.mLOD[LLModel::LOD_IMPOSTOR],   				decomp,  -				save_skinweights, save_joint_positions, -                FALSE, TRUE, instance.mModel->mSubmodelID); +				save_skinweights, save_joint_positions, FALSE, TRUE); +  			data["mesh"][instance.mModel->mLocalID] = str.str();  		} @@ -1741,28 +3596,13 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable  		clearGLODGroup();  	} -	mModelLoader = new LLDAELoader( -		filename, -		lod,  -		&LLModelPreview::loadedCallback, -		&LLModelPreview::lookupJointByName, -		&LLModelPreview::loadTextures, -		&LLModelPreview::stateChangedCallback, -		this, -		mJointTransformMap, -		mJointsFromNode, -		gSavedSettings.getU32("ImporterModelLimit")); +	mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );  	if (force_disable_slm)  	{  		mModelLoader->mTrySLM = false;  	} -	else -	{ -		//only try to load from slm if viewer is configured to do so and this is the  -		//initial model load (not an LoD or physics shape) -		mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); -	} +  	mModelLoader->start();  	mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); @@ -1793,7 +3633,6 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)  	if (lod >= 0 && lod <= 3)  	{ -		mPhysicsSearchLOD = lod;  		mModel[LLModel::LOD_PHYSICS] = mModel[lod];  		mScene[LLModel::LOD_PHYSICS] = mScene[lod];  		mLODFile[LLModel::LOD_PHYSICS].clear(); @@ -1813,14 +3652,11 @@ void LLModelPreview::clearIncompatible(S32 lod)  		return;  	} -	// at this point we don't care about sub-models, -	// different amount of sub-models means face count mismatch, not incompatibility -	U32 lod_size = countRootModels(mModel[lod]);  	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)  	{ //clear out any entries that aren't compatible with this model  		if (i != lod)  		{ -			if (countRootModels(mModel[i]) != lod_size) +			if (mModel[i].size() != mModel[lod].size())  			{  				mModel[i].clear();  				mScene[i].clear(); @@ -1855,7 +3691,7 @@ void LLModelPreview::clearGLODGroup()  	}  } -void LLModelPreview::loadModelCallback(S32 loaded_lod) +void LLModelPreview::loadModelCallback(S32 lod)  {  	assert_main_thread(); @@ -1868,18 +3704,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  	if(getLoadState() >= LLModelLoader::ERROR_PARSING)  	{  		mLoading = false ; -		mModelLoader = NULL;  		return ;  	} -	// Copy determinations about rig so UI will reflect them -	// -	setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); -	setLegacyRigValid(mModelLoader->isLegacyRigValid()); -  	mModelLoader->loadTextures() ; -	if (loaded_lod == -1) +	if (lod == -1)  	{ //populate all LoDs from model loader scene  		mBaseModel.clear();  		mBaseScene.clear(); @@ -1911,11 +3741,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  						//override displayed model with current LoD  						list_iter->mModel = list_iter->mLOD[lod]; -						if (!list_iter->mModel) -						{ -							continue; -						} -  						//add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)  						S32 idx = list_iter->mModel->mLocalID; @@ -1924,7 +3749,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  							mModel[lod].resize(idx+1);  						} -						mModel[lod][idx] = list_iter->mModel; +						mModel[lod][idx] = list_iter->mModel;	  						if (!list_iter->mModel->mSkinWeights.empty())  						{  							skin_weights = true; @@ -1967,31 +3792,31 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  	}  	else  	{ //only replace given LoD -		mModel[loaded_lod] = mModelLoader->mModelList; -		mScene[loaded_lod] = mModelLoader->mScene; -		mVertexBuffer[loaded_lod].clear(); +		mModel[lod] = mModelLoader->mModelList; +		mScene[lod] = mModelLoader->mScene; +		mVertexBuffer[lod].clear(); -		setPreviewLOD(loaded_lod); +		setPreviewLOD(lod); -		if (loaded_lod == LLModel::LOD_HIGH) +		if (lod == LLModel::LOD_HIGH)  		{ //save a copy of the highest LOD for automatic LOD manipulation  			if (mBaseModel.empty())  			{ //first time we've loaded a model, auto-gen LoD  				mGenLOD = true;  			} -			mBaseModel = mModel[loaded_lod]; +			mBaseModel = mModel[lod];  			clearGLODGroup(); -			mBaseScene = mScene[loaded_lod]; +			mBaseScene = mScene[lod];  			mVertexBuffer[5].clear();  		} -		clearIncompatible(loaded_lod); +		clearIncompatible(lod);  		mDirty = true; -		if (loaded_lod == LLModel::LOD_HIGH) +		if (lod == LLModel::LOD_HIGH)  		{  			resetPreviewTarget();  		} @@ -2010,8 +3835,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  	refresh();  	mModelLoadedSignal(); - -	mModelLoader = NULL;  }  void LLModelPreview::resetPreviewTarget() @@ -2360,20 +4183,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);  			mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); -            std::string name = base->mLabel; - -            switch (lod) -            { -                case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; -                case LLModel::LOD_LOW:      name += "_LOD1"; break; -		        case LLModel::LOD_MEDIUM:   name += "_LOD2"; break; -                case LLModel::LOD_PHYSICS:  name += "_PHYS"; break; -                case LLModel::LOD_HIGH:                      break; -            } - -            mModel[lod][mdl_idx]->mLabel = name; -			mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; -              			GLint* sizes = new GLint[patch_count*2];  			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);  			stop_gloderror(); @@ -2486,6 +4295,125 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  	{  		shader->bind();  	} + +	/*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) +	 { //build physics scene +	 mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; +	 mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + +	 for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) +	 { +	 mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); +	 } +	 }*/ +} + +void LLModelPreview::genModelBBox() +{ +	LLVector3 min, max; +	min = this->mModelLoader->mExtents[0]; +	max = this->mModelLoader->mExtents[1]; + +	std::vector<LLVector3> v_list; +	v_list.resize(4); +	std::map<U8, std::vector<LLVector3> > face_list; + +	// Face 0 +	v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); +	v_list[1] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); +	v_list[2] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); +	v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(0, v_list)); + +	// Face 1 +	v_list[0] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); +	v_list[1] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); +	v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); +	v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(1, v_list)); + +	// Face 2 +	v_list[0] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); +	v_list[1] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); +	v_list[2] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); +	v_list[3] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(2, v_list)); + +	// Face 3 +	v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); +	v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); +	v_list[2] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); +	v_list[3] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(3, v_list)); + +	// Face 4 +	v_list[0] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); +	v_list[1] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); +	v_list[2] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); +	v_list[3] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(4, v_list)); + +	// Face 5 +	v_list[0] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); +	v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); +	v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); +	v_list[3] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); +	face_list.insert(std::pair<U8, std::vector<LLVector3> >(5, v_list)); + +	U16 Idx[] = { 0, 1, 2, 3, 0, 2, }; + +	U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; +	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); +	buff->allocateBuffer(4, 6, true); + +	LLStrider<LLVector3> pos; +	LLStrider<U16> idx; +	LLStrider<LLVector3> norm; +	LLStrider<LLVector2> tc; + +	buff->getVertexStrider(pos); +	buff->getIndexStrider(idx); + +	buff->getNormalStrider(norm); +	buff->getTexCoord0Strider(tc); + +	for (U32 i = 0; i < 6; ++i) +	{ +		idx[i] = Idx[i]; +	} + +	LLVolumeParams volume_params; +	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); +	LLModel* mdl = new LLModel(volume_params, 0.f); +	mdl->mLabel = "BBOX"; + +	mdl->setNumVolumeFaces(6); +	for (U8 i = 0; i < 6; ++i) +	{ +		for (U8 j = 0; j < 4; ++j) +		{ +			pos[j] = face_list[i][j]; +		} + +		mdl->setVolumeFaceData(i, pos, norm, tc, idx, buff->getNumVerts(), buff->getNumIndices()); +	} + +	if (validate_model(mdl)) +	{ +		LLMatrix4 mat; +		std::map<std::string, LLImportMaterial> materials; +		std::vector<LLModelInstance> instance_list; +		instance_list.push_back(LLModelInstance(mdl, mdl->mLabel, mat, materials)); + +		for (S32 i = LLModel::LOD_HIGH - 1; i >= 0; i--) +		{ +			mModel[i].clear(); +			mModel[i].push_back(mdl); + +			mScene[i].clear(); +			mScene[i].insert(std::pair<LLMatrix4, std::vector<LLModelInstance> >(mat, instance_list)); +		} +	}  }  void LLModelPreview::updateStatusMessages() @@ -2502,89 +4430,43 @@ void LLModelPreview::updateStatusMessages()  	S32 total_verts[LLModel::NUM_LODS];  	S32 total_submeshes[LLModel::NUM_LODS]; -    for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) -    { -        total_tris[i] = 0; -	    total_verts[i] = 0; -	    total_submeshes[i] = 0; -    } - -    for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) +	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)  	{ -		LLModelInstance& instance = *iter; - -        LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; -        if (!model_high_lod) -		{ -			setLoadState( LLModelLoader::ERROR_MATERIALS ); -			mFMP->childDisable( "calculate_btn" ); -			continue; -		} +		//initialize total for this lod to 0 +		total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; -        for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +		for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter)  		{ -            LLModel* lod_model = instance.mLOD[i]; -            if (!lod_model) -            { -                setLoadState( LLModelLoader::ERROR_MATERIALS ); -                mFMP->childDisable( "calculate_btn" ); -            } - -            int refFaceCnt = 0; -            int modelFaceCnt = 0; - -            if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) ) +			for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)  			{ -                setLoadState( LLModelLoader::ERROR_MATERIALS ); -				mFMP->childDisable( "calculate_btn" ); -			} - -            if (lod_model) -			{ -					//for each model in the lod -				S32 cur_tris = 0; -				S32 cur_verts = 0; -				S32 cur_submeshes = lod_model->getNumVolumeFaces(); - -				for (S32 j = 0; j < cur_submeshes; ++j) -				{ //for each submesh (face), add triangles and vertices to current total -					const LLVolumeFace& face = lod_model->getVolumeFace(j); -					cur_tris += face.mNumIndices/3; -					cur_verts += face.mNumVertices; -				} - -                std::string instance_name = instance.mLabel; +				LLModel* model = instance->mModel; +				if (model) +				{ +					 //for each model in the lod +					S32 cur_tris = 0; +					S32 cur_verts = 0; +					S32 cur_submeshes = model->getNumVolumeFaces(); -                BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); -                if (importerDebug) -                { -                    // Useful for debugging generalized complaints below about total submeshes which don't have enough -                    // context to address exactly what needs to be fixed to move towards compliance with the rules. -                    // -                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: "   << cur_verts     << LL_ENDL; -                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris:  "   << cur_tris      << LL_ENDL; -                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: "   << cur_submeshes << LL_ENDL; - -                    LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); -                    while (mat_iter != lod_model->mMaterialList.end()) -                    { -                        LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL; -                        mat_iter++; -                    } -                } +					for (S32 j = 0; j < cur_submeshes; ++j) +					{ //for each submesh (face), add triangles and vertices to current total +						const LLVolumeFace& face = model->getVolumeFace(j); +						cur_tris += face.mNumIndices/3; +						cur_verts += face.mNumVertices; +					} -                //add this model to the lod total -				total_tris[i] += cur_tris; -				total_verts[i] += cur_verts; -				total_submeshes[i] += cur_submeshes; +					//add this model to the lod total +					total_tris[lod] += cur_tris; +					total_verts[lod] += cur_verts; +					total_submeshes[lod] += cur_submeshes; -				//store this model's counts to asset data -				tris[i].push_back(cur_tris); -				verts[i].push_back(cur_verts); -				submeshes[i].push_back(cur_submeshes); +					//store this model's counts to asset data +					tris[lod].push_back(cur_tris); +					verts[lod].push_back(cur_verts); +					submeshes[lod].push_back(cur_submeshes); +				}  			}  		} -    } +	}  	if (mMaxTriangleLimit == 0)  	{ @@ -2598,48 +4480,37 @@ void LLModelPreview::updateStatusMessages()  		const LLVector4a scale(0.5f);  		for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)  		{ //for each model in the lod -			if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty()) +			if (mModel[lod][i]->mPhysics.mHull.empty())  			{ //no decomp exists  				S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();  				for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)  				{ //for each submesh (face), add triangles and vertices to current total -					LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); -					for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; ) +					const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); +					for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )  					{ -						U16 index_a = face.mIndices[k+0]; -						U16 index_b = face.mIndices[k+1]; -						U16 index_c = face.mIndices[k+2]; - -						LLVector4a v1; v1.setMul(face.mPositions[index_a], scale); -						LLVector4a v2; v2.setMul(face.mPositions[index_b], scale); -						LLVector4a v3; v3.setMul(face.mPositions[index_c], scale); +						LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale); +						LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale); +						LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);  						if (ll_is_degenerate(v1,v2,v3))  						{  							has_degenerate = true;  						} -						else -						{ -							k += 3; -						}  					}  				}  			}  		}  	} - +	  	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));  	std::string mesh_status_na = mFMP->getString("mesh_status_na");  	S32 upload_status[LLModel::LOD_HIGH+1]; -	mModelNoErrors = true; +	bool upload_ok = true; -	const U32 lod_high = LLModel::LOD_HIGH; -	U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); - -	for (S32 lod = 0; lod <= lod_high; ++lod) +	for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)  	{  		upload_status[lod] = 0; @@ -2652,7 +4523,7 @@ void LLModelPreview::updateStatusMessages()  		}  		else  		{ -			if (lod == lod_high) +			if (lod == LLModel::LOD_HIGH)  			{  				upload_status[lod] = 2;  				message = "mesh_status_missing_lod"; @@ -2673,6 +4544,8 @@ void LLModelPreview::updateStatusMessages()  			mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na);  		} +		const U32 lod_high = LLModel::LOD_HIGH; +  		if (lod != lod_high)  		{  			if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -2680,13 +4553,6 @@ void LLModelPreview::updateStatusMessages()  				message = "mesh_status_submesh_mismatch";  				upload_status[lod] = 2;  			} -			else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) -			{//number of submodels is different, not all faces are matched correctly. -				message = "mesh_status_submesh_mismatch"; -				upload_status[lod] = 2; -				// Note: Submodels in instance were loaded from higher LOD and as result face count -				// returns same value and total_submeshes[lod] is identical to high_lod one. -			}  			else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())  			{ //number of meshes is different  				message = "mesh_status_mesh_mismatch"; @@ -2707,7 +4573,7 @@ void LLModelPreview::updateStatusMessages()  				{  					//too many vertices in this lod  					message = "mesh_status_too_many_vertices"; -					upload_status[lod] = 1; +					upload_status[lod] = 2;  				}  			}  		} @@ -2719,7 +4585,7 @@ void LLModelPreview::updateStatusMessages()  		if (upload_status[lod] >= 2)  		{ -			mModelNoErrors = false; +			upload_ok = false;  		}  		if (lod == mPreviewLOD) @@ -2733,41 +4599,23 @@ void LLModelPreview::updateStatusMessages()  	} -	//warn if hulls have more than 256 points in them -	BOOL physExceededVertexLimit = FALSE; -	for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) +	//make sure no hulls have more than 256 points in them +	for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)  	{  		LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; -		if (mdl) +		for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)  		{ -			for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) +			if (mdl->mPhysics.mHull[j].size() > 256)  			{ -				if (mdl->mPhysics.mHull[j].size() > 256) -				{ -					physExceededVertexLimit = TRUE; -					LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; -					break; -				} +				upload_ok = false;  			}  		}  	} -	mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); -	LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon"); -	physStatusIcon->setVisible(physExceededVertexLimit); -	if (physExceededVertexLimit) -	{ -		mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded")); -		LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning"); -		physStatusIcon->setImage(img); -	} -	if (getLoadState() >= LLModelLoader::ERROR_PARSING) -	{ -		mModelNoErrors = false; -		LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; -	} +	bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; +	bool skinAndRigOk = true;  	bool uploadingSkin		     = mFMP->childGetValue("upload_skin").asBoolean();  	bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); @@ -2775,23 +4623,19 @@ void LLModelPreview::updateStatusMessages()  	{  		if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )  		{ -			mModelNoErrors = false; -			LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; -		} +			skinAndRigOk = false; +		}	  	} - -	if(mModelNoErrors && mModelLoader) +	 +	if(upload_ok && mModelLoader)  	{  		if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())  		{ -			// Some textures are still loading, prevent upload until they are done -			mModelNoErrors = false; +			upload_ok = false ;  		}  	} -	// Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics -	// current use of has_degenerate won't block upload permanently - later checks will restore the button -	if (!mModelNoErrors || has_degenerate) +	if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate)  	{  		mFMP->childDisable("ok_btn");  	} @@ -3133,8 +4977,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)  		LLModel* base_mdl = *base_iter;  		base_iter++; -		S32 num_faces = mdl->getNumVolumeFaces(); -		for (S32 i = 0; i < num_faces; ++i) +		for (S32 i = 0, e = mdl->getNumVolumeFaces(); i < e; ++i)  		{  			const LLVolumeFace &vf = mdl->getVolumeFace(i);  			U32 num_vertices = vf.mNumVertices; @@ -3229,14 +5072,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)  void LLModelPreview::update()  { -    if (mGenLOD) -	{ -		mGenLOD = false; -		genLODs(); -		refresh(); -		updateStatusMessages(); -	} -  	if (mDirty)  	{  		mDirty = false; @@ -3244,8 +5079,18 @@ void LLModelPreview::update()  		refresh();  		updateStatusMessages();  	} -} +	if (mGenLOD) +	{ +		if (!this->mHasBrokenModel) +		{ +			mGenLOD = false; +			genLODs(); +			refresh(); +			updateStatusMessages(); +		}		 +	} +}  //-----------------------------------------------------------------------------  // getTranslationForJointOffset()  //----------------------------------------------------------------------------- @@ -3279,79 +5124,10 @@ void LLModelPreview::createPreviewAvatar( void )  	}  	else  	{ -		LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; +		LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL;  	}  } -//static -U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) -{ -	U32 root_models = 0; -	model_list::iterator model_iter = models.begin(); -	while (model_iter != models.end()) -	{ -		LLModel* mdl = *model_iter; -		if (mdl && mdl->mSubmodelID == 0) -		{ -			root_models++; -		} -		model_iter++; -	} -	return root_models; -} - -void LLModelPreview::loadedCallback( -	LLModelLoader::scene& scene, -	LLModelLoader::model_list& model_list, -	S32 lod, -	void* opaque) -{ -	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); -	if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) -	{ -		pPreview->loadModelCallback(lod); -	}	 -} - -void LLModelPreview::stateChangedCallback(U32 state,void* opaque) -{ -	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); -	if (pPreview) -	{ -	 pPreview->setLoadState(state); -	} -} - -LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) -{ -	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); -	if (pPreview) -	{ -		return pPreview->getPreviewAvatar()->getJoint(str); -	} -	return NULL; -} - -U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque) -{ -	(void)opaque; - -	if (material.mDiffuseMapFilename.size()) -	{ -		material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; -		LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); - -		tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); -		tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); -		tex->forceToSaveRawImage(0, F32_MAX); -		material.setDiffuseMap(tex->getID()); // record tex ID -		return 1; -	} - -	material.mOpaqueData = NULL; -	return 0;	 -} -  void LLModelPreview::addEmptyFace( LLModel* pTarget )  {  	U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -3597,7 +5373,7 @@ BOOL LLModelPreview::render()  			}  			else  			{ -				LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; +				LL_INFOS(" ") << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL;  				regen = TRUE;  			}  		} @@ -3607,6 +5383,24 @@ BOOL LLModelPreview::render()  			genBuffers(mPreviewLOD, skin_weight);  		} +		//make sure material lists all match +		for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +		{ +			if (mBaseModel.size() == mModel[i].size()) +			{ +				for (U32 j = 0; j < mBaseModel.size(); ++j) +				{ +					int refFaceCnt = 0; +					int modelFaceCnt = 0; +										 +					if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) +					{ +						mFMP->childDisable( "calculate_btn" ); +					} +				} +			} +		} +  		if (!skin_weight)  		{  			for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) @@ -3615,63 +5409,66 @@ BOOL LLModelPreview::render()  				LLModel* model = instance.mLOD[mPreviewLOD]; -					if (!model) -					{ -						continue; -					} - -					gGL.pushMatrix(); -					LLMatrix4 mat = instance.mTransform; +				if (!model) +				{ +					continue; +				} -					gGL.multMatrix((GLfloat*) mat.mMatrix); +				gGL.pushMatrix(); +				LLMatrix4 mat; +				if (model->getName() != "BBOX") +				{ +					mat = instance.mTransform; +				} +				gGL.multMatrix((GLfloat*) mat.mMatrix); -					U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); -					for (U32 i = 0; i < num_models; ++i) -					{ -						LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; +				for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) +				{ +					LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; -						buffer->setBuffer(type_mask & buffer->getTypeMask()); +					buffer->setBuffer(type_mask & buffer->getTypeMask()); -						if (textures) +					if (textures) +					{ +						int materialCnt = instance.mModel->mMaterialList.size(); +						if ( i < materialCnt )  						{ -							int materialCnt = instance.mModel->mMaterialList.size(); -							if ( i < materialCnt ) -							{ -								const std::string& binding = instance.mModel->mMaterialList[i];						 -								const LLImportMaterial& material = instance.mMaterial[binding]; +							const std::string& binding = instance.mModel->mMaterialList[i];						 +							const LLImportMaterial& material = instance.mMaterial[binding]; -								gGL.diffuseColor4fv(material.mDiffuseColor.mV); +							gGL.diffuseColor4fv(material.mDiffuseColor.mV); -								// Find the tex for this material, bind it, and add it to our set -								// -								LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); -								if (tex) +							if (material.mDiffuseMap.notNull()) +							{ +								if (material.mDiffuseMap->getDiscardLevel() > -1)  								{ -									mTextureSet.insert(tex); +									gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); +									mTextureSet.insert(material.mDiffuseMap.get());  								}  							}  						} -						else -						{ -							gGL.diffuseColor4f(1,1,1,1); -						} +					} +					else +					{ +						gGL.diffuseColor4f(1,1,1,1); +					} -						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -						gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -						gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); +					buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +					gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); -						if (edges) -						{ -							glLineWidth(3.f); -							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -							glLineWidth(1.f); -						} +					if (edges) +					{ +						glLineWidth(3.f); +						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +						glLineWidth(1.f);  					} -					gGL.popMatrix();  				} +				gGL.popMatrix(); +			}  			if (physics)  			{ @@ -3699,100 +5496,98 @@ BOOL LLModelPreview::render()  						LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; -							if (!model) -							{ -								continue; -							} +						if (!model) +						{ +							continue; +						} -							gGL.pushMatrix(); -							LLMatrix4 mat = instance.mTransform; +						gGL.pushMatrix(); +						LLMatrix4 mat = instance.mTransform;  						gGL.multMatrix((GLfloat*) mat.mMatrix); -							bool render_mesh = true; +						bool render_mesh = true; -							LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; -							if (decomp) -							{ -								LLMutexLock(decomp->mMutex); +						LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; +						if (decomp) +						{ +							LLMutexLock(decomp->mMutex); -								LLModel::Decomposition& physics = model->mPhysics; +							LLModel::Decomposition& physics = model->mPhysics; -								if (!physics.mHull.empty()) -								{ -									render_mesh = false; +							if (!physics.mHull.empty()) +							{ +								render_mesh = false; -									if (physics.mMesh.empty()) -									{ //build vertex buffer for physics mesh -										gMeshRepo.buildPhysicsMesh(physics); -									} +								if (physics.mMesh.empty()) +								{ //build vertex buffer for physics mesh +									gMeshRepo.buildPhysicsMesh(physics); +								} -									if (!physics.mMesh.empty()) -									{ //render hull instead of mesh -										for (U32 i = 0; i < physics.mMesh.size(); ++i) +								if (!physics.mMesh.empty()) +								{ //render hull instead of mesh +									for (U32 i = 0; i < physics.mMesh.size(); ++i) +									{ +										if (explode > 0.f)  										{ -											if (explode > 0.f) -											{ -												gGL.pushMatrix(); +											gGL.pushMatrix(); -												LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; -												offset *= explode; +											LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; +											offset *= explode; -												gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); -											} +											gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); +										} -											static std::vector<LLColor4U> hull_colors; +										static std::vector<LLColor4U> hull_colors; -											if (i+1 >= hull_colors.size()) -											{ -												hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); -											} +										if (i+1 >= hull_colors.size()) +										{ +											hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); +										} -											gGL.diffuseColor4ubv(hull_colors[i].mV); -											LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); +										gGL.diffuseColor4ubv(hull_colors[i].mV); +										LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); -											if (explode > 0.f) -											{ -												gGL.popMatrix(); -											} +										if (explode > 0.f) +										{ +											gGL.popMatrix();  										}  									}  								}  							} -						 -							if (render_mesh) -							{ -								if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) -								{ -									genBuffers(LLModel::LOD_PHYSICS, false); -								} +						} -								U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); -								for (U32 i = 0; i < num_models; ++i) -								{ -									LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; +						if (render_mesh) +						{ +							if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) +							{ +								genBuffers(LLModel::LOD_PHYSICS, false); +							} +							for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) +							{ +								LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; -									gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -									gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); +								gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +								gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); -									buffer->setBuffer(type_mask & buffer->getTypeMask()); -									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +								buffer->setBuffer(type_mask & buffer->getTypeMask()); +								buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -									gGL.diffuseColor3f(1.f, 1.f, 0.f); +								gGL.diffuseColor3f(1.f, 1.f, 0.f); -									glLineWidth(2.f); -									glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +								glLineWidth(2.f); +								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +								buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -									glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -									glLineWidth(1.f); -								} +								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +								glLineWidth(1.f);  							} - -							gGL.popMatrix();  						} +						gGL.popMatrix(); +					} +  					glLineWidth(3.f);  					glPointSize(8.f);  					gPipeline.enableLightsFullbright(LLColor4::white); @@ -3972,20 +5767,20 @@ BOOL LLModelPreview::render()  								position[j] = v;  							} -							llassert(model->mMaterialList.size() > i);  +							llassert(model->mMaterialList.size() > i);  							const std::string& binding = instance.mModel->mMaterialList[i];  							const LLImportMaterial& material = instance.mMaterial[binding];  							buffer->setBuffer(type_mask & buffer->getTypeMask());  							gGL.diffuseColor4fv(material.mDiffuseColor.mV);  							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - -							// Find the tex for this material, bind it, and add it to our set -							// -							LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); -							if (tex) +							if (material.mDiffuseMap.notNull())  							{ -								mTextureSet.insert(tex); +								if (material.mDiffuseMap->getDiscardLevel() > -1) +								{ +									gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); +									mTextureSet.insert(material.mDiffuseMap.get()); +								}  							}  							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); @@ -4100,14 +5895,14 @@ void LLFloaterModelPreview::onReset(void* user_data)  	LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;  	fmp->childDisable("reset_btn");  	LLModelPreview* mp = fmp->mModelPreview; -	std::string filename = mp->mLODFile[LLModel::LOD_HIGH];  +	std::string filename = mp->mLODFile[3];   	fmp->resetDisplayOptions();  	//reset model preview  	fmp->initModelPreview();  	mp = fmp->mModelPreview; -	mp->loadModel(filename,LLModel::LOD_HIGH,true); +	mp->loadModel(filename,3,true);  }  //static @@ -4157,6 +5952,16 @@ void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)  {  	if (!mLODFrozen)  	{ +		S32 lod_mode = 0; +		LLCtrlSelectionInterface* iface = this->mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]); +		if (iface) +		{ +			lod_mode = iface->getFirstSelectedIndex(); +		} + +		if (lod_mode == 0 && this->mHasBrokenModel) +			return; +  		genLODs(lod, 3, enforce_tri_limit);  		refresh();  	} @@ -4201,7 +6006,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)  	}  	mUploadBtn->setVisible(!visible); -	mUploadBtn->setEnabled(isModelUploadAllowed()); +	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());  	if (visible)  	{ @@ -4267,7 +6072,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()  	childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));  	childSetVisible("upload_fee", true);  	childSetVisible("price_breakdown", true); -	mUploadBtn->setEnabled(isModelUploadAllowed()); +	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());  }  void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) @@ -4291,16 +6096,6 @@ void LLFloaterModelPreview::onModelUploadFailure()  	mUploadBtn->setEnabled(true);  } -bool LLFloaterModelPreview::isModelUploadAllowed() -{ -	bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty(); -	if (mModelPreview) -	{ -		allow_upload &= mModelPreview->mModelNoErrors; -	} -	return allow_upload; -} -  S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)  {  	if (mContinue) @@ -4350,8 +6145,8 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)  	// BAP HACK: handle "" for case that  MeshUploadFlag cap is broken.  	mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status)); -	// isModelUploadAllowed() includes mHasUploadPerm -	mUploadBtn->setEnabled(isModelUploadAllowed()); +	//mUploadBtn->setEnabled(mHasUploadPerm); +	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());  	getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);  	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);  } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 7a518c798b..813e49305b 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -37,8 +37,6 @@  #include "llviewermenufile.h"  #include "llfloatermodeluploadbase.h" -#include "lldaeloader.h" -  class LLComboBox;  class LLJoint;  class LLViewerJointMesh; @@ -47,18 +45,103 @@ class LLTextBox;  class LLVertexBuffer;  class LLModelPreview;  class LLFloaterModelPreview; -class DAE;  class daeElement;  class domProfile_COMMON;  class domInstance_geometry;  class domNode;  class domTranslate;  class domController; -class domSkin; -class domMesh;  class LLMenuButton;  class LLToggleableMenu; +typedef std::map<std::string, LLMatrix4> JointTransformMap; +typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt; + +const S32 NUM_LOD = 4; + +class LLModelLoader : public LLThread +{ +public: +	typedef enum +	{ +		STARTING = 0, +		READING_FILE, +		CREATING_FACES, +		GENERATING_VERTEX_BUFFERS, +		GENERATING_LOD, +		DONE, +		ERROR_PARSING, //basically loading failed +		ERROR_MATERIALS, +	} eLoadState; + +	U32 mState; +	std::string mFilename; +	S32 mLod; +	LLModelPreview* mPreview; +	LLMatrix4 mTransform; +	BOOL mFirstTransform; +	LLVector3 mExtents[2]; +	bool mTrySLM; +	 +	std::map<daeElement*, LLPointer<LLModel> > mModel; +	 +	typedef std::vector<LLPointer<LLModel> > model_list; +	model_list mModelList; + +	typedef std::vector<LLModelInstance> model_instance_list; +	 +	typedef std::map<LLMatrix4, model_instance_list > scene; + +	scene mScene; + +	typedef std::queue<LLPointer<LLModel> > model_queue; + +	//queue of models that need a physics rep +	model_queue mPhysicsQ; + +	LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,  +				   std::deque<std::string>& jointsFromNodes ); +	~LLModelLoader() ; + +	virtual void run(); +	bool doLoadModel(); +	bool loadFromSLM(const std::string& filename); +	void loadModelCallback(); + +	void loadTextures() ; //called in the main thread. +	void processElement(daeElement* element, bool& badElement); +	std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo); +	LLImportMaterial profileToMaterial(domProfile_COMMON* material); +	std::string getElementLabel(daeElement *element); +	LLColor4 getDaeColor(daeElement* element); +	 +	daeElement* getChildFromElement( daeElement* pElement, std::string const & name ); +	 +	bool isNodeAJoint( domNode* pNode ); +	void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms ); +	void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ); +	void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ); +	void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ); + +	void setLoadState(U32 state); + +	void buildJointToNodeMappingFromScene( daeElement* pRoot ); +	void processJointToNodeMapping( domNode* pNode ); +	void processChildJoints( domNode* pParentNode ); + +	//map of avatar joints as named in COLLADA assets to internal joint names +	std::map<std::string, std::string> mJointMap; +	JointTransformMap& mJointList;	 +	std::deque<std::string>& mJointsFromNode; + +	S32 mNumOfFetchingTextures ; //updated in the main thread +	bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. + +private: +	static std::list<LLModelLoader*> sActiveLoaderList; +	static bool isAlive(LLModelLoader* loader) ; +}; +  class LLFloaterModelPreview : public LLFloaterModelUploadBase  {  public: @@ -89,7 +172,6 @@ public:  	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);   	/*virtual*/ void onOpen(const LLSD& key); -	/*virtual*/ void onClose(bool app_quitting);  	static void onMouseCaptureLostModelPreview(LLMouseHandler*);  	static void setUploadAmount(S32 amount) { sUploadAmount = amount; } @@ -128,8 +210,6 @@ public:  	/*virtual*/ void onModelUploadFailure(); -	bool isModelUploadAllowed(); -  protected:  	friend class LLModelPreview;  	friend class LLMeshFilePicker; @@ -262,6 +342,7 @@ public:  	void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);  	void loadModelCallback(S32 lod);  	void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); +	void genModelBBox(); // Generate just a model BBox if we can't generate proper LOD  	void generateNormals();  	void restoreNormals();  	U32 calcResourceCost(); @@ -279,14 +360,21 @@ public:  	void setHasPivot( bool val ) { mHasPivot = val; }  	void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } +	//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) +	void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ); +	void critiqueJointToNodeMappingFromScene( void  );  	//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions  	//Accessors for joint position upload friendly rigs  	const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }  	void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } - +	bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); +	//Determines if a rig is a legacy from the joint list +	bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );	  	//Accessors for the legacy rigs  	const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } -	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }		 +	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }	 +	//Verify that a controller matches vertex counts +	bool verifyController( domController* pController );  	static void	textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); @@ -301,16 +389,6 @@ public:  	LLVector3 getTranslationForJointOffset( std::string joint ); -	static bool 		sIgnoreLoadedCallback; - -protected: - -	static void			loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); -	static void			stateChangedCallback(U32 state, void* opaque); - -	static LLJoint*	lookupJointByName(const std::string&, void* opaque); -	static U32			loadTextures(LLImportMaterial& material, void* opaque); -  private:  	//Utility function for controller vertex compare  	bool verifyCount( int expected, int result ); @@ -318,8 +396,6 @@ private:  	void		createPreviewAvatar( void );  	//Accessor for the dummy avatar  	LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } -	// Count amount of original models, excluding sub-models -	static U32 countRootModels(LLModelLoader::model_list models);   protected:  	friend class LLModelLoader; @@ -341,15 +417,14 @@ private:  	LLVector3	mPreviewTarget;  	LLVector3	mPreviewScale;  	S32			mPreviewLOD; -	S32			mPhysicsSearchLOD;  	U32			mResourceCost;  	std::string mLODFile[LLModel::NUM_LODS];  	bool		mLoading;  	U32			mLoadState;  	bool		mResetJoints;  	bool		mRigParityWithScene; -	bool		mModelNoErrors; - +	bool		mHasBrokenModel; +	  	std::map<std::string, bool> mViewOption;  	//GLOD object parameters (must rebuild object if these change) @@ -386,7 +461,7 @@ private:  	U32 mMaxTriangleLimit;  	LLMeshUploadThread::instance_list mUploadData; -	std::set<LLViewerFetchedTexture * > mTextureSet; +	std::set<LLViewerFetchedTexture* > mTextureSet;  	//map of vertex buffers to models (one vertex buffer in vector per face in model  	std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; @@ -405,9 +480,10 @@ private:  	bool		mLastJointUpdate; -	JointSet				mJointsFromNode; -	JointTransformMap	mJointTransformMap; - +	std::deque<std::string> mMasterJointList; +	std::deque<std::string> mMasterLegacyJointList; +	std::deque<std::string> mJointsFromNode; +	JointTransformMap		mJointTransformMap;  	LLPointer<LLVOAvatar>	mPreviewAvatar;  }; diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 042cf47070..04a818c2c0 100755 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -166,15 +166,59 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)  	xfer->setEnabled(copyable);  } -class LLFloaterPermsResponder : public LLHTTPClient::Responder +const int MAX_HTTP_RETRIES = 5; +LLFloaterPermsRequester* LLFloaterPermsRequester::sPermsRequester = NULL; + +LLFloaterPermsRequester::LLFloaterPermsRequester(const std::string url, const LLSD report,  +	int maxRetries) +	: mRetriesCount(0), mMaxRetries(maxRetries), mUrl(url), mReport(report) +{} + +//static  +void LLFloaterPermsRequester::init(const std::string url, const LLSD report, int maxRetries) +{ +	if (sPermsRequester == NULL) { +		sPermsRequester = new LLFloaterPermsRequester(url, report, maxRetries); +	} +} +     +//static +void LLFloaterPermsRequester::finalize() +{ +	if (sPermsRequester != NULL) +	{ +		delete sPermsRequester; +		sPermsRequester = NULL; +	} +} + +//static +LLFloaterPermsRequester* LLFloaterPermsRequester::instance() +{ +	return sPermsRequester; +} + +void LLFloaterPermsRequester::start()  { -public: -	LLFloaterPermsResponder(): LLHTTPClient::Responder() {} -private: -	static	std::string sPreviousReason; +	++mRetriesCount; +	LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder()); +} +     +bool LLFloaterPermsRequester::retry() +{ +	if (++mRetriesCount < mMaxRetries) +	{ +		LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder()); +		return true; +	} +	return false; +} -	void httpFailure() +void LLFloaterPermsResponder::httpFailure() +{ +	if (!LLFloaterPermsRequester::instance() || !LLFloaterPermsRequester::instance()->retry())  	{ +		LLFloaterPermsRequester::finalize();  		const std::string& reason = getReason();  		// Do not display the same error more than once in a row  		if (reason != sPreviousReason) @@ -185,27 +229,27 @@ private:  			LLNotificationsUtil::add("DefaultObjectPermissions", args);  		}  	} +} -	void httpSuccess() -	{ -		//const LLSD& content = getContent(); -		//dump_sequential_xml("perms_responder_result.xml", content); - -		// Since we have had a successful POST call be sure to display the next error message -		// even if it is the same as a previous one. -		sPreviousReason = ""; -		LLFloaterPermsDefault::setCapSent(true); -		LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; -	} -}; +void LLFloaterPermsResponder::httpSuccess() +{ +	//const LLSD& content = getContent(); +	//dump_sequential_xml("perms_responder_result.xml", content); -	std::string	LLFloaterPermsResponder::sPreviousReason; +	// Since we have had a successful POST call be sure to display the next error message +	// even if it is the same as a previous one. +	sPreviousReason = ""; +	LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; +} + +std::string	LLFloaterPermsResponder::sPreviousReason;  void LLFloaterPermsDefault::sendInitialPerms()  {  	if(!mCapSent)  	{  		updateCap(); +		setCapSent(true);  	}  } @@ -230,8 +274,8 @@ void LLFloaterPermsDefault::updateCap()              LLSDSerialize::toPrettyXML(report, sent_perms_log);              LL_CONT << sent_perms_log.str() << LL_ENDL;          } -     -		LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder()); +        LLFloaterPermsRequester::init(object_url, report, MAX_HTTP_RETRIES); +        LLFloaterPermsRequester::instance()->start();  	}      else      { diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index 2bb0a19dc1..d3b52c1fe5 100755 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -29,6 +29,7 @@  #define LL_LLFLOATERPERMPREFS_H  #include "llfloater.h" +#include "llhttpclient.h"  class LLFloaterPerms : public LLFloater  { @@ -89,4 +90,36 @@ private:  	bool mNextOwnerTransfer[CAT_LAST];  }; +class LLFloaterPermsRequester +{ +public: +	LLFloaterPermsRequester(const std::string url, const LLSD report, int maxRetries); + +	static void init(const std::string url, const LLSD report, int maxRetries); +	static void finalize(); +	static LLFloaterPermsRequester* instance(); + +	void start(); +	bool retry(); + +private: +	int mRetriesCount; +	int mMaxRetries; +	const std::string mUrl; +	const LLSD mReport; +public: +	static LLFloaterPermsRequester* sPermsRequester; +}; + +class LLFloaterPermsResponder : public LLHTTPClient::Responder +{ +public: +	LLFloaterPermsResponder() : LLHTTPClient::Responder() {} +private: +	static	std::string sPreviousReason; + +	void httpFailure(); +	void httpSuccess(); +}; +  #endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index ee4396758e..dac610eda1 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -49,6 +49,7 @@  //#include "llfirstuse.h"  #include "llfloaterreg.h"  #include "llfloaterabout.h" +#include "llfavoritesbar.h"  #include "llfloaterhardwaresettings.h"  #include "llfloatersidepanelcontainer.h"  #include "llfloaterimsession.h" @@ -1919,7 +1920,7 @@ BOOL LLPanelPreference::postBuild()  	}  	if (hasChild("favorites_on_login_check", TRUE))  	{ -		getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2)); +		getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2));  		bool show_favorites_at_login = LLPanelLogin::getShowFavorites();  		getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login);  	} @@ -2004,11 +2005,15 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v  	}  } -void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value) +void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value)  { -	if (checkbox && checkbox->getValue()) +	if (checkbox)  	{ -		LLNotificationsUtil::add("FavoritesOnLogin"); +		LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean()); +		if(checkbox->getValue()) +		{ +			LLNotificationsUtil::add("FavoritesOnLogin"); +		}  	}  } @@ -2235,6 +2240,11 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key)  void LLFloaterPreferenceProxy::onClose(bool app_quitting)  { +	if(app_quitting) +	{ +		cancel(); +	} +  	if (mSocksSettingsDirty)  	{ @@ -2334,6 +2344,11 @@ void LLFloaterPreferenceProxy::onBtnCancel()  	cancel();  } +void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting) +{ +	cancel(); +} +  void LLFloaterPreferenceProxy::cancel()  { @@ -2344,7 +2359,7 @@ void LLFloaterPreferenceProxy::cancel()  		LLSD ctrl_value = iter->second;  		control->set(ctrl_value);  	} - +	mSocksSettingsDirty = false;  	closeFloater();  } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 7bf6ae7d79..04e5e37731 100755 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -229,7 +229,7 @@ private:  	//for "Only friends and groups can call or IM me"  	static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&);  	//for "Show my Favorite Landmarks at Login" -	static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value); +	static void handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value);  	typedef std::map<std::string, LLColor4> string_color_map_t;  	string_color_map_t mSavedColors; @@ -269,6 +269,7 @@ protected:  	void saveSettings();  	void onBtnOk();  	void onBtnCancel(); +	void onClickCloseBtn(bool app_quitting = false);  	void onChangeSocksSettings(); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 2f4d2a93b2..99a5cf8002 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -35,6 +35,7 @@  #include "llassetstorage.h"  #include "llavatarnamecache.h"  #include "llcachename.h" +#include "llcheckboxctrl.h"  #include "llfontgl.h"  #include "llimagej2c.h"  #include "llinventory.h" @@ -137,6 +138,7 @@ BOOL LLFloaterReporter::postBuild()  	mOwnerName = LLStringUtil::null;  	getChild<LLUICtrl>("summary_edit")->setFocus(TRUE); +	getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE);  	mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString(); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 16fa4684ab..afec981d56 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -663,14 +663,20 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)  {  	LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;  	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; +	LLSnapshotLivePreview* previewp = getPreviewView(view); -	if (!view || !check_box) +	if (!view || !check_box || !previewp)  	{  		return;  	}  	gSavedSettings.setBOOL("UseFreezeFrame", check_box->get()); +	if (check_box->get()) +	{ +		previewp->prepareFreezeFrame(); +	} +  	updateLayout(view);  } diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index c1c21c593e..ae33acb842 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -141,6 +141,12 @@ BOOL LLFloaterTOS::postBuild()  		// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.  		// Store the URL separately and navigate here instead.  		web_browser->navigateTo( getString( "loading_url" ) ); +		LLPluginClassMedia* media_plugin = web_browser->getMediaPlugin(); +		if (media_plugin) +		{ +			// All links from tos_html should be opened in external browser +			media_plugin->setOverrideClickTarget("_external"); +		}  	}  	return TRUE; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 1b1c24b19a..ece3e10faa 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -284,12 +284,12 @@ BOOL LLFloaterWorldMap::postBuild()  	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");  	avatar_combo->selectFirstItem();  	avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); -	avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); +	avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );  	mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);  	LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");  	location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); -	location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this)); +	location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));  	getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));  	mListSearchResults = childGetListInterface("search_results"); @@ -297,7 +297,7 @@ BOOL LLFloaterWorldMap::postBuild()  	LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");  	landmark_combo->selectFirstItem();  	landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); -	landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); +	landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );  	mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);  	mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f); diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 44eda4d6c0..e9f80b795a 100755 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -109,6 +109,29 @@ bool LLFolderViewModelInventory::contentsReady()  	return !LLInventoryModelBackgroundFetch::instance().folderFetchActive();  } +bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder) +{ +	LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem()); +	LLUUID cat_id = modelp->getUUID(); +	if (cat_id.isNull()) +	{ +		return false; +	} +	LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); +	if (cat) +	{ +		// don't need to check version - descendents_server == -1 if we have no data +		S32 descendents_server = cat->getDescendentCount(); +		S32 descendents_actual = cat->getViewerDescendentCount(); +		if (descendents_server == descendents_actual +			|| (descendents_actual > 0 && descendents_server == -1)) // content was loaded in previous session +		{ +			return true; +		} +	} +	return false; +} +  void LLFolderViewModelItemInventory::requestSort()  {  	LLFolderViewModelItemCommon::requestSort(); diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 0516fc3b4b..dea54cbe57 100755 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -115,6 +115,7 @@ public:  	void sort(LLFolderViewFolder* folder);  	bool contentsReady(); +	bool isFolderComplete(LLFolderViewFolder* folder);  	bool startDrag(std::vector<LLFolderViewModelItem*>& items);  private: diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 86f9da6318..4d92fee04f 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -239,7 +239,8 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :  	mRoleMemberDataComplete(false),  	mGroupPropertiesDataComplete(false),  	mPendingRoleMemberRequest(false), -	mAccessTime(0.0f) +	mAccessTime(0.0f), +	mPendingBanRequest(false)  {  	mMemberVersion.generate();  } @@ -761,8 +762,69 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)  	mBanList.erase(ban_id);  } +void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid) +{ +	if (!mMemberDataComplete || +		!mRoleDataComplete || +		!(mRoleMemberDataComplete && mMembers.size())) +	{ +		LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL; +		mPendingBanRequest = true; +		mPendingBanMemberID = participant_uuid; + +		if (!mMemberDataComplete) +		{ +			LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); +		} + +		if (!mRoleDataComplete) +		{ +			LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID); +		} + +		return; +	} +	 +	LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid)); +	if (mi == mMembers.end()) +	{ +		if (!mPendingBanRequest) +		{ +			mPendingBanRequest = true; +			mPendingBanMemberID = participant_uuid; +			LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading +		} +		else +		{ +			mPendingBanRequest = false; +		} +		return; +	} +	mPendingBanRequest = false; + +	LLGroupMemberData* member_data = (*mi).second; +	if (member_data && member_data->isInRole(mOwnerRole)) +	{ +		return; // can't ban group owner +	} + +	std::vector<LLUUID> ids; +	ids.push_back(participant_uuid); + +	LLGroupBanData ban_data; +	createBanEntry(participant_uuid, ban_data); +	LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids); +	LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids); +	LLGroupMgr::getInstance()->sendGroupMembersRequest(mID); +	LLSD args; +	std::string name; +	gCacheName->getFullName(participant_uuid, name); +	args["AVATAR_NAME"] = name; +	args["GROUP_NAME"] = mName; +	LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); +}  //  // LLGroupMgr @@ -1245,6 +1307,11 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)  	group_datap->mChanged = TRUE;  	LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA); + +	if (group_datap->mPendingBanRequest) +	{ +		group_datap->banMemberById(group_datap->mPendingBanMemberID); +	}  }  // static @@ -1993,8 +2060,6 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content)  	LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);  } - -  // Responder class for capability group management  class GroupMemberDataResponder : public LLHTTPClient::Responder  { @@ -2083,11 +2148,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  		return;  	} -	// If we have no members, there's no reason to do anything else -	S32	num_members	= content["member_count"]; -	if(num_members < 1) -		return; -	  	LLUUID group_id = content["group_id"].asUUID();  	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); @@ -2097,6 +2157,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  		return;  	} +	// If we have no members, there's no reason to do anything else +	S32	num_members	= content["member_count"]; +	if (num_members < 1) +	{ +		LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL; +		// Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237 +		group_datap->mMemberDataComplete = true; +		group_datap->mChanged = TRUE; +		LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); +		return; +	} +	  	group_datap->mMemberCount = num_members;  	LLSD	member_list	= content["members"]; diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index 2e94e8d9a0..5307c4de92 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -149,7 +149,7 @@ public:  	const uuid_vec_t& getRoleMembers() const { return mMemberIDs; }  	S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE); -	S32 getTotalMembersInRole() { return mMemberIDs.size(); } +	S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225  	LLRoleData getRoleData() const { return mRoleData; }  	void setRoleData(LLRoleData data) { mRoleData = data; } @@ -269,8 +269,8 @@ public:  	void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData());  	void removeBanEntry(const LLUUID& ban_id); +	void banMemberById(const LLUUID& participant_uuid); -  public:  	typedef	std::map<LLUUID,LLGroupMemberData*> member_list_t;  	typedef	std::map<LLUUID,LLGroupRoleData*> role_list_t; @@ -302,6 +302,9 @@ public:  	S32					mMemberCount;  	S32					mRoleCount; +	bool				mPendingBanRequest; +	LLUUID				mPendingBanMemberID; +  protected:  	void sendRoleChanges();  	void cancelRoleChanges(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 605f71f412..a20540306b 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -121,7 +121,7 @@ bool isAddAction(const std::string& action)  bool isRemoveAction(const std::string& action)  { -	return ("take_off" == action || "detach" == action || "deactivate" == action); +	return ("take_off" == action || "detach" == action);  }  bool isMarketplaceCopyAction(const std::string& action) @@ -295,7 +295,11 @@ BOOL LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD      S32 option = LLNotificationsUtil::getSelectedOption(notification, response);      if (option == 0) // YES      { -        return perform_cutToClipboard(); +		const LLInventoryObject* obj = gInventory.getObject(mUUID); +		LLUUID parent_uuid = obj->getParentUUID(); +		BOOL result = perform_cutToClipboard(); +		gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, parent_uuid); +		return result;      }      return FALSE;  } @@ -915,15 +919,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,  		return;  	} -	// "Remove link" and "Delete" are the same operation. -	if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) -	{ -		items.push_back(std::string("Remove Link")); -	} -	else -	{ -		items.push_back(std::string("Delete")); -	} +	items.push_back(std::string("Delete"));  	if (!isItemRemovable())  	{ @@ -1810,7 +1806,9 @@ void LLItemBridge::restoreItem()  	if(item)  	{  		LLInventoryModel* model = getInventoryModel(); -		const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); +		bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT); + +		const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));  		// do not restamp on restore.  		LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);  	} @@ -2437,7 +2435,8 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const  BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  											BOOL drop,  											std::string& tooltip_msg, -                                            BOOL user_confirm) +											BOOL is_link, +											BOOL user_confirm)  {  	LLInventoryModel* model = getInventoryModel(); @@ -2483,6 +2482,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  		const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);  		const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);  		const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); +		const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);  		const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);  		//-------------------------------------------------------------------------------- @@ -2520,8 +2520,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  		}  		if (is_movable && move_is_into_outfit)  		{ +			if((mUUID == my_outifts_id) || (getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE)) +			{ +				is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); +			} +			else +			{ +				is_movable = false; +			} +		} +		if(is_movable && move_is_into_current_outfit && is_link) +		{  			is_movable = FALSE; -			// tooltip?  		}  		if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))  		{ @@ -2705,9 +2715,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  					}  				}  			} +  			// if target is current outfit folder we use link  			if (move_is_into_current_outfit && -				inv_cat->getPreferredType() == LLFolderType::FT_NONE) +				(inv_cat->getPreferredType() == LLFolderType::FT_NONE || +				inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))  			{  				// traverse category and add all contents to currently worn.  				BOOL append = true; @@ -4141,7 +4153,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,  				LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());  				if (linked_category)  				{ -					accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg); +					accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);  				}  			}  			else @@ -4561,7 +4573,7 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c      if (option == 0) // YES      {          std::string tooltip_msg; -        dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE); +		dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE, FALSE);      }  } @@ -5760,7 +5772,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action)  		gInventory.updateItem(item);  		gInventory.notifyObservers();  	} -	else if (isRemoveAction(action)) +	else if ("deactivate" == action || isRemoveAction(action))  	{  		LLGestureMgr::instance().deactivateGesture(mUUID); @@ -6382,12 +6394,8 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action  void LLWearableBridge::openItem()  { -	LLViewerInventoryItem* item = getItem(); - -	if (item) -	{ -		LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); -	} +	performAction(getInventoryModel(), +			      get_is_item_worn(mUUID) ? "take_off" : "wear");  }  void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 7e7cf9c7dd..03e19cc4da 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -274,7 +274,7 @@ public:  	{}  	BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); -	BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE); +	BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);      void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);      void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 990343c205..6aaf45c35d 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2473,7 +2473,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root  	{  		LLSD args;  		args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" :  "DeleteItem"); -		LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&onItemsRemovalConfirmation, _1, _2, root->getHandle())); +		LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));          // Note: marketplace listings will be updated in the callback if delete confirmed  		return;  	} diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 6ae8fd0f13..b93bf9a163 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -465,9 +465,9 @@ struct LLInventoryAction  	static void removeItemFromDND(LLFolderView* root);  private: -    static void buildMarketplaceFolders(LLFolderView* root); -    static void updateMarketplaceFolders(); -    static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed +	static void buildMarketplaceFolders(LLFolderView* root); +	static void updateMarketplaceFolders(); +	static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed  }; diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 4e9947fca0..46c1ffa789 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -515,7 +515,7 @@ void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)  			{  				LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);  				LLSculptParams new_params(*old_params); -				new_params.setSculptTexture(new_id); +				new_params.setSculptTexture(new_id, (*old_params).getSculptType());  				object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE);  			}  		} diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index cf04c5f7a5..8d21fda8f9 100755 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -862,14 +862,11 @@ void LLLocationInputCtrl::refreshParcelIcons()  		bool see_avs        = current_parcel->getSeeAVs();  		bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled(); -		bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID()); -		bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify()); -  		// Most icons are "block this ability"  		mParcelIcon[VOICE_ICON]->setVisible(   !allow_voice );  		mParcelIcon[FLY_ICON]->setVisible(     !allow_fly );  		mParcelIcon[PUSH_ICON]->setVisible(    !allow_push ); -		mParcelIcon[BUILD_ICON]->setVisible(   !allow_build && !is_parcel_owner && !allow_group_modify ); +		mParcelIcon[BUILD_ICON]->setVisible(   !allow_build );  		mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );  		mParcelIcon[DAMAGE_ICON]->setVisible(  allow_damage );  		mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 7ddacf3033..4116e38f11 100755 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -804,6 +804,22 @@ bool LLLogChat::isNearbyTranscriptExist()  	return false;  } +bool LLLogChat::isAdHocTranscriptExist(std::string file_name) +{ +	std::vector<std::string> list_of_transcriptions; +	LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); + +	file_name = makeLogFileName(file_name); +	BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) +	{ +	   	if (transcript_file_name == file_name) +	   	{ +	   		return true; +		} +	} +	return false; +} +  //*TODO mark object's names in a special way so that they will be distinguishable form avatar name   //which are more strict by its nature (only firstname and secondname)  //Example, an object's name can be written like "Object <actual_object's_name>" diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index ca597599dd..6022e539a9 100755 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -120,6 +120,7 @@ public:  	static void deleteTranscripts();  	static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);  	static bool isNearbyTranscriptExist(); +	static bool isAdHocTranscriptExist(std::string file_name);  	static bool historyThreadsFinished(LLUUID session_id);  	static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 407613d32c..85faa70552 100755 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -1677,12 +1677,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)  				F32 alpha = (1.f - (1.f *  ((F32)llabs(i) / (F32)num_ticks_per_side1)));  				LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1); -				F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - -				if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) +				//No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) +				//F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); +				/*if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)  				{  					continue; -				} +				}*/  				F32 tick_scale = 1.f;  				for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) @@ -1710,12 +1710,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)  				F32 alpha = (1.f - (1.f *  ((F32)llabs(i) / (F32)num_ticks_per_side2)));  				LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2); -				F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - -				if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) +				//No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) +				//F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); +				/*if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)  				{  					continue; -				} +				}*/  				F32 tick_scale = 1.f;  				for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 394db71fb9..b4259a456c 100755 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1285,12 +1285,12 @@ void LLManipTranslate::renderSnapGuides()  				{  					tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit)); -					F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()); - -					if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f) +					//No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208) +					//F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()); +					/*if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)  					{  						continue; -					} +					}*/  					// add in off-axis offset  					tick_start += (mSnapOffsetAxis * mSnapOffsetMeters); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b96bdd73ff..73faed7ef5 100755 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -95,6 +95,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  	mStretchToFill( true ),  	mMaintainAspectRatio ( true ),  	mDecoupleTextureSize ( false ), +	mUpdateScrolls( false ),  	mTextureWidth ( 1024 ),  	mTextureHeight ( 1024 ),  	mClearCache(false), @@ -682,7 +683,13 @@ bool LLMediaCtrl::ensureMediaSourceExists()  			mMediaSource->addObserver( this );  			mMediaSource->setBackgroundColor( getBackgroundColor() );  			mMediaSource->setTrustedBrowser(mTrusted); -			mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); + +			F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; +			if (scale_factor != mMediaSource->getPageZoomFactor()) +			{ +				mMediaSource->setPageZoomFactor( scale_factor ); +				mUpdateScrolls = true; +			}  			if(mClearCache)  			{ @@ -720,10 +727,11 @@ void LLMediaCtrl::draw()  {  	F32 alpha = getDrawContext().mAlpha; -	if ( gRestoreGL == 1 ) +	if ( gRestoreGL == 1 || mUpdateScrolls)  	{  		LLRect r = getRect();  		reshape( r.getWidth(), r.getHeight(), FALSE ); +		mUpdateScrolls = false;  		return;  	} @@ -765,7 +773,12 @@ void LLMediaCtrl::draw()  	{  		gGL.pushUIMatrix();  		{ -			mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); +			F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; +			if (scale_factor != mMediaSource->getPageZoomFactor()) +			{ +				mMediaSource->setPageZoomFactor( scale_factor ); +				mUpdateScrolls = true; +			}  			// scale texture to fit the space using texture coords  			gGL.getTexUnit(0)->bind(media_texture); @@ -970,11 +983,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  		case MEDIA_EVENT_CLICK_LINK_HREF:  		{ -			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;  			// retrieve the event parameters  			std::string url = self->getClickURL(); -			std::string target = self->getClickTarget(); +			std::string target = self->isOverrideClickTarget() ? self->getOverrideClickTarget() : self->getClickTarget();  			std::string uuid = self->getClickUUID(); +			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL;  			LLNotification::Params notify_params;  			notify_params.name = "PopupAttempt"; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 785c57b78a..988733b85a 100755 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -192,7 +192,8 @@ public:  				mHidingInitialLoad,  				mClearCache,  				mHoverTextChanged, -				mDecoupleTextureSize; +				mDecoupleTextureSize, +				mUpdateScrolls;  		std::string mHomePageUrl,  					mHomePageMimeType, diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index fe562baf96..70035bcc74 100755 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -303,7 +303,15 @@ void LLFloaterMove::onFlyButtonClick()  void LLFloaterMove::setMovementMode(const EMovementMode mode)  {  	mCurrentMode = mode; -	gAgent.setFlying(MM_FLY == mode); + +	if(MM_FLY == mode) +	{ +		LLAgent::toggleFlying(); +	} +	else +	{ +		gAgent.setFlying(FALSE); +	}  	// attempts to set avatar flying can not set it real flying in some cases.  	// For ex. when avatar fell down & is standing up. diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 79988a0800..5510598ae7 100755 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -130,8 +130,14 @@ BOOL LLNameListCtrl::handleDragAndDrop(  	return handled;  } -void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group) +void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience)  { +	if(is_experience) +	{ +		LLFloaterReg::showInstance("experience_profile", avatar_id, true); +		return; +	} +  	if (is_group)  		LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id));  	else @@ -230,10 +236,11 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)  				// Should we show a group or an avatar inspector?  				bool is_group = hit_item->isGroup(); +				bool is_experience = hit_item->isExperience();  				LLToolTip::Params params;  				params.background_visible( false ); -				params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) ); +				params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience) );  				params.delay_time(0.0f);		// spawn instantly on hover  				params.image( icon );  				params.message(""); @@ -295,7 +302,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(  	const std::string& prefix)  {  	LLUUID id = name_item.value().asUUID(); -	LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP); +	LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP, name_item.target() == EXPERIENCE);  	if (!item) return NULL; @@ -353,6 +360,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(  			}  			break;  		} +	case EXPERIENCE: +		// just use supplied name  	default:  		break;  	} diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 515962df7d..19ce3c7aed 100755 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -44,22 +44,30 @@ class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameLi  public:  	bool isGroup() const { return mIsGroup; }  	void setIsGroup(bool is_group) { mIsGroup = is_group; } +	bool isExperience() const { return mIsExperience; } +	void setIsExperience(bool is_experience) { mIsExperience = is_experience; }  protected:  	friend class LLNameListCtrl;  	LLNameListItem( const LLScrollListItem::Params& p ) -	:	LLScrollListItem(p), mIsGroup(false) +	:	LLScrollListItem(p), mIsGroup(false), mIsExperience(false)  	{  	}  	LLNameListItem( const LLScrollListItem::Params& p, bool is_group ) -	:	LLScrollListItem(p), mIsGroup(is_group) +	:	LLScrollListItem(p), mIsGroup(is_group), mIsExperience(false) +	{ +	} + +	LLNameListItem( const LLScrollListItem::Params& p, bool is_group, bool is_experience ) +	:	LLScrollListItem(p), mIsGroup(is_group), mIsExperience(is_experience)  	{  	}  private:  	bool mIsGroup; +	bool mIsExperience;  }; @@ -73,7 +81,8 @@ public:  	{  		INDIVIDUAL,  		GROUP, -		SPECIAL +		SPECIAL, +		EXPERIENCE  	} ENameType;  	// provide names for enums @@ -160,7 +169,7 @@ public:  	/*virtual*/ void mouseOverHighlightNthItem( S32 index );  private: -	void showInspector(const LLUUID& avatar_id, bool is_group); +	void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false);  	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, LLHandle<LLNameListItem> item);  private: diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 9bd6007772..b7e1b2d3a4 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1168,6 +1168,8 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO          targetPanel->setVisible(show);          toggleTypeSpecificControls(type); +		// Update type controls here +		updateTypeSpecificControls(type);          if (show)          { @@ -1179,7 +1181,6 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO                  mNameEditor->setText(mWearableItem->getName());                  updatePanelPickerControls(type); -                updateTypeSpecificControls(type);                  // clear and rebuild visual param list                  U8 num_subparts = wearable_entry->mSubparts.size(); diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp index fc4ee9862e..7c07301762 100644 --- a/indra/newview/llpanelexperiencelisteditor.cpp +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -33,6 +33,7 @@  #include "llfloaterexperiencepicker.h"  #include "llfloaterreg.h"  #include "llhandle.h" +#include "llnamelistctrl.h"  #include "llscrolllistctrl.h"  #include "llviewerregion.h"  #include "llagent.h" @@ -54,7 +55,7 @@ LLPanelExperienceListEditor::LLPanelExperienceListEditor()  BOOL LLPanelExperienceListEditor::postBuild()  { -	mItems = getChild<LLScrollListCtrl>("experience_list"); +	mItems = getChild<LLNameListCtrl>("experience_list");  	mAdd = getChild<LLButton>("btn_add");  	mRemove = getChild<LLButton>("btn_remove");  	mProfile = getChild<LLButton>("btn_profile"); @@ -178,12 +179,13 @@ void LLPanelExperienceListEditor::onItems()  	{  		const LLUUID& experience = *it;  		item["id"]=experience; +		item["target"] = LLNameListCtrl::EXPERIENCE;  		LLSD& columns = item["columns"];  		columns[0]["column"] = "experience_name";  		columns[0]["value"] = getString("loading");  		mItems->addElement(item); -		LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,  +		LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,  			getDerivedHandle<LLPanelExperienceListEditor>(), _1));  	} diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h index f69f0509be..bc9867752d 100644 --- a/indra/newview/llpanelexperiencelisteditor.h +++ b/indra/newview/llpanelexperiencelisteditor.h @@ -31,6 +31,7 @@  #include "lluuid.h"  #include <set> +class LLNameListCtrl;  class LLScrollListCtrl;  class LLButton;  class LLFloaterExperiencePicker; @@ -82,7 +83,7 @@ private:  	uuid_list_t mExperienceIds; -	LLScrollListCtrl*			mItems; +	LLNameListCtrl*				mItems;  	filter_list					mFilters;  	LLButton*					mAdd;  	LLButton*					mRemove; diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp index df03ef7526..30576a8d67 100644 --- a/indra/newview/llpanelexperiencelog.cpp +++ b/indra/newview/llpanelexperiencelog.cpp @@ -54,7 +54,6 @@ LLPanelExperienceLog::LLPanelExperienceLog(  )  	buildFromFile("panel_experience_log.xml");  } -  BOOL LLPanelExperienceLog::postBuild( void )  {  	LLExperienceLog* log = LLExperienceLog::getInstance(); @@ -112,7 +111,7 @@ void LLPanelExperienceLog::refresh()  	int itemsToSkip = mPageSize*mCurrentPage;  	int items = 0;  	bool moreItems = false; -	 +	LLSD events_to_save = events;  	if (!events.emptyMap())  	{  		LLSD::map_const_iterator day = events.endMap(); @@ -120,6 +119,13 @@ void LLPanelExperienceLog::refresh()  		{  			--day;  			const LLSD& dayArray = day->second; + +			std::string date = day->first; +			if(!LLExperienceLog::instance().isNotExpired(date)) +			{ +				events_to_save.erase(day->first); +				continue; +			}  			int size = dayArray.size();  			if(itemsToSkip > size)  			{ @@ -164,6 +170,7 @@ void LLPanelExperienceLog::refresh()  			}  		} while (day != events.beginMap());  	} +	LLExperienceLog::getInstance()->setEventsToSave(events_to_save);  	if(waiting)  	{  		mEventList->deleteAllItems(); @@ -237,12 +244,8 @@ void LLPanelExperienceLog::notifyChanged()  void LLPanelExperienceLog::logSizeChanged()  {  	int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get()); -	bool dirty = value > 0 && value < LLExperienceLog::instance().getMaxDays();  	LLExperienceLog::instance().setMaxDays(value); -	if(dirty) -	{ -		refresh(); -	} +	refresh();  }  void LLPanelExperienceLog::onSelectionChanged() diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index 70d826a407..43dc7569a4 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -42,6 +42,7 @@  #include "llviewercontrol.h"  #include "llfloater.h"  #include "lltrans.h" +#include <boost/regex.hpp>  #define BTN_FIND		"find"  #define BTN_OK			"ok_btn" @@ -147,6 +148,46 @@ void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* u  void LLPanelExperiencePicker::onBtnFind()  {  	mCurrentPage=1; +	boost::cmatch what; +	std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString(); +	const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); +	if (boost::regex_match(text.c_str(), what, expression)) +	{ +		LLURI uri(text); +		LLSD path_array = uri.pathArray(); +		if (path_array.size() == 4) +		{ +			std::string exp_id = path_array.get(2).asString(); +			LLUUID experience_id(exp_id); +			if (!experience_id.isNull()) +			{ +				const LLSD& experience_details = LLExperienceCache::get(experience_id); +				if(!experience_details.isUndefined()) +				{ +					std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); +					if(!experience_name_string.empty()) +					{ +						getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string); +					} +				} +				else +				{ +					getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems(); +					getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching")); + +					getChildView(BTN_OK)->setEnabled(FALSE); +					getChildView(BTN_PROFILE)->setEnabled(FALSE); + +					getChildView(BTN_RIGHT)->setEnabled(FALSE); +					getChildView(BTN_LEFT)->setEnabled(FALSE); +					LLExperienceCache::get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); +					return; +				} +			} +		} +	} + +  	find();  } @@ -183,7 +224,6 @@ void LLPanelExperiencePicker::find()  	getChildView(BTN_LEFT)->setEnabled(FALSE);  } -  bool LLPanelExperiencePicker::isSelectButtonEnabled()  {  	LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 9823e84cd9..d7e89b4832 100755 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -307,7 +307,7 @@ private:  						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);  					} -					object->setTEMaterialParams(face, new_material); +					object->setTEMaterialParams(face, new_material, TRUE);  					return new_material;  				}  				return NULL; diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index f67a90fd01..342b57ba4a 100755 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -338,7 +338,7 @@ void LLPanelGroup::update(LLGroupChange gc)  		group_name_ctrl->setToolTip(group_name);  		LLGroupData agent_gdatap; -		bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); +		bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();  		bool join_btn_visible = !is_member && gdatap->mOpenEnrollment;  		mButtonJoin->setVisible(join_btn_visible); @@ -470,7 +470,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)  		}  		LLGroupData agent_gdatap; -		bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); +		bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();  		tab_roles->setVisible(is_member);  		tab_notices->setVisible(is_member); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 7ffaa05919..b2164c1f21 100755 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -287,11 +287,6 @@ void LLPanelGroupGeneral::activate()  	{  		LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID);  		LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); -		 -		if (!gdatap || !gdatap->isMemberDataComplete() ) -		{ -			LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); -		}  		mFirstUse = FALSE;  	} diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index e662a05dfc..866cb8dbef 100755 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -243,56 +243,59 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)  	LLGroupMgrGroupData::member_list_t::iterator agent_iter =  		gdatap->mMembers.find(gAgent.getID()); +	//loop over the agent's roles in the group +	//then add those roles to the list of roles that the agent +	//can invite people to be. +	//if the user is the owner then we add +	//all of the roles in the group, +	//else if they have the add to roles power +	//we add every role but owner, +	//else if they have the limited add to roles power +	//we add every role the user is in, +	//else we just add to everyone +	bool is_owner = FALSE; +	bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, +												 GP_ROLE_ASSIGN_MEMBER); +	bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, +													 GP_ROLE_ASSIGN_MEMBER_LIMITED); +	LLGroupMemberData* member_data = NULL;  	//get the member data for the agent if it exists -	if ( agent_iter != gdatap->mMembers.end() ) +	if (agent_iter != gdatap->mMembers.end())  	{ -		LLGroupMemberData* member_data = (*agent_iter).second; - -		//loop over the agent's roles in the group -		//then add those roles to the list of roles that the agent -		//can invite people to be -		if ( member_data && mRoleNames) +		member_data = (*agent_iter).second; +		if (member_data && mRoleNames)  		{ -			//if the user is the owner then we add -			//all of the roles in the group -			//else if they have the add to roles power -			//we add every role but owner, -			//else if they have the limited add to roles power -			//we add every role the user is in -			//else we just add to everyone -			bool is_owner   = member_data->isOwner(); -			bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, -												 GP_ROLE_ASSIGN_MEMBER); -			bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, -												 GP_ROLE_ASSIGN_MEMBER_LIMITED); +			is_owner = member_data->isOwner(); +		}//end if member data is not null +	}//end if agent is in the group + -			LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin(); -			LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); -			//populate the role list -			for ( ; rit != end; ++rit) +	LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin(); +	LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); + +	//populate the role list: +	for ( ; rit != end; ++rit) +	{ +		LLUUID role_id = (*rit).first; +		LLRoleData rd; +		if ( gdatap->getRoleData(role_id,rd) ) +		{ +			// Owners can add any role. +			if ( is_owner  +				// Even 'can_assign_any' can't add owner role. +				|| (can_assign_any && role_id != gdatap->mOwnerRole) +				// Add all roles user is in +				|| (can_assign_limited && member_data && member_data->isInRole(role_id)) +				// Everyone role. +				|| role_id == LLUUID::null )  			{ -				LLUUID role_id = (*rit).first; -				LLRoleData rd; -				if ( gdatap->getRoleData(role_id,rd) ) -				{ -					// Owners can add any role. -					if ( is_owner  -						// Even 'can_assign_any' can't add owner role. -						 || (can_assign_any && role_id != gdatap->mOwnerRole) -						// Add all roles user is in -						 || (can_assign_limited && member_data->isInRole(role_id)) -						// Everyone role. -						 || role_id == LLUUID::null ) -					{ -							mRoleNames->add(rd.mRoleName, -											role_id, -											ADD_BOTTOM); -					} -				} +				mRoleNames->add(rd.mRoleName, +								role_id, +								ADD_BOTTOM);  			} -		}//end if member data is not null -	}//end if agent is in the group +		} +	}  }  //static @@ -579,7 +582,8 @@ void LLPanelGroupInvite::updateLists()  		{  			waiting = true;  		} -		if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())  +		if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() +			&& (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them  		{  			if ( mImplementation->mRoleNames )  			{ diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index c3a10b3fa0..00c204e702 100755 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -350,12 +350,10 @@ void LLPanelGroupRoles::update(LLGroupChange gc)  void LLPanelGroupRoles::activate()  { +	if (!gAgent.isInGroup(mGroupID)) return; +  	// Start requesting member and role data if needed.  	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); -	if (!gdatap || !gdatap->isMemberDataComplete() ) -	{ -		LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); -	}  	if (!gdatap || !gdatap->isRoleDataComplete() )  	{ @@ -364,13 +362,7 @@ void LLPanelGroupRoles::activate()  		LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);  	} - -	// Check role-member mapping data. -	if (!gdatap || !gdatap->isRoleMemberDataComplete() ) -	{ -		LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); -	} - +	  	// Need this to get base group member powers  	if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )  	{ @@ -1163,7 +1155,37 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)  	if ( selfp )  	{ -		selfp->handleEjectMembers(); +		selfp->confirmEjectMembers(); +	} +} + +void LLPanelGroupMembersSubTab::confirmEjectMembers() +{ +	std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); +	if (selection.empty()) return; + +	S32 selection_count = selection.size(); +	if (selection_count == 1) +	{ +		LLSD args; +		std::string fullname; +		gCacheName->getFullName(mMembersList->getValue(), fullname); +		args["AVATAR_NAME"] = fullname; +		LLSD payload; +		LLNotificationsUtil::add("EjectGroupMemberWarning", +				 	 	 	 	 args, +								 payload, +								 boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); +	} +	else +	{ +		LLSD args; +		args["COUNT"] = llformat("%d", selection_count); +		LLSD payload; +		LLNotificationsUtil::add("EjectGroupMembersWarning", +				 	 	 	 	 args, +								 payload, +								 boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));  	}  } @@ -1190,6 +1212,16 @@ void LLPanelGroupMembersSubTab::handleEjectMembers()  	LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);  } +bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	if (0 == option) // Eject button +	{ +		handleEjectMembers(); +	} +	return false; +} +  void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)  {  	LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); @@ -1327,15 +1359,26 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick()  void LLPanelGroupMembersSubTab::activate()  { +	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); +  	LLPanelGroupSubTab::activate();  	if(!mActivated)  	{ +		if (!gdatap || !gdatap->isMemberDataComplete()) +		{ +			LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); +		} + +		if (!gdatap || !gdatap->isRoleMemberDataComplete()) +		{ +			LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); +		} +  		update(GC_ALL);  		mActivated = true;  	}  	else  	{ -		LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);  		// Members can be removed outside of this tab, checking changes  		if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount()))  		{ @@ -1636,7 +1679,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)  	{  		// Build a string with info on retrieval progress.  		std::ostringstream retrieved; -		if ( !gdatap->isMemberDataComplete() ) + +		if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() ) +		{ +			// MAINT-5237 +			retrieved << "Member list not available."; +		} +		else if ( !gdatap->isMemberDataComplete() )  		{  			// Still busy retreiving member list.  			retrieved << "Retrieving member list (" << gdatap->mMembers.size() @@ -1783,7 +1832,7 @@ void LLPanelGroupMembersSubTab::updateMembers()  		{  			mMembersList->setEnabled(TRUE);  		} -		else +		else if (gdatap->mMembers.size())   		{  			mMembersList->setEnabled(FALSE);  			mMembersList->setCommentText(std::string("No match.")); @@ -1801,7 +1850,47 @@ void LLPanelGroupMembersSubTab::updateMembers()  void LLPanelGroupMembersSubTab::onBanMember(void* user_data)  {  	LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data); -	self->handleBanMember(); +	self->confirmBanMembers(); +} + +void LLPanelGroupMembersSubTab::confirmBanMembers() +{ +	std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); +	if (selection.empty()) return; + +	S32 selection_count = selection.size(); +	if (selection_count == 1) +	{ +		LLSD args; +		std::string fullname; +		gCacheName->getFullName(mMembersList->getValue(), fullname); +		args["AVATAR_NAME"] = fullname; +		LLSD payload; +		LLNotificationsUtil::add("BanGroupMemberWarning", +				 	 	 	 	 args, +								 payload, +								 boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2)); +	} +	else +	{ +		LLSD args; +		args["COUNT"] = llformat("%d", selection_count); +		LLSD payload; +		LLNotificationsUtil::add("BanGroupMembersWarning", +				 	 	 	 	 args, +								 payload, +								 boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2)); +	} +} + +bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	if (0 == option) // Eject button +	{ +		handleBanMember(); +	} +	return false;  }  void LLPanelGroupMembersSubTab::handleBanMember() @@ -2111,20 +2200,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)  			mDeleteRoleButton->setEnabled(FALSE);  		}  	} - -	if(!mFirstOpen) -	{ -		if (!gdatap || !gdatap->isMemberDataComplete()) -		{ -			LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); -		} - -		if (!gdatap || !gdatap->isRoleMemberDataComplete()) -		{ -			LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); -		} -	} - +	  	if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)  	    && gdatap  	    && gdatap->isMemberDataComplete() diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 540b24ada6..9a696124a8 100755 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -171,6 +171,7 @@ public:  	void handleEjectMembers();  	void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members);  	bool handleEjectCallback(const LLSD& notification, const LLSD& response); +	void confirmEjectMembers();  	static void onRoleCheck(LLUICtrl* check, void* user_data);  	void handleRoleCheck(const LLUUID& role_id, @@ -178,6 +179,8 @@ public:  	static void onBanMember(void* user_data);  	void handleBanMember(); +	bool handleBanCallback(const LLSD& notification, const LLSD& response); +	void confirmBanMembers();  	void applyMemberChanges(); diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index d4894d4a42..06bb886ae8 100755 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -147,6 +147,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)  				}  				else  				{ +					LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos);  					region_name = desc;  				} diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 7aaf9510eb..4229419fce 100755 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -604,7 +604,7 @@ void LLPanelMainInventory::updateItemcountText()  	}  	else  	{ -		text = getString("ItemcountUnknown"); +		text = getString("ItemcountUnknown", string_args);  	}      mCounterCtrl->setValue(text); diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index 2856ea9db1..d7c43c224c 100755 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -319,6 +319,10 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media  // Helper to set media control to media URL as required  void LLPanelMediaSettingsGeneral::updateMediaPreview()  { +	if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString()) +	{ +		return; +	}  	if ( mHomeURL->getValue().asString().length() > 0 )  	{  		if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString()) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index dcd0aab3ab..5dd44b4444 100755 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1739,9 +1739,10 @@ void LLPanelObject::sendSculpt()  		return;  	LLSculptParams sculpt_params; +	LLUUID sculpt_id = LLUUID::null;  	if (mCtrlSculptTexture) -		sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); +		sculpt_id = mCtrlSculptTexture->getImageAssetID();  	U8 sculpt_type = 0; @@ -1765,7 +1766,7 @@ void LLPanelObject::sendSculpt()  	if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))  		sculpt_type |= LL_SCULPT_FLAG_INVERT; -	sculpt_params.setSculptType(sculpt_type); +	sculpt_params.setSculptTexture(sculpt_id, sculpt_type);  	mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);  } @@ -2000,7 +2001,11 @@ void LLPanelObject::onCancelSculpt(const LLSD& data)  	LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");  	if(!mTextureCtrl)  		return; -	 + +	if(mSculptTextureRevert == LLUUID::null) +	{ +		mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE); +	}  	mTextureCtrl->setImageAssetID(mSculptTextureRevert);  	sendSculpt(); diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 496168229d..01a22df9e1 100755 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1059,6 +1059,9 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)  		case LLAssetType::AT_BODYPART:  			applyListViewFilter(LVIT_BODYPART);  			break; +		case LLAssetType::AT_GESTURE: +			applyListViewFilter(LVIT_GESTURES); +			break;  		case LLAssetType::AT_CLOTHING:  		default:  			applyListViewFilter(LVIT_CLOTHING); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 30870daf40..841bb4337a 100755 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -80,6 +80,7 @@ public:  	{  		LVIT_ALL = 0,  		LVIT_CLOTHING, +		LVIT_GESTURES,  		LVIT_BODYPART,  		LVIT_ATTACHMENT,  		LVIT_SHAPE, diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 5977d558d3..6b86459d8f 100755 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -85,6 +85,8 @@ static const std::string RECENT_TAB_NAME	= "recent_panel";  static const std::string BLOCKED_TAB_NAME	= "blocked_panel"; // blocked avatars  static const std::string COLLAPSED_BY_USER  = "collapsed_by_user"; +const S32 BASE_MAX_AGENT_GROUPS = 42; +const S32 PREMIUM_MAX_AGENT_GROUPS = 60;  extern S32 gMaxAgentGroups; @@ -585,6 +587,7 @@ BOOL LLPanelPeople::postBuild()  	getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));  	getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));  	getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); +	getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this));  	mTabContainer = getChild<LLTabContainer>("tabs");  	mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); @@ -902,8 +905,11 @@ void LLPanelPeople::updateButtons()  		LLPanel* groups_panel = mTabContainer->getCurrentPanel();  		groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected -		groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size())); -		groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d",(gMaxAgentGroups-gAgent.mGroups.size()))); + +		U32 groups_count = gAgent.mGroups.size(); +		U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0; +		groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count)); +		groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining));  	}  	else  	{ @@ -1114,6 +1120,14 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)  	}  } +void LLPanelPeople::onGroupLimitInfo() +{ +	LLSD args; +	args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS; +	args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS; +	LLNotificationsUtil::add("GroupLimitInfo", args); +} +  void LLPanelPeople::onTabSelected(const LLSD& param)  {  	std::string tab_name = getChild<LLPanel>(param.asString())->getName(); @@ -1312,8 +1326,12 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ -		mAllFriendList->toggleIcons(); -		mOnlineFriendList->toggleIcons(); +		std::string param = mAllFriendList->getIconParamName(); +		gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		gSavedSettings.setBOOL(mOnlineFriendList->getIconParamName(), gSavedSettings.getBOOL(param)); +		mAllFriendList->setIconsVisible(gSavedSettings.getBOOL(param)); +		mOnlineFriendList->setIconsVisible(gSavedSettings.getBOOL(param));  	}  	else if (chosen_item == "view_permissions")  	{ @@ -1349,7 +1367,10 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ -		mNearbyList->toggleIcons(); +		std::string param = mNearbyList->getIconParamName(); +		gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		mNearbyList->setIconsVisible(gSavedSettings.getBOOL(param));  	}  	else if (chosen_item == "sort_distance")  	{ @@ -1368,6 +1389,8 @@ bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata)  		return sort_order == E_SORT_BY_NAME;  	if (item == "sort_distance")  		return sort_order == E_SORT_BY_DISTANCE; +	if (item == "view_icons") +		return gSavedSettings.getBOOL(mNearbyList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");  	return false;  } @@ -1386,7 +1409,10 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ -		mRecentList->toggleIcons(); +		std::string param = mRecentList->getIconParamName(); +		gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride"))); +		mRecentList->setIconsVisible(gSavedSettings.getBOOL(param));  	}  } @@ -1399,6 +1425,8 @@ bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata)  		return sort_order == E_SORT_BY_NAME;  	if (item == "sort_status")  		return sort_order == E_SORT_BY_STATUS; +	if (item == "view_icons") +		return gSavedSettings.getBOOL(mAllFriendList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");  	return false;  } @@ -1412,6 +1440,8 @@ bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata)  		return sort_order == E_SORT_BY_MOST_RECENT;  	if (item == "sort_name")   		return sort_order == E_SORT_BY_NAME; +	if (item == "view_icons") +		return gSavedSettings.getBOOL(mRecentList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");  	return false;  } diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index c1d7a134fa..eb7e76a772 100755 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -93,6 +93,7 @@ private:  	// UI callbacks  	void					onFilterEdit(const std::string& search_string); +	void					onGroupLimitInfo();  	void					onTabSelected(const LLSD& param);  	void					onAddFriendButtonClicked();  	void					onAddFriendWizButtonClicked(); diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index d73a5b402e..55c09d85ea 100755 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -432,7 +432,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)  		mNoPicks = !mPicksList->size();  	} -	else if(APT_CLASSIFIEDS == type) +	else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))  	{  		LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);  		if(c_info && getAvatarId() == c_info->target_id) diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 4bcd932d4b..a9a0c30e26 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -921,7 +921,12 @@ void LLPanelPlaces::onBackButtonClicked()  void LLPanelPlaces::togglePickPanel(BOOL visible)  {  	if (mPickPanel) +	{  		mPickPanel->setVisible(visible); +		mPlaceProfile->setVisible(!visible); +		updateVerbs(); +	} +  }  void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) @@ -1141,16 +1146,21 @@ void LLPanelPlaces::updateVerbs()  	bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE;  	bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; +	bool is_pick_panel_visible = false; +	if(mPickPanel) +	{ +		is_pick_panel_visible = mPickPanel->isInVisibleChain(); +	}  	bool have_3d_pos = ! mPosGlobal.isExactlyZero(); -	mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); -	mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); +	mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); +	mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);  	mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);  	mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn);  	mSaveBtn->setVisible(isLandmarkEditModeOn);  	mCancelBtn->setVisible(isLandmarkEditModeOn);  	mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); -	mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); +	mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);  	mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos); diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index ac9a31ce4e..109013498e 100755 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -313,14 +313,11 @@ void LLPanelTopInfoBar::updateParcelIcons()  		bool allow_damage	= vpm->allowAgentDamage(agent_region, current_parcel);  		bool see_avs        = current_parcel->getSeeAVs(); -		bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID()); -		bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify()); -  		// Most icons are "block this ability"  		mParcelIcon[VOICE_ICON]->setVisible(   !allow_voice );  		mParcelIcon[FLY_ICON]->setVisible(     !allow_fly );  		mParcelIcon[PUSH_ICON]->setVisible(    !allow_push ); -		mParcelIcon[BUILD_ICON]->setVisible(   !allow_build && !is_parcel_owner && !allow_group_modify ); +		mParcelIcon[BUILD_ICON]->setVisible(   !allow_build );  		mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );  		mParcelIcon[DAMAGE_ICON]->setVisible(  allow_damage );  		mDamageText->setVisible(allow_damage); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 75e0ed3741..d86a8b4480 100755 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -131,7 +131,7 @@ protected:  			{  				bp_selected = true;  			} -			else if (type == LLAssetType::AT_OBJECT) +			else if (type == LLAssetType::AT_OBJECT || type == LLAssetType::AT_GESTURE)  			{  				attachments_selected = true;  			} diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 1bbb22416d..67832c5994 100755 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1391,6 +1391,8 @@ void LLLiveLSLEditor::buildExperienceList()  	else  	{  		mExperiences->setEnabled(TRUE); +		mExperiences->sortByName(TRUE); +		mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex());  		getChild<LLButton>("view_profile")->setVisible(TRUE);  	}  } @@ -2621,8 +2623,12 @@ void LLLiveLSLEditor::onLoad(void* userdata)  void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)  {  	LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; -	self->mCloseAfterSave = close_after_save; -	self->saveIfNeeded(); +	if(self) +	{ +		self->mCloseAfterSave = close_after_save; +		self->mScriptEd->mErrorList->setCommentText(""); +		self->saveIfNeeded(); +	}  } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index f91a18d8d3..c8cf0faa15 100755 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -618,4 +618,5 @@ void LLPreviewTexture::setObjectID(const LLUUID& object_id)  		mAssetStatus = PREVIEW_ASSET_UNLOADED;  		loadAsset();  	} +	refreshFromItem();  } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4fafbf917b..55bcb3dc65 100755 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2127,7 +2127,7 @@ void LLSelectMgr::selectionRemoveMaterial()  			{  			        LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;  				LLMaterialMgr::getInstance()->remove(object->getID(),face); -				object->setTEMaterialParams(face, NULL); +				object->setTEMaterialParams(face, NULL, FALSE);  			}  			return true;  		} @@ -4950,6 +4950,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,  									ESendType send_type)  {  	LLSelectNode* node; +	LLSelectNode* linkset_root = NULL;  	LLViewerRegion*	last_region;  	LLViewerRegion*	current_region; @@ -4957,6 +4958,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,  	S32 packets_sent = 0;  	S32 objects_in_this_packet = 0; +	bool link_operation = message_name == "ObjectLink"; +  	//clear update override data (allow next update through)  	struct f : public LLSelectedNodeFunctor  	{ @@ -5065,6 +5068,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,  			&& (! gMessageSystem->isSendFull(NULL))  			&& (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))  		{ +			if (link_operation && linkset_root == NULL) +			{ +				// linksets over 254 will be split into multiple messages, +				// but we need to provide same root for all messages or we will get separate linksets +				linkset_root = node; +			}  			// add another instance of the body of the data  			(*pack_body)(node, user_data);              // do any related logging @@ -5093,6 +5102,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,  			gMessageSystem->newMessage(message_name.c_str());  			(*pack_header)(user_data); +			if (linkset_root != NULL) +			{ +				if (current_region != last_region) +				{ +					// root should be in one region with the child, reset it +					linkset_root = NULL; +				} +				else +				{ +					// add root instance into new message +					(*pack_body)(linkset_root, user_data); +					++objects_sent; +					++objects_in_this_packet; +				} +			} +  			// don't move to the next object, we still need to add the  			// body data.   		} diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 17ecfab4fb..2548d730f0 100755 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -370,18 +370,25 @@ void LLSidepanelTaskInfo::refresh()  	// Update creator text field  	getChildView("Creator:")->setEnabled(TRUE); +  	std::string creator_name; -	LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); +	LLUUID creator_id; +	LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); -	getChild<LLUICtrl>("Creator Name")->setValue(creator_name); -	getChildView("Creator Name")->setEnabled(TRUE); +	if(creator_id != mCreatorID ) +	{ +		mDACreatorName->setValue(creator_name); +		mCreatorID = creator_id; +	} +	mDACreatorName->setEnabled(TRUE);  	// Update owner text field  	getChildView("Owner:")->setEnabled(TRUE);  	std::string owner_name; -	const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name); -	if (mOwnerID.isNull()) +	LLUUID owner_id; +	const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); +	if (owner_id.isNull())  	{  		if (LLSelectMgr::getInstance()->selectIsGroupOwned())  		{ @@ -402,7 +409,12 @@ void LLSidepanelTaskInfo::refresh()  			}  		}  	} -	getChild<LLUICtrl>("Owner Name")->setValue(owner_name); + +	if(owner_id.isNull() || (owner_id != mOwnerID)) +	{ +		mDAOwnerName->setValue(owner_name); +		mOwnerID = owner_id; +	}  	getChildView("Owner Name")->setEnabled(TRUE);  	// update group text field diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 728fc69723..a8e012bfa1 100755 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -271,7 +271,14 @@ LLSLURL::LLSLURL(const std::string& slurl)  			// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z   			// are collectively optional  			// are optional +  			mRegion = LLURI::unescape(path_array[0].asString()); + +			if(LLStringUtil::containsNonprintable(mRegion)) +			{ +				LLStringUtil::stripNonprintable(mRegion); +			} +  			path_array.erase(0);  			// parse the x, y, and optionally z diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 0ae8a338e0..8561a89ae5 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -195,7 +195,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail          // Stop shining animation.          mShineAnimTimer.stop();  		mSnapshotDelayTimer.start(); -		mSnapshotDelayTimer.setTimerExpirySec(delay); +		mSnapshotDelayTimer.resetWithExpiry(delay); +  		mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal(); @@ -462,7 +463,10 @@ void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_pare  	if (old_rect.getWidth() != width || old_rect.getHeight() != height)  	{  		LL_DEBUGS() << "window reshaped, updating thumbnail" << LL_ENDL; -		updateSnapshot(TRUE); +		if (mViewContainer && mViewContainer->isInVisibleChain()) +		{ +			updateSnapshot(TRUE); +		}  	}  } @@ -670,10 +674,27 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )  		return FALSE;  	} -	// If we're in freeze-frame mode and camera has moved, update snapshot. +	if (previewp->mSnapshotDelayTimer.getStarted()) // Wait for a snapshot delay timer +	{ +		if (!previewp->mSnapshotDelayTimer.hasExpired()) +		{ +			return FALSE; +		} +		previewp->mSnapshotDelayTimer.stop(); +	} + +	if (LLToolCamera::getInstance()->hasMouseCapture()) // Hide full-screen preview while camming, either don't take snapshots while ALT-zoom active +	{ +		previewp->setVisible(FALSE); +		return FALSE; +	} + +	// If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot.  	LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();  	LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); -	if (previewp->mForceUpdateSnapshot || (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview && +	if (previewp->mForceUpdateSnapshot || +		(((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) || +		(gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) &&  		(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)))  	{  		previewp->mCameraPos = new_camera_pos; @@ -688,11 +709,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )  		previewp->mForceUpdateSnapshot = FALSE;  	} -	// see if it's time yet to snap the shot and bomb out otherwise. -	previewp->mSnapshotActive =  -		(previewp->mSnapshotDelayTimer.getStarted() &&	previewp->mSnapshotDelayTimer.hasExpired()) -		&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active -	if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate()) +	if (previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())  	{  		return FALSE;  	} @@ -706,6 +723,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )              previewp->mPreviewImage = new LLImageRaw;          } +        previewp->mSnapshotActive = TRUE; +          previewp->setVisible(FALSE);          previewp->setEnabled(FALSE); @@ -734,40 +753,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )              // Full size preview is set: get the decoded image result and save it for animation              if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview)              { -                // Get the decoded version of the formatted image -                previewp->getEncodedImage(); -             -                // We need to scale that a bit for display... -                LLPointer<LLImageRaw> scaled = new LLImageRaw( -                    previewp->mPreviewImageEncoded->getData(), -                    previewp->mPreviewImageEncoded->getWidth(), -                    previewp->mPreviewImageEncoded->getHeight(), -                    previewp->mPreviewImageEncoded->getComponents()); - -                if (!scaled->isBufferInvalid()) -                { -                    // leave original image dimensions, just scale up texture buffer -                    if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024) -                    { -                        // go ahead and shrink image to appropriate power of 2 for display -                        scaled->biasedScaleToPowerOfTwo(1024); -                        previewp->setImageScaled(TRUE); -                    } -                    else -                    { -                        // expand image but keep original image data intact -                        scaled->expandToPowerOfTwo(1024, FALSE); -                    } - -                    previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); -                    LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; -                    gGL.getTexUnit(0)->bind(curr_preview_image); -                    curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); -                    curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); - -                    previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame -                } +                previewp->prepareFreezeFrame();              } +              // The snapshot is updated now...              previewp->mSnapshotUpToDate = TRUE; @@ -777,7 +765,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )          }          previewp->getWindow()->decBusyCount();          previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode -        previewp->mSnapshotDelayTimer.stop();          previewp->mSnapshotActive = FALSE;          LL_DEBUGS() << "done creating snapshot" << LL_ENDL;      } @@ -796,6 +783,47 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )  	return TRUE;  } +void LLSnapshotLivePreview::prepareFreezeFrame() +{ +    // Get the decoded version of the formatted image +    getEncodedImage(); + +    // We need to scale that a bit for display... +    LLPointer<LLImageRaw> scaled = new LLImageRaw( +        mPreviewImageEncoded->getData(), +        mPreviewImageEncoded->getWidth(), +        mPreviewImageEncoded->getHeight(), +        mPreviewImageEncoded->getComponents()); + +    if (!scaled->isBufferInvalid()) +    { +        // leave original image dimensions, just scale up texture buffer +        if (mPreviewImageEncoded->getWidth() > 1024 || mPreviewImageEncoded->getHeight() > 1024) +        { +            // go ahead and shrink image to appropriate power of 2 for display +            scaled->biasedScaleToPowerOfTwo(1024); +            setImageScaled(TRUE); +        } +        else +        { +            // expand image but keep original image data intact +            scaled->expandToPowerOfTwo(1024, FALSE); +        } + +        mViewerImage[mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); +        LLPointer<LLViewerTexture> curr_preview_image = mViewerImage[mCurImageIndex]; +        gGL.getTexUnit(0)->bind(curr_preview_image); +        curr_preview_image->setFilteringOption(getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); +        curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP); + + +        if (gSavedSettings.getBOOL("UseFreezeFrame") && mAllowFullScreenPreview) +        { +            mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame +        } +    } +} +  S32 LLSnapshotLivePreview::getEncodedImageWidth() const  {      S32 width = getWidth(); diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h index fed33bf37c..57e5d83f8e 100644 --- a/indra/newview/llsnapshotlivepreview.h +++ b/indra/newview/llsnapshotlivepreview.h @@ -119,7 +119,7 @@ public:  	void generateThumbnailImage(BOOL force_update = FALSE) ;  	void resetThumbnailImage() { mThumbnailImage = NULL ; }  	void drawPreviewRect(S32 offset_x, S32 offset_y) ; - +	void prepareFreezeFrame();  	LLViewerTexture* getBigThumbnailImage();  	S32  getBigThumbnailWidth() const { return mBigThumbnailWidth ; } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 7867e1573c..44c980c96f 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -547,21 +547,8 @@ void LLSpeakerMgr::updateSpeakerList()  				// For groups, we need to hit the group manager.  				// Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.  				LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); -                F32 large_group_delay = 0.f; -                if (gdatap) -                { -                    //This is a viewer-side bandaid for maint-4414 it does not fix the core issue. -                    large_group_delay = (F32)(gdatap->mMemberCount / 5000); -                } -                 -                const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay; - -				if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout)) -				{ -					// Request the data the first time around -					LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id); -				} -				else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + +				if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())  				{  					// Add group members when we get the complete list (note: can take a while before we get that list)  					LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d2050aec3e..965aad517d 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -421,9 +421,7 @@ bool idle_startup()  		gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());  		gSavedSettings.setString("LastGPUString", thisGPU); -		// load dynamic GPU/feature tables from website (S3) -		LLFeatureManager::getInstance()->fetchHTTPTables(); -		 +  		std::string xml_file = LLUI::locateSkin("xui_version.xml");  		LLXMLNodePtr root;  		bool xml_ok = false; @@ -3238,6 +3236,23 @@ bool process_login_success_response()  			LLStringUtil::trim(gDisplayName);  		}  	} +	std::string first_name; +	if(response.has("first_name")) +	{ +		first_name = response["first_name"].asString(); +		LLStringUtil::replaceChar(first_name, '"', ' '); +		LLStringUtil::trim(first_name); +		gAgentUsername = first_name; +	} + +	if(response.has("last_name") && !gAgentUsername.empty() && (gAgentUsername != "Resident")) +	{ +		std::string last_name = response["last_name"].asString(); +		LLStringUtil::replaceChar(last_name, '"', ' '); +		LLStringUtil::trim(last_name); +		gAgentUsername = gAgentUsername + " " + last_name; +	} +  	if(gDisplayName.empty())  	{  		if(response.has("first_name")) @@ -3258,6 +3273,7 @@ bool process_login_success_response()  			gDisplayName += text;  		}  	} +  	if(gDisplayName.empty())  	{  		gDisplayName.assign(gUserCredential->asString()); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index ef852bc905..bcdf8360ed 100755 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1544,17 +1544,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)  		{  			std::string dirname = mTexturesDirName + delem + subdirs[i];  			LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL; -			gDirUtilp->deleteFilesInDir(dirname, mask);  			if (purge_directories)  			{ -				LLFile::rmdir(dirname); +				gDirUtilp->deleteDirAndContents(dirname); +			} +			else +			{ +				gDirUtilp->deleteFilesInDir(dirname, mask);  			}  		}  		if (purge_directories)  		{  			gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);  			LLFile::rmdir(mTexturesDirName); -		}		 +		}  	}  	mHeaderIDMap.clear();  	mTexturesSizeMap.clear(); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 81fbc471b3..ff71028a9b 100755 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1013,13 +1013,10 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,  	// causing a dirty inventory) and we can do an update, stall the user  	// while fetching the inventory.  	// -	// Note: fetch only if inventory is both dirty and not present since previously checked faces -	// could have requested new fetch for same item (removed inventory and marked as dirty=false). -	// Objects without listeners (dirty==true and inventory!=NULL. In this specific case - before -	// first fetch) shouldn't be updated either since we won't receive any changes. -	if (hit_obj->isInventoryDirty() && hit_obj->getInventoryRoot() == NULL) +	// Fetch if inventory is dirty and listener is present (otherwise we will not receive update) +	if (hit_obj->isInventoryDirty() && hit_obj->hasInventoryListeners())  	{ -		hit_obj->fetchInventoryFromServer(); +		hit_obj->requestInventory();  		LLSD args;  		args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again.";  		LLNotificationsUtil::add("ErrorMessage", args); @@ -1099,10 +1096,12 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,  		{  			hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);  		} -		// Force the object to update its refetch its inventory so it has this texture. -		hit_obj->fetchInventoryFromServer(); - 		// TODO: Check to see if adding the item was successful; if not, then -		// we should return false here. +		// Force the object to update and refetch its inventory so it has this texture. +		hit_obj->dirtyInventory(); +		hit_obj->requestInventory(); +		// TODO: Check to see if adding the item was successful; if not, then +		// we should return false here. This will requre a separate listener +		// since without listener, we have no way to receive update  	}  	return TRUE;  } @@ -1155,8 +1154,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,  	}  	LLSculptParams sculpt_params; -	sculpt_params.setSculptTexture(asset_id); -	sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH); +	sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH);  	hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);  	dialog_refresh_all(); diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index cad5769042..8a61114852 100755 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -84,7 +84,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()  	const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));  	LLWString text_to_copy;  	// *HACK: Because LLSLURL is currently broken we cannot use it to check if unescaped_text is a valid SLURL (see EXT-8335). -	if (LLStringUtil::startsWith(unescaped_text, "http://")) // SLURL +	if (LLStringUtil::startsWith(unescaped_text, "http://") || LLStringUtil::startsWith(unescaped_text, "secondlife://")) // SLURL  		text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));  	else // human-readable location  		text_to_copy = utf8str_to_wstring(unescaped_text); diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 6803adfaa2..1ce42e97b8 100755 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -248,6 +248,7 @@ public:  	void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;};  	void clearCache();  	void setPageZoomFactor( double factor ); +	double getPageZoomFactor() {return mZoomFactor;}  	std::string getMimeType() { return mMimeType; }  	void scaleMouse(S32 *mouse_x, S32 *mouse_y);  	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2505ae6a9c..38d62dee5e 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -57,6 +57,7 @@  #include "llfacebookconnect.h"  #include "llfilepicker.h"  #include "llfirstuse.h" +#include "llfloaterabout.h"  #include "llfloaterbuy.h"  #include "llfloaterbuycontents.h"  #include "llbuycurrencyhtml.h" @@ -2139,6 +2140,22 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t +/////////////////////// +// CHECK FOR UPDATES // +/////////////////////// + + + +class LLAdvancedCheckViewerUpdates : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		LLFloaterAboutUtil::checkUpdatesAndNotify(); +		return true; +	} +}; + +  ////////////////////  // COMPRESS IMAGE //  //////////////////// @@ -7140,11 +7157,10 @@ void handle_selected_texture_info(void*)     			{     				msg.append( llformat("%d ", (S32)(it->second[i])));     			} - -			LLSD args; -			args["MESSAGE"] = msg; -			LLNotificationsUtil::add("SystemMessage", args);     		} +   		LLSD args; +   		args["MESSAGE"] = msg; +   		LLNotificationsUtil::add("SystemMessage", args);  	}  } @@ -8920,6 +8936,7 @@ void initialize_menus()  	// Advanced (toplevel)  	view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");  	view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); +	view_listener_t::addMenu(new LLAdvancedCheckViewerUpdates(), "Advanced.CheckViewerUpdates");  	view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");  	view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");  	view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 886725be79..e570657cf9 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -57,6 +57,7 @@  #include "llcallingcard.h"  #include "llbuycurrencyhtml.h"  #include "llfirstuse.h" +#include "llfloaterbump.h"  #include "llfloaterbuyland.h"  #include "llfloaterland.h"  #include "llfloaterregioninfo.h" @@ -2349,7 +2350,8 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s  	LLNotificationsUtil::add("GodMessage", args);  	// Treat like a system message and put in chat history. -	chat.mText = av_name.getCompleteName() + ": " + message; +	chat.mSourceType = CHAT_SOURCE_SYSTEM; +	chat.mText = message;  	LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");  	if (nearby_chat) @@ -2860,6 +2862,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  	case IM_FROM_TASK:  		{ +  			if (is_do_not_disturb && !is_owned_by_me)  			{  				return; @@ -2943,17 +2946,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			payload["from_id"] = from_id;  			payload["slurl"] = location;  			payload["name"] = name; -			std::string session_name; +  			if (from_group)  			{  				payload["group_owned"] = "true";  			} -			LLNotification::Params params("ServerObjectMessage"); -			params.substitutions = substitutions; -			params.payload = payload; - -			LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group); +			LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);  		}  		break; @@ -3789,11 +3788,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  			}  		} -		LLSD msg_notify = LLSD(LLSD::emptyMap()); -		msg_notify["session_id"] = LLUUID(); -        msg_notify["from_id"] = chat.mFromID; -		msg_notify["source_type"] = chat.mSourceType; -        on_new_message(msg_notify); +		if (mesg != "") +		{ +			LLSD msg_notify = LLSD(LLSD::emptyMap()); +			msg_notify["session_id"] = LLUUID(); +			msg_notify["from_id"] = chat.mFromID; +			msg_notify["source_type"] = chat.mSourceType; +			on_new_message(msg_notify); +		} +  	}  } @@ -6263,6 +6266,11 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use  			gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));  		}  	} +	LLFloaterBump* bumps_floater = LLFloaterBump::getInstance(); +	if(bumps_floater && bumps_floater->isInVisibleChain()) +	{ +		bumps_floater->populateCollisionList(); +	}  }  void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index ac3f07fcd8..c4d3829ee9 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2840,6 +2840,11 @@ void LLViewerObject::clearInventoryListeners()  	mInventoryCallbacks.clear();  } +bool LLViewerObject::hasInventoryListeners() +{ +	return !mInventoryCallbacks.empty(); +} +  void LLViewerObject::requestInventory()  {  	if(mInventoryDirty && mInventory && !mInventoryCallbacks.empty()) @@ -2847,15 +2852,20 @@ void LLViewerObject::requestInventory()  		mInventory->clear(); // will deref and delete entries  		delete mInventory;  		mInventory = NULL; -		mInventoryDirty = FALSE; //since we are going to request it now  	} +  	if(mInventory)  	{ +		// inventory is either up to date or doesn't has a listener +		// if it is dirty, leave it this way in case we gain a listener  		doInventoryCallback();  	} -	// throw away duplicate requests  	else  	{ +		// since we are going to request it now +		mInventoryDirty = FALSE; + +		// Note: throws away duplicate requests  		fetchInventoryFromServer();  	}  } @@ -2865,8 +2875,6 @@ void LLViewerObject::fetchInventoryFromServer()  	if (!mInventoryPending)  	{  		delete mInventory; -		mInventory = NULL; -		mInventoryDirty = FALSE;  		LLMessageSystem* msg = gMessageSystem;  		msg->newMessageFast(_PREHASH_RequestTaskInventory);  		msg->nextBlockFast(_PREHASH_AgentData); @@ -2885,6 +2893,9 @@ struct LLFilenameAndTask  {  	LLUUID mTaskID;  	std::string mFilename; + +	// for sequencing in case of multiple updates +	S16 mSerial;  #ifdef _DEBUG  	static S32 sCount;  	LLFilenameAndTask() @@ -2920,9 +2931,17 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)  		return;  	} -	msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);  	LLFilenameAndTask* ft = new LLFilenameAndTask;  	ft->mTaskID = task_id; +	// we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update +	msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); + +	if (ft->mSerial < object->mInventorySerialNum) +	{ +		// viewer did some changes to inventory that were not saved yet. +		LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; +		object->mInventorySerialNum = ft->mSerial; +	}  	std::string unclean_filename;  	msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); @@ -2962,9 +2981,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS  {  	LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;  	LLViewerObject* object = NULL; -	if(ft && (0 == error_code) && -	   (object = gObjectList.findObject(ft->mTaskID))) + +	if (ft +		&& (0 == error_code) +		&& (object = gObjectList.findObject(ft->mTaskID)) +		&& ft->mSerial >= object->mInventorySerialNum)  	{ +		object->mInventorySerialNum = ft->mSerial;  		if (object->loadTaskInvFile(ft->mFilename))  		{ @@ -2995,7 +3018,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS  	}  	else  	{ -		// This Occurs When to requests were made, and the first one +		// This Occurs When two requests were made, and the first one  		// has already handled it.  		LL_DEBUGS() << "Problem loading task inventory. Return code: "  				 << error_code << LL_ENDL; @@ -4637,7 +4660,7 @@ S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID  	return retval;  } -S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)  {  	S32 retval = 0;  	const LLTextureEntry *tep = getTE(te); @@ -4647,13 +4670,14 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri  		return 0;  	} -	retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams); +	setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); +	setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); + +	retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams, isInitFromServer);  	LL_DEBUGS("Material") << "Changing material params for te " << (S32)te  							<< ", object " << mID  			               << " (" << retval << ")"  							<< LL_ENDL; -	setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); -	setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);  	refreshMaterials();  	return retval; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 05c87c153b..65d6f8225f 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -330,7 +330,7 @@ public:  	/*virtual*/	S32		setTEMediaFlags(const U8 te, const U8 media_flags );  	/*virtual*/ S32     setTEGlow(const U8 te, const F32 glow);  	/*virtual*/ S32     setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); -	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); +	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);  	// Used by Materials update functions to properly kick off rebuilds  	// of VBs etc when materials updates require changes. @@ -436,8 +436,8 @@ public:  	void removeInventoryListener(LLVOInventoryListener* listener);  	BOOL isInventoryPending() { return mInventoryPending; }  	void clearInventoryListeners(); +	bool hasInventoryListeners();  	void requestInventory(); -	void fetchInventoryFromServer();  	static void processTaskInv(LLMessageSystem* msg, void** user_data);  	void removeInventory(const LLUUID& item_id); @@ -593,6 +593,9 @@ private:  	static void initObjectDataMap(); +	// forms task inventory request if none are pending +	void fetchInventoryFromServer(); +  public:  	//  	// Viewer-side only types - use the LL_PCODE_APP mask. diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index f60829e9e8..24a6758312 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -60,6 +60,7 @@  #include "llfeaturemanager.h"  #include "llviewernetwork.h"  #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llsdserialize.h"  namespace LLStatViewer  { @@ -616,8 +617,10 @@ void send_stats()  	body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");  	body["MinimalSkin"] = false; -	 +  	LLViewerStats::getInstance()->addToMessage(body); + +	LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL;  	LLHTTPClient::post(url, body, new ViewerStatsResponder());  	LLViewerStats::instance().getRecording().resume(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f753448770..b97a1bde99 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -160,6 +160,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;  const S32 MORPH_MASK_REQUESTED_DISCARD = 0; +const F32 MAX_STANDOFF_FROM_ORIGIN = 3; +const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32; +  // Discard level at which to switch to baked textures  // Should probably be 4 or 3, but didn't want to change it while change other logic - SJB  const S32 SWITCH_TO_BAKED_DISCARD = 5; @@ -2132,7 +2135,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)  	// animate the character  	// store off last frame's root position to be consistent with camera position -	LLVector3 root_pos_last = mRoot->getWorldPosition(); +	mLastRootPos = mRoot->getWorldPosition();  	BOOL detailed_update = updateCharacter(agent);  	static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false); @@ -2150,7 +2153,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)  		idleUpdateWindEffect();  	} -	idleUpdateNameTag( root_pos_last ); +	idleUpdateNameTag( mLastRootPos );  	idleUpdateRenderCost();  } @@ -6080,10 +6083,10 @@ void LLVOAvatar::getOffObject()  	{  		return;  	} -	 +  	LLViewerObject* sit_object = (LLViewerObject*)getParent(); -	if (sit_object)  +	if (sit_object)  	{  		stopMotionFromSource(sit_object->getID());  		LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE); @@ -6100,9 +6103,19 @@ void LLVOAvatar::getOffObject()  	}  	// assumes that transform will not be updated with drawable still having a parent +	// or that drawable had no parent from the start  	LLVector3 cur_position_world = mDrawable->getWorldPosition();  	LLQuaternion cur_rotation_world = mDrawable->getWorldRotation(); +	if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN +		&& (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN +			|| dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE)) +	{ +		// Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent +		// restore coordinates from cache +		cur_position_world = mLastRootPos; +	} +  	// set *local* position based on last *world* position, since we're unparenting the avatar  	mDrawable->mXform.setPosition(cur_position_world);  	mDrawable->mXform.setRotation(cur_rotation_world);	 @@ -6278,6 +6291,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)  BOOL LLVOAvatar::isVisible() const  {  	return mDrawable.notNull() +		&& (!mOrphaned || isSelf())  		&& (mDrawable->isVisible() || mIsDummy);  } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1c3f4f2aa7..5b4379165a 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -869,6 +869,8 @@ public:  private:  	// set this property only with LLVOAvatar::sitDown method  	BOOL 			mIsSitting; +	// position backup in case of missing data +	LLVector3		mLastRootPos;  /**                    Hierarchy   **                                                                            ** diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 267061b83d..68713280c0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");  static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");  static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) +{ +	bool regen_faces = false; + +	LLVolume *old_volumep, *new_volumep; +	F32 old_lod, new_lod; +	S32 old_num_faces, new_num_faces; + +	old_volumep = getVolume(); +	old_lod = old_volumep->getDetail(); +	old_num_faces = old_volumep->getNumFaces(); +	old_volumep = NULL; + +	{ +		LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); +		const LLVolumeParams &volume_params = getVolume()->getParams(); +		setVolume(volume_params, 0); +	} + +	new_volumep = getVolume(); +	new_lod = new_volumep->getDetail(); +	new_num_faces = new_volumep->getNumFaces(); +	new_volumep = NULL; + +	if ((new_lod != old_lod) || mSculptChanged) +	{ +		compiled = TRUE; +		sNumLODChanges += new_num_faces; + +		if ((S32)getNumTEs() != getVolume()->getNumFaces()) +		{ +			setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. +		} + +		drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() + +		{ +			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); +			regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs(); +			if (regen_faces) +			{ +				regenFaces(); +			} + +			if (mSculptChanged) +			{ //changes in sculpt maps can thrash an object bounding box without  +				//triggering a spatial group bounding box update -- force spatial group +				//to update bounding boxes +				LLSpatialGroup* group = mDrawable->getSpatialGroup(); +				if (group) +				{ +					group->unbound(); +				} +			} +		} +	} + +	return regen_faces; +} +  BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)  {  	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES); @@ -1664,83 +1724,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)  		return TRUE; // No update to complete  	} -	if (mVolumeChanged || mFaceMappingChanged ) +	if (mVolumeChanged || mFaceMappingChanged)  	{  		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); -		compiled = TRUE; +		bool was_regen_faces = false;  		if (mVolumeChanged)  		{ -			LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); -			LLVolumeParams volume_params = getVolume()->getParams(); -			setVolume(volume_params, 0); +			was_regen_faces = lodOrSculptChanged(drawable, compiled);  			drawable->setState(LLDrawable::REBUILD_VOLUME);  		} - +		else if (mSculptChanged || mLODChanged)  		{ +			compiled = TRUE; +			was_regen_faces = lodOrSculptChanged(drawable, compiled); +		} + +		if (!was_regen_faces) {  			LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);  			regenFaces(); -			genBBoxes(FALSE);  		} + +		genBBoxes(FALSE);  	} -	else if ((mLODChanged) || (mSculptChanged)) +	else if (mLODChanged || mSculptChanged)  	{  		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - -		LLVolume *old_volumep, *new_volumep; -		F32 old_lod, new_lod; -		S32 old_num_faces, new_num_faces ; - -		old_volumep = getVolume(); -		old_lod = old_volumep->getDetail(); -		old_num_faces = old_volumep->getNumFaces() ; -		old_volumep = NULL ; - -		{ -			LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); -			LLVolumeParams volume_params = getVolume()->getParams(); -			setVolume(volume_params, 0); -		} - -		new_volumep = getVolume(); -		new_lod = new_volumep->getDetail(); -		new_num_faces = new_volumep->getNumFaces() ; -		new_volumep = NULL ; - -		if ((new_lod != old_lod) || mSculptChanged) -		{ -			compiled = TRUE; -			sNumLODChanges += new_num_faces ; -	 -			if((S32)getNumTEs() != getVolume()->getNumFaces()) -			{ -				setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. -			} - -			drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() - -			{ -				LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); -				if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs()) -				{ -					regenFaces(); -				} -				genBBoxes(FALSE); - -				if (mSculptChanged) -				{ //changes in sculpt maps can thrash an object bounding box without  -				  //triggering a spatial group bounding box update -- force spatial group -				  //to update bounding boxes -					LLSpatialGroup* group = mDrawable->getSpatialGroup(); -					if (group) -					{ -						group->unbound(); -					} -				} -			} -		} - +		compiled = TRUE; +		lodOrSculptChanged(drawable, compiled);  		genBBoxes(FALSE);  	}  	// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local @@ -2010,7 +2022,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM  		LLTextureEntry* texture_entry = pVol->getTE(te);  		if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))  		{ -			pVol->setTEMaterialParams(te, pMaterialParams); +			pVol->setTEMaterialParams(te, pMaterialParams, FALSE);  		}  	}  } @@ -2081,7 +2093,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture)  	for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)  	{  		LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); -		LLViewerObject::setTEMaterialParams(it->first, it->second); +		LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);  	}  	//clear wait-list @@ -2158,7 +2170,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)  	for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)  	{  		LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); -		LLViewerObject::setTEMaterialParams(it->first, it->second); +		LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);  	}  	//clear wait-list @@ -2167,7 +2179,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)  	return 0 != new_material.size();  } -S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)  {  	LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams); @@ -2264,7 +2276,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa  		}  	} -	S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial); +	S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer);  	LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res  							 << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" ) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index bbaca316b0..ff7438ac09 100755 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -192,7 +192,7 @@ public:  	static void	setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te); -	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); +	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);  	/*virtual*/ S32		setTEScale(const U8 te, const F32 s, const F32 t);  	/*virtual*/ S32		setTEScaleS(const U8 te, const F32 s);  	/*virtual*/ S32		setTEScaleT(const U8 te, const F32 t); @@ -339,6 +339,10 @@ protected:  	void cleanUpMediaImpls();  	void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;  	void removeMediaImpl(S32 texture_index) ; + +private: +	bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled); +  public:  	static S32 getRenderComplexityMax() {return mRenderComplexity_last;} diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 1c3808ce68..f8981d0c51 100755 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -35,6 +35,7 @@  #include "llappearancemgr.h"  #include "llinventoryfunctions.h"  #include "llinventoryicon.h" +#include "llgesturemgr.h"  #include "lltransutil.h"  #include "llviewerattachmenu.h"  #include "llvoavatarself.h" @@ -55,7 +56,8 @@ bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,  	{  		if((item->getType() == LLAssetType::AT_CLOTHING)  		   || (item->getType() == LLAssetType::AT_BODYPART) -		   || (item->getType() == LLAssetType::AT_OBJECT)) +		   || (item->getType() == LLAssetType::AT_OBJECT) +		   || (item->getType() == LLAssetType::AT_GESTURE))  		{  			return TRUE;  		} @@ -491,6 +493,7 @@ LLWearableItemTypeNameComparator::LLWearableItemTypeNameComparator()  	mWearableOrder[LLAssetType::AT_CLOTHING] = LLWearableTypeOrder(ORDER_RANK_1, false, false);  	mWearableOrder[LLAssetType::AT_OBJECT]   = LLWearableTypeOrder(ORDER_RANK_2, true, true);  	mWearableOrder[LLAssetType::AT_BODYPART] = LLWearableTypeOrder(ORDER_RANK_3, false, true); +	mWearableOrder[LLAssetType::AT_GESTURE] = LLWearableTypeOrder(ORDER_RANK_4, true, false);  }  void LLWearableItemTypeNameComparator::setOrder(LLAssetType::EType items_of_type,  LLWearableItemTypeNameComparator::ETypeListOrder order_priority, bool sort_asset_items_by_name, bool sort_wearable_items_by_name) @@ -989,6 +992,10 @@ void LLWearableItemsList::ContextMenu::updateMask(U32& mask, LLAssetType::EType  	{  		mask |= MASK_ATTACHMENT;  	} +	else if (at == LLAssetType::AT_GESTURE) +	{ +		mask |= MASK_GESTURE; +	}  	else  	{  		mask |= MASK_UNKNOWN; diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index e6788ab249..df4b1a8a50 100755 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -310,6 +310,7 @@ public:  		ORDER_RANK_1 = 1,  		ORDER_RANK_2,  		ORDER_RANK_3, +		ORDER_RANK_4,  		ORDER_RANK_UNKNOWN  	}; @@ -419,7 +420,8 @@ public:  			MASK_CLOTHING		= 0x01,  			MASK_BODYPART		= 0x02,  			MASK_ATTACHMENT		= 0x04, -			MASK_UNKNOWN		= 0x08, +			MASK_GESTURE		= 0x08, +			MASK_UNKNOWN		= 0x16,  		};  		/* virtual */ LLContextMenu* createMenu(); diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index bfae142812..837b30586b 100755 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -383,6 +383,7 @@ void LLWorldMap::reloadItems(bool force)  		LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);  		LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);  		LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE); +		LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT);  	}  } diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml index aa6bc53672..299322001b 100755 --- a/indra/newview/skins/default/xui/da/menu_viewer.xml +++ b/indra/newview/skins/default/xui/da/menu_viewer.xml @@ -37,7 +37,7 @@  		<menu_item_separator/>  		<menu_item_call label="Profil for sted" name="Place Profile"/>  		<menu_item_call label="Om land" name="About Land"/> -		<menu_item_call label="Region/Estate" name="Region/Estate"/> +		<menu_item_call label="Region/Estate" name="RegionEstate"/>  		<menu_item_call label="Køb dette land" name="Buy Land"/>  		<menu_item_call label="Mit land" name="My Land"/>  		<menu label="Vis" name="LandShow"> diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 33b876bdb9..aad3b9d062 100755 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1311,9 +1311,6 @@ Prøv igen om lidt.  	<notification name="NoValidCircuit">  		Ingen gyldig kode for kredsløb.  	</notification> -	<notification name="NoValidTimestamp"> -		Ikke et gyldigt klokkeslæt. -	</notification>  	<notification name="NoPendingConnection">  		Kunne ikke skabe fast forbindelse.  	</notification> diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 1924ff4ec3..956530c990 100755 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Fliegen" name="Fly"/>  			<menu_item_check label="Immer rennen" name="Always Run"/>  			<menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/> -			<menu_item_call label="Gehen/Rennen/Fliegen..." name="Walk / run / fly"/> +			<menu_item_call label="Gehen/Rennen/Fliegen..." name="WalkRunFly"/>  		</menu>  		<menu label="Status" name="Status">  			<menu_item_check label="Abwesend" name="Away"/> @@ -64,7 +64,7 @@  		<menu_item_call label="Foto" name="Take Snapshot"/>  		<menu_item_call label="Ortsprofil" name="Place Profile"/>  		<menu_item_call label="Landinformationen" name="About Land"/> -		<menu_item_call label="Region/Grundbesitz" name="Region/Estate"/> +		<menu_item_call label="Region/Grundbesitz" name="RegionEstate"/>  		<menu_item_call label="Mein Landbesitz..." name="My Land"/>  		<menu_item_call label="Dieses Land kaufen" name="Buy Land"/>  		<menu label="Anzeigen" name="LandShow"> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 0b1c18cd51..fa7db0a8a3 100755 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2802,9 +2802,6 @@ Versuchen Sie es in einigen Minuten erneut.  	<notification name="NoValidCircuit">  		Kein gültiger Verbindungscode.  	</notification> -	<notification name="NoValidTimestamp"> -		Kein gültiger Zeitstempel. -	</notification>  	<notification name="NoPendingConnection">  		Verbindung kann nicht hergestellt werden.  	</notification> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 60f36770bb..ec87b3684e 100755 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -43,6 +43,14 @@          top_pad="5"          height="25"          width="180" /> +      <button +        follows="left|top" +        label="Check for updates" +        name="update_btn" +        left_pad="70" +        top_delta="0" +        height="25" +        width="180" />      </panel>      <panel        border="true"  diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 90d45d5ebc..edf028bf60 100755 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -2013,7 +2013,7 @@ Only large parcels can be listed in search.               name="AllowedText"               top="0"               width="230"> -                Allowed Residents +                Allowed Residents ([COUNT])              </text>              <name_list               column_padding="0" @@ -2062,7 +2062,7 @@ Only large parcels can be listed in search.               name="BanCheck"               top="0"               width="200"> -                Banned Residents +                Banned Residents ([COUNT])              </text>              <name_list               column_padding="0" diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml index 1f2fe62b3c..126e3aac48 100755 --- a/indra/newview/skins/default/xui/en/floater_bumps.xml +++ b/indra/newview/skins/default/xui/en/floater_bumps.xml @@ -7,7 +7,7 @@   help_topic="floater_bumps"   save_rect="true"   title="BUMPS, PUSHES & HITS" - width="400"> + width="420">      <floater.string       name="none_detected">          None detected @@ -34,7 +34,7 @@      </floater.string>      <floater.string       name="timeStr"> -        [[hour,datetime,slt]:[min,datetime,slt]] +        [[hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt]]      </floater.string>      <scroll_list       draw_border="false" @@ -45,5 +45,5 @@       multi_select="true"       name="bump_list"       top="20" -     width="388" /> +     width="408" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_experiences.xml b/indra/newview/skins/default/xui/en/floater_experiences.xml index 70e7507907..442da887c5 100644 --- a/indra/newview/skins/default/xui/en/floater_experiences.xml +++ b/indra/newview/skins/default/xui/en/floater_experiences.xml @@ -12,7 +12,7 @@    name="floater_experiences"    save_rect="true"    single_instance="true" -  reuse_instance="false" +     bg_opaque_color="0 0.5 0 0.3"    title="EXPERIENCES">    <tab_container diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 91adec0789..033a10c9ec 100755 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -565,14 +565,6 @@      <menu_item_call       label="Delete"       layout="topleft" -     name="Remove Link"> -        <menu_item_call.on_click -         function="Inventory.DoToSelected" -         parameter="delete" /> -    </menu_item_call> -    <menu_item_call -     label="Delete" -     layout="topleft"       name="Delete">          <menu_item_call.on_click           function="Inventory.DoToSelected" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index e91eea04d1..73ca7c529d 100755 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -108,6 +108,12 @@               function="Floater.Show"               parameter="sl_about" />          </menu_item_call> +        <menu_item_call +         label="Check for Updates" +         name="Check for Updates"> +            <menu_item_call.on_click +             function="Advanced.CheckViewerUpdates"/> +        </menu_item_call>      </menu>      <menu_item_check        label="Show Debug Menu" diff --git a/indra/newview/skins/default/xui/en/menu_participant_view.xml b/indra/newview/skins/default/xui/en/menu_participant_view.xml index 7ea87ee05c..658238bf41 100755 --- a/indra/newview/skins/default/xui/en/menu_participant_view.xml +++ b/indra/newview/skins/default/xui/en/menu_participant_view.xml @@ -59,6 +59,19 @@           function="IMFloaterContainer.Check"           parameter="sort_participants_by_recent" />      </menu_item_check> +	<menu_item_separator +     layout="topleft" /> +	<menu_item_check +	 label="View people icons" +	 layout="topleft" +	 name="view_icons"> +		<on_click +         function="IMFloaterContainer.Action" +         parameter="view_icons" /> +		<on_check +         function="IMFloaterContainer.Check" +         parameter="view_icons" /> +	</menu_item_check>      <menu_item_separator       layout="topleft" />      <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml index 8790fde7c5..02c6cfc006 100755 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml @@ -29,8 +29,8 @@       function="People.Friends.ViewSort.Action"       parameter="view_icons" />      <menu_item_check.on_check -     function="CheckControl" -     parameter="FriendsListShowIcons" /> +     function="People.Friends.ViewSort.CheckItem" +     parameter="view_icons" />    </menu_item_check>    <menu_item_check name="view_permissions" label="View Permissions Granted">      <menu_item_check.on_click diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml index da88ca9f4d..44b3d14e10 100755 --- a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml @@ -39,8 +39,8 @@           function="People.Nearby.ViewSort.Action"           parameter="view_icons" />          <menu_item_check.on_check -         function="CheckControl" -         parameter="NearbyListShowIcons" /> +         function="People.Nearby.ViewSort.CheckItem" +         parameter="view_icons"/>      </menu_item_check>      <menu_item_check name ="view_map" label="View Map">          <menu_item_check.on_check diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view.xml index 1dbc90dd2b..cd2260d0c4 100755 --- a/indra/newview/skins/default/xui/en/menu_people_recent_view.xml +++ b/indra/newview/skins/default/xui/en/menu_people_recent_view.xml @@ -29,7 +29,7 @@       function="People.Recent.ViewSort.Action"       parameter="view_icons" />      <menu_item_check.on_check -     function="CheckControl" -     parameter="RecentListShowIcons" /> +     function="People.Recent.ViewSort.CheckItem" +     parameter="view_icons" />    </menu_item_check>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_email.xml b/indra/newview/skins/default/xui/en/menu_url_email.xml new file mode 100644 index 0000000000..6467fe5c90 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_email.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Email Popup"> +    <menu_item_call +     label="Compose Email in an External client" +     layout="topleft" +     name="email_open_external"> +        <menu_item_call.on_click +         function="Url.OpenExternal" /> +    </menu_item_call> +    <menu_item_separator +     layout="topleft" /> +    <menu_item_call +     label="Copy Email to clipboard" +     layout="topleft" +     name="email_copy"> +        <menu_item_call.on_click +         function="Url.CopyLabel" /> +    </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 2463c5f43b..3f557d0d0f 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -134,7 +134,7 @@          </menu_item_call>          <menu_item_call           label="Walk / run / fly..." -         name="Walk / run / fly"> +         name="WalkRunFly">            <menu_item_call.on_click             function="Floater.ToggleOrBringToFront"             parameter="moveview" /> @@ -509,7 +509,7 @@          </menu_item_call>          <menu_item_call           label="Region / Estate" -         name="Region/Estate"> +         name="RegionEstate">              <menu_item_call.on_click               function="Floater.Show"               parameter="region_info" /> @@ -1438,7 +1438,7 @@                   function="Floater.Show"                   parameter="bumps" />          </menu_item_call> -        <menu_item_separator/>     +        <menu_item_separator/>          <menu_item_call           label="About [APP_NAME]"           name="About Second Life"> @@ -1446,6 +1446,12 @@               function="Floater.Show"               parameter="sl_about" />          </menu_item_call> +        <menu_item_call +         label="Check for Updates" +         name="Check for Updates"> +          <menu_item_call.on_click +           function="Advanced.CheckViewerUpdates"/> +        </menu_item_call>      </menu>      <menu       create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index f847c73287..70ba4d5077 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -819,6 +819,33 @@ If you no longer wish to have these abilities granted to this role, disable them        notext="Cancel"        yestext="Eject"/>    </notification> +   +  <notification +    icon="alertmodal.tga" +    name="BanGroupMemberWarning" +    type="alertmodal"> +     You are about to ban [AVATAR_NAME] from the group. +     <tag>group</tag> +     <tag>confirm</tag> +     <usetemplate +      ignoretext="Confirm banning a participant from group" +      name="okcancelignore" +      notext="Cancel" +      yestext="Ban"/> +  </notification> +  <notification +    icon="alertmodal.tga" +    name="BanGroupMembersWarning" +    type="alertmodal"> +     You are about to ban [COUNT] members from group. +     <tag>group</tag> +     <tag>confirm</tag> +     <usetemplate +      ignoretext="Confirm banning multiple members from group" +      name="okcancelignore" +      notext="Cancel" +      yestext="Ban"/> +  </notification>    <notification     icon="alertmodal.tga" @@ -3892,6 +3919,53 @@ see [[INFO_URL] Information about this update]       name="okbutton"       yestext="OK"/>    </notification> +   +  <notification + icon="alertmodal.tga" + name="UpdateDownloadInProgress" + type="alertmodal"> +An update is available! +It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready. +    <tag>confirm</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> +   +  <notification + icon="alertmodal.tga" + name="UpdateDownloadComplete" + type="alertmodal"> +An update was downloaded. It will be installed during restart. +    <tag>confirm</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification + icon="alertmodal.tga" + name="UpdateCheckError" + type="alertmodal"> +An error occured while checking for update. +Please try again later. +    <tag>confirm</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> + +  <notification + icon="alertmodal.tga" + name="UpdateViewerUpToDate" + type="alertmodal"> +Your viewer is up to date! +If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers. +    <tag>confirm</tag> +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification>    <notification     icon="alertmodal.tga" @@ -4217,6 +4291,21 @@ You have reached your maximum number of groups. Please leave some group before j    <notification     icon="alert.tga" +   name="GroupLimitInfo" +   type="alert"> +The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium] +accounts is [MAX_PREMIUM]. +If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more. + +[https://secondlife.com/my/account/membership.php Upgrade today!] +    <tag>group</tag> +    <usetemplate +     name="okbutton" +     yestext="Close"/> +  </notification> + +  <notification +   icon="alert.tga"     name="KickUser"     type="alert">     <tag>win</tag> @@ -7029,15 +7118,6 @@ No valid circuit code.    <notification  	icon="notify.tga" -	name="NoValidTimestamp" -   persist="true" -	type="notify"> -   <tag>fail</tag> -No valid timestamp. -  </notification> - -  <notification -	icon="notify.tga"  	name="NoPendingConnection"     persist="true"  	type="notify"> diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml index c76b958eda..c357f9e7d5 100644 --- a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml +++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml @@ -47,19 +47,19 @@        height="12"        follows="top|left">     </text> -  <scroll_list +  <name_list      draw_heading="false"      left="3"      width="225"      height="75"      follows="all"      name="experience_list"> -    <columns +    <name_list.columns        width="225"        user_resize="false"        name="experience_name"        label="Name"/> -  </scroll_list> +  </name_list>    <button      layout="topleft"      follows="top|right" diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index 0518688f45..0a85477bf4 100755 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -21,7 +21,7 @@    </panel.string>    <panel.string     name="ItemcountUnknown"> - +    Fetched [ITEM_COUNT] Items [FILTER]    </panel.string>    <text  		     type="string" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 2d4665c128..4fb8b9a67f 100755 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M                  left="3"                  use_ellipses="true"                  name="groupcount"> -              You belong to [COUNT] groups, and can join [REMAINING] more. +              You belong to [COUNT] groups, and can join [REMAINING] more.  [secondlife:/// Want more?]              </text>              <group_list               allow_select="true"  diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 2e778014c5..3e96160834 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -216,7 +216,7 @@       control_name="QAMode"       follows="top|left"       height="15" -     label="Show Developer Menu" +     label="Show Develop Menu"       layout="topleft"       left="30"       name="show_develop_menu_check" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 1e9a1aa27c..a8be517f3c 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -270,7 +270,7 @@           value="1" />        -->          <combo_box.item -         label="Download and install updates manually" +         label="I will download and install updates manually"           name="Install_manual"           value="0" />    </combo_box> @@ -313,4 +313,30 @@  		<button.commit_callback  		  function="Pref.Proxy" />    </button> +  <text +    type="string" +    length="1" +    follows="left|top" +    height="10" +    layout="topleft" +    left="30" +    name="People Icons:" +    mouse_opaque="false" +    top_pad="5" +    width="300"> +		People Icons: +  </text> +  <check_box +	top_delta="4" +	enabled="true" +	follows="left|top" +	height="14" +	initial_value="false" +	control_name="GlobalShowIconsOverride" +	label="Hide people icons (global override)" +	left_delta="50" +	mouse_opaque="true" +	name="global_show_icons_override" +	width="400"            +	top_pad="10"/>  </panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b7e0cff146..4eb6e2462d 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -238,6 +238,7 @@ Please try logging in again in a minute.</string>  	<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>  	<string name="TooltipTooManyWearables">You can't wear a folder containing more than [AMOUNT] items.  You can change this limit in Advanced > Show Debug Settings > WearFolderLimit.</string>  	<string name="TooltipPrice" value="L$[AMOUNT]: "/> +	<string name="TooltipSLIcon">This links to a page on the official SecondLife.com or LindenLab.com domain.</string>      <string name="TooltipOutboxDragToWorld">You can't rez items from the Marketplace Listings folder</string>      <string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string> @@ -277,6 +278,7 @@ Please try logging in again in a minute.</string>  	<string name="TooltipMapUrl">Click to view this location on a map</string>  	<string name="TooltipSLAPP">Click to run the secondlife:// command</string>  	<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" /> +	<string name="TooltipEmail">Click to compose an email</string>  	<!-- text for SLURL labels -->  	<string name="SLurlLabelTeleport">Teleport to</string> diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index 5118171d80..f6ebb498ec 100755 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Volar" name="Fly"/>  			<menu_item_check label="Correr siempre" name="Always Run"/>  			<menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/> -			<menu_item_call label="Caminar / Correr / Volar..." name="Walk / run / fly"/> +			<menu_item_call label="Caminar / Correr / Volar..." name="WalkRunFly"/>  		</menu>  		<menu label="Estado" name="Status">  			<menu_item_check label="Ausente" name="Away"/> @@ -63,7 +63,7 @@  		<menu_item_call label="Foto" name="Take Snapshot"/>  		<menu_item_call label="Perfil del lugar" name="Place Profile"/>  		<menu_item_call label="Acerca del terreno" name="About Land"/> -		<menu_item_call label="Región/Estado" name="Region/Estate"/> +		<menu_item_call label="Región/Estado" name="RegionEstate"/>  		<menu_item_call label="Mis terrenos..." name="My Land"/>  		<menu_item_call label="Comprar este terreno" name="Buy Land"/>  		<menu label="Mostrar" name="LandShow"> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 9578e1b863..1e367b33fc 100755 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -2796,9 +2796,6 @@ Por favor, vuelve a intentarlo en unos momentos.  	<notification name="NoValidCircuit">  		Circuito de código inválido.  	</notification> -	<notification name="NoValidTimestamp"> -		Fecha inválida. -	</notification>  	<notification name="NoPendingConnection">  		No se puede crear la conexión.  	</notification> diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index 33b2ba6982..788cdbf856 100755 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Voler" name="Fly"/>  			<menu_item_check label="Toujours courir" name="Always Run"/>  			<menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/> -			<menu_item_call label="Marcher / Courir / Voler..." name="Walk / run / fly"/> +			<menu_item_call label="Marcher / Courir / Voler..." name="WalkRunFly"/>  		</menu>  		<menu label="Statut" name="Status">  			<menu_item_check label="Absent" name="Away"/> @@ -64,7 +64,7 @@  		<menu_item_call label="Photo" name="Take Snapshot"/>  		<menu_item_call label="Profil du lieu" name="Place Profile"/>  		<menu_item_call label="À propos du terrain" name="About Land"/> -		<menu_item_call label="Région/Domaine" name="Region/Estate"/> +		<menu_item_call label="Région/Domaine" name="RegionEstate"/>  		<menu_item_call label="Mes terrains..." name="My Land"/>  		<menu_item_call label="Acheter ce terrain" name="Buy Land"/>  		<menu label="Afficher" name="LandShow"> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index f13a80fe61..29e6fe1979 100755 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -2788,9 +2788,6 @@ Veuillez réessayer dans quelques minutes.  	<notification name="NoValidCircuit">  		Aucun code de circuit valide.  	</notification> -	<notification name="NoValidTimestamp"> -		Timestamp non valide. -	</notification>  	<notification name="NoPendingConnection">  		Impossible de créer la connexion en attente.  	</notification> diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml index 40082cb265..2b8249c8a9 100755 --- a/indra/newview/skins/default/xui/fr/panel_login.xml +++ b/indra/newview/skins/default/xui/fr/panel_login.xml @@ -1,9 +1,6 @@  <?xml version="1.0" encoding="utf-8"?>  <panel name="panel_login">  	<panel.string name="forgot_password_url">http://secondlife.com/account/request.php?lang=fr</panel.string> -	<panel.string name="forgot_password_url"> -		http://secondlife.com/account/request.php?lang=fr -	</panel.string>  	<layout_stack name="ui_stack">  		<layout_panel name="ui_container">  			<combo_box label="Nom d'utilisateur" name="username_combo" tool_tip="Nom d'utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/> diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml index 3f4c370ccd..18ddad5ee8 100755 --- a/indra/newview/skins/default/xui/it/menu_viewer.xml +++ b/indra/newview/skins/default/xui/it/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Vola" name="Fly"/>  			<menu_item_check label="Corri sempre" name="Always Run"/>  			<menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/> -			<menu_item_call label="Cammina / corri / vola..." name="Walk / run / fly"/> +			<menu_item_call label="Cammina / corri / vola..." name="WalkRunFly"/>  		</menu>  		<menu label="Stato" name="Status">  			<menu_item_check label="Assente" name="Away"/> @@ -64,7 +64,7 @@  		<menu_item_call label="Istantanea" name="Take Snapshot"/>  		<menu_item_call label="Profilo del luogo" name="Place Profile"/>  		<menu_item_call label="Informazioni sul terreno" name="About Land"/> -		<menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/> +		<menu_item_call label="Regione/proprietà immobiliare" name="RegionEstate"/>  		<menu_item_call label="Terreni posseduti..." name="My Land"/>  		<menu_item_call label="Acquista questo terreno" name="Buy Land"/>  		<menu label="Mostra" name="LandShow"> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 06f2b70dcf..61131b09c3 100755 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2793,9 +2793,6 @@ Riprova tra qualche istante.  	<notification name="NoValidCircuit">  		Nessun codice circuito valido.  	</notification> -	<notification name="NoValidTimestamp"> -		Nessuna data/timestamp valido. -	</notification>  	<notification name="NoPendingConnection">  		Impossibile creare la connessione in sospeso.  	</notification> diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml index 3f756c5f94..0384dc1efc 100755 --- a/indra/newview/skins/default/xui/ja/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="飛ぶ" name="Fly"/>  			<menu_item_check label="常に走る" name="Always Run"/>  			<menu_item_call label="私のアニメーションを停止する" name="Stop Animating My Avatar"/> -			<menu_item_call label="歩行/走行/飛行..." name="Walk / run / fly"/> +			<menu_item_call label="歩行/走行/飛行..." name="WalkRunFly"/>  		</menu>  		<menu label="ログイン" name="Status">  			<menu_item_check label="一時退席中" name="Away"/> @@ -64,7 +64,7 @@  		<menu_item_call label="スナップショット" name="Take Snapshot"/>  		<menu_item_call label="場所のプロフィール" name="Place Profile"/>  		<menu_item_call label="土地情報" name="About Land"/> -		<menu_item_call label="地域 / 不動産" name="Region/Estate"/> +		<menu_item_call label="地域 / 不動産" name="RegionEstate"/>  		<menu_item_call label="保有地..." name="My Land"/>  		<menu_item_call label="この土地を購入" name="Buy Land"/>  		<menu label="表示" name="LandShow"> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index 694f38467e..5f0ce7a73b 100755 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2836,9 +2836,6 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ  	<notification name="NoValidCircuit">  		回路コードが無効です。  	</notification> -	<notification name="NoValidTimestamp"> -		タイムスタンプが無効です。 -	</notification>  	<notification name="NoPendingConnection">  		接続を生成できません。  	</notification> diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index ef3fe71945..6fd498eea8 100755 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -33,7 +33,7 @@  		<menu_item_call label="Zrób zdjęcie" name="Take Snapshot"/>  		<menu_item_call label="Profil miejsca" name="Place Profile"/>  		<menu_item_call label="O posiadłości" name="About Land"/> -		<menu_item_call label="Region/Majątek" name="Region/Estate"/> +		<menu_item_call label="Region/Majątek" name="RegionEstate"/>  		<menu_item_call label="Moje posiadłości" name="My Land"/>  		<menu_item_call label="Kup posiadłość" name="Buy Land"/>  		<menu label="Pokaż" name="LandShow"> diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 62fda0d601..c4a65d92b4 100755 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -2368,9 +2368,6 @@ Spróbuj ponowanie za kilka minut.  	<notification name="NoValidCircuit">  		Nieważny obwód kodowania.  	</notification> -	<notification name="NoValidTimestamp"> -		Niewłaściwy czas zapisu. -	</notification>  	<notification name="NoPendingConnection">  		Brak możliwości wykonania połączenia.  	</notification> diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index 9b3b6077ed..3d5d9eccc6 100755 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Voar" name="Fly"/>  			<menu_item_check label="Correr sempre" name="Always Run"/>  			<menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/> -			<menu_item_call label="Andar/correr/voar..." name="Walk / run / fly"/> +			<menu_item_call label="Andar/correr/voar..." name="WalkRunFly"/>  		</menu>  		<menu label="Status" name="Status">  			<menu_item_check label="Ausente" name="Away"/> @@ -64,7 +64,7 @@  		<menu_item_call label="Foto" name="Take Snapshot"/>  		<menu_item_call label="Perfil da região" name="Place Profile"/>  		<menu_item_call label="Sobre terrenos" name="About Land"/> -		<menu_item_call label="Região/Propriedade" name="Region/Estate"/> +		<menu_item_call label="Região/Propriedade" name="RegionEstate"/>  		<menu_item_call label="Meus terrenos..." name="My Land"/>  		<menu_item_call label="Comprar este terreno" name="Buy Land"/>  		<menu label="Mostrar" name="LandShow"> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index 29b85d9e97..a264495404 100755 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -2777,9 +2777,6 @@ Por favor, tente novamente em alguns instantes.  	<notification name="NoValidCircuit">  		Código de circuito inválido.  	</notification> -	<notification name="NoValidTimestamp"> -		Hora inválida. -	</notification>  	<notification name="NoPendingConnection">  		Impossível criar a conexão pendente.  	</notification> diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index 958105a70f..d22ca845f9 100755 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Полет" name="Fly"/>  			<menu_item_check label="Всегда бегать" name="Always Run"/>  			<menu_item_call label="Остановить анимацию" name="Stop Animating My Avatar"/> -			<menu_item_call label="Ходьба / бег / полет..." name="Walk / run / fly"/> +			<menu_item_call label="Ходьба / бег / полет..." name="WalkRunFly"/>  		</menu>  		<menu label="Статус" name="Status">  			<menu_item_check label="Нет на месте" name="Away"/> @@ -62,7 +62,7 @@  		<menu_item_call label="Снимок" name="Take Snapshot"/>  		<menu_item_call label="Профиль места" name="Place Profile"/>  		<menu_item_call label="О земле" name="About Land"/> -		<menu_item_call label="Регион/землевладение" name="Region/Estate"/> +		<menu_item_call label="Регион/землевладение" name="RegionEstate"/>  		<menu_item_call label="Мои владения..." name="My Land"/>  		<menu_item_call label="Купить эту землю" name="Buy Land"/>  		<menu label="Показать" name="LandShow"> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index acf3ce608f..70b9a25590 100755 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -2788,9 +2788,6 @@ http://secondlife.com/download.  	<notification name="NoValidCircuit">  		Нет подходящего кода канала.  	</notification> -	<notification name="NoValidTimestamp"> -		Нет подходящей метки времени. -	</notification>  	<notification name="NoPendingConnection">  		Невозможно создать отложенное соединение.  	</notification> diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml index cc8d8c895b..cea57011dd 100755 --- a/indra/newview/skins/default/xui/tr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="Uç" name="Fly"/>  			<menu_item_check label="Daima Koş" name="Always Run"/>  			<menu_item_call label="Beni Anime Etmeyi Durdur" name="Stop Animating My Avatar"/> -			<menu_item_call label="Yürü / koş / uç..." name="Walk / run / fly"/> +			<menu_item_call label="Yürü / koş / uç..." name="WalkRunFly"/>  		</menu>  		<menu label="Durum" name="Status">  			<menu_item_check label="Uzakta" name="Away"/> @@ -62,7 +62,7 @@  		<menu_item_call label="Anlık Görüntü" name="Take Snapshot"/>  		<menu_item_call label="Profili yerleştir" name="Place Profile"/>  		<menu_item_call label="Arazi hakkında" name="About Land"/> -		<menu_item_call label="Bölge / Gayrimenkul" name="Region/Estate"/> +		<menu_item_call label="Bölge / Gayrimenkul" name="RegionEstate"/>  		<menu_item_call label="Sahip olduğum arazi parçaları..." name="My Land"/>  		<menu_item_call label="Bu araziyi satın al" name="Buy Land"/>  		<menu label="Göster" name="LandShow"> diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml index a6c69c7ab2..df22251b3d 100755 --- a/indra/newview/skins/default/xui/tr/notifications.xml +++ b/indra/newview/skins/default/xui/tr/notifications.xml @@ -2788,9 +2788,6 @@ Lütfen biraz sonra tekrar deneyin.  	<notification name="NoValidCircuit">  		Geçerli bir devre kodu yok.  	</notification> -	<notification name="NoValidTimestamp"> -		Geçerli bir zaman damgası yok. -	</notification>  	<notification name="NoPendingConnection">  		Beklemedeki bağlantı oluşturulamıyor.  	</notification> diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml index e94f52a401..9572ad49d3 100755 --- a/indra/newview/skins/default/xui/zh/menu_viewer.xml +++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml @@ -15,7 +15,7 @@  			<menu_item_check label="飛行" name="Fly"/>  			<menu_item_check label="以跑代步" name="Always Run"/>  			<menu_item_call label="停止我身上的動作" name="Stop Animating My Avatar"/> -			<menu_item_call label="行走 / 跑步 / 飛行…" name="Walk / run / fly"/> +			<menu_item_call label="行走 / 跑步 / 飛行…" name="WalkRunFly"/>  		</menu>  		<menu label="狀態" name="Status">  			<menu_item_check label="離開" name="Away"/> @@ -62,7 +62,7 @@  		<menu_item_call label="快照" name="Take Snapshot"/>  		<menu_item_call label="地點小檔案" name="Place Profile"/>  		<menu_item_call label="土地資料" name="About Land"/> -		<menu_item_call label="地區/領地" name="Region/Estate"/> +		<menu_item_call label="地區/領地" name="RegionEstate"/>  		<menu_item_call label="我所擁有的土地…" name="My Land"/>  		<menu_item_call label="購買這塊土地" name="Buy Land"/>  		<menu label="顯示" name="LandShow"> diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml index 179f01e90d..0a98101b60 100755 --- a/indra/newview/skins/default/xui/zh/notifications.xml +++ b/indra/newview/skins/default/xui/zh/notifications.xml @@ -2778,9 +2778,6 @@ SHA1 指紋:[MD5_DIGEST]  	<notification name="NoValidCircuit">  		沒有有效的線路碼。  	</notification> -	<notification name="NoValidTimestamp"> -		沒有有效的時間戳記。 -	</notification>  	<notification name="NoPendingConnection">  		無法建立待通的連線。  	</notification> diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index c152493a51..788955a1b2 100755 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -132,6 +132,7 @@ public:  	void startChecking(bool install_if_ready);  	void stopChecking(); +	bool forceCheck();  	bool isChecking();  	LLUpdaterService::eUpdaterState getState(); @@ -266,6 +267,46 @@ void LLUpdaterServiceImpl::stopChecking()  	setState(LLUpdaterService::TERMINAL);  } +bool LLUpdaterServiceImpl::forceCheck() +{ +	if (!mIsDownloading && getState() != LLUpdaterService::CHECKING_FOR_UPDATE) +	{ +		if (mIsChecking) +		{ +			// Service is running, just reset the timer +			if (mTimer.getStarted()) +			{ +				mTimer.setTimerExpirySec(0); +				setState(LLUpdaterService::CHECKING_FOR_UPDATE); +				return true; +			} +		} +		else if (!mChannel.empty() && !mVersion.empty()) +		{ +			// one time check +			bool has_install = checkForInstall(false); +			if (!has_install) +			{ +				std::string query_url = LLGridManager::getInstance()->getUpdateServiceURL(); +				if (!query_url.empty()) +				{ +					setState(LLUpdaterService::CHECKING_FOR_UPDATE); +					mUpdateChecker.checkVersion(query_url, mChannel, mVersion, +						mPlatform, mPlatformVersion, mUniqueId, +						mWillingToTest); +					return true; +				} +				else +				{ +					LL_WARNS("UpdaterService") +						<< "No updater service defined for grid '" << LLGridManager::getInstance()->getGrid() << LL_ENDL; +				} +			} +		} +	} +	return false; +} +  bool LLUpdaterServiceImpl::isChecking()  {  	return mIsChecking; @@ -402,9 +443,9 @@ bool LLUpdaterServiceImpl::checkForResume()  void LLUpdaterServiceImpl::error(std::string const & message)  { +	setState(LLUpdaterService::TEMPORARY_ERROR);  	if(mIsChecking)  	{ -		setState(LLUpdaterService::TEMPORARY_ERROR);  		restartTimer(mCheckPeriod);  	}  } @@ -449,8 +490,12 @@ void LLUpdaterServiceImpl::response(LLSD const & content)  	else  	{  		LL_WARNS("UpdaterService") << "Invalid update query response ignored; retry in " -								   << mCheckPeriod << " seconds" << LL_ENDL; -		restartTimer(mCheckPeriod); +			<< mCheckPeriod << " seconds" << LL_ENDL; +		setState(LLUpdaterService::TEMPORARY_ERROR); +		if (mIsChecking) +		{ +			restartTimer(mCheckPeriod); +		}  	}  } @@ -672,6 +717,11 @@ void LLUpdaterService::stopChecking()  	mImpl->stopChecking();  } +bool LLUpdaterService::forceCheck() +{ +	return mImpl->forceCheck(); +} +  bool LLUpdaterService::isChecking()  {  	return mImpl->isChecking(); diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 0ddf24935b..95bbe1695c 100755 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -84,6 +84,7 @@ public:  	void startChecking(bool install_if_ready = false);  	void stopChecking(); +	bool forceCheck();  	bool isChecking();  	eUpdaterState getState(); | 
