diff options
Diffstat (limited to 'indra')
53 files changed, 1145 insertions, 540 deletions
| diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 70b3a08473..b0c87b0208 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -661,7 +661,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)          return false;      } -    if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) +    if (!gDirUtilp->fileExists(filename))      {          // File not found, abort.          return false; diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 15c5c7c6c0..ad20d71a86 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -116,6 +116,15 @@ public:  		else return LLJoint::LOW_PRIORITY;  	} +    virtual S32 getNumJointMotions() +    { +        if (mJointMotionList) +        { +            return mJointMotionList->getNumJointMotions(); +        } +        return 0; +    } +  	virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }  	// called to determine when a motion should be activated/deactivated based on avatar pixel coverage diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index 2dfc3afc7f..aaa9a146d7 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -129,6 +129,9 @@ public:  	// motions must report their priority level  	virtual LLJoint::JointPriority getPriority() = 0; +	// amount of affected joints +	virtual S32 getNumJointMotions() { return 0; }; +  	// motions must report their blend type  	virtual LLMotionBlendType getBlendType() = 0; diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 7241b3c0c2..675da65af2 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -37,15 +37,22 @@  struct FolderEntry : public LLDictionaryEntry  {  	FolderEntry(const std::string &type_name, // 8 character limit! -				bool is_protected) // can the viewer change categories of this type? +				bool is_protected, // can the viewer change categories of this type? +				bool is_automatic, // always made before first login?  +				bool is_singleton  // should exist as a unique copy under root +		)   		:  	LLDictionaryEntry(type_name), -	mIsProtected(is_protected) +	mIsProtected(is_protected), +	mIsAutomatic(is_automatic), +	mIsSingleton(is_singleton)  	{  		llassert(type_name.length() <= 8);  	}  	const bool mIsProtected; +	const bool mIsAutomatic; +	const bool mIsSingleton;  };  class LLFolderDictionary : public LLSingleton<LLFolderDictionary>, @@ -59,50 +66,64 @@ protected:  	}  }; +// Folder types +//  +// PROTECTED means that folders of this type can't be moved, deleted +// or otherwise modified by the viewer. +//  +// SINGLETON means that there should always be exactly one folder of +// this type, and it should be the root or a child of the root. This +// is true for most types of folders. +// +// AUTOMATIC means that a copy of this folder should be created under +// the root before the user ever logs in, and should never be created +// from the viewer. A missing AUTOMATIC folder should be treated as a +// fatal error by the viewer, since it indicates either corrupted +// inventory or a failure in the inventory services. +//  LLFolderDictionary::LLFolderDictionary()  { -	//       													    TYPE NAME	PROTECTED -	//      													   |-----------|---------| -	addEntry(LLFolderType::FT_TEXTURE, 				new FolderEntry("texture",	TRUE)); -	addEntry(LLFolderType::FT_SOUND, 				new FolderEntry("sound",	TRUE)); -	addEntry(LLFolderType::FT_CALLINGCARD, 			new FolderEntry("callcard",	TRUE)); -	addEntry(LLFolderType::FT_LANDMARK, 			new FolderEntry("landmark",	TRUE)); -	addEntry(LLFolderType::FT_CLOTHING, 			new FolderEntry("clothing",	TRUE)); -	addEntry(LLFolderType::FT_OBJECT, 				new FolderEntry("object",	TRUE)); -	addEntry(LLFolderType::FT_NOTECARD, 			new FolderEntry("notecard",	TRUE)); -	addEntry(LLFolderType::FT_ROOT_INVENTORY, 		new FolderEntry("root_inv",	TRUE)); -	addEntry(LLFolderType::FT_LSL_TEXT, 			new FolderEntry("lsltext",	TRUE)); -	addEntry(LLFolderType::FT_BODYPART, 			new FolderEntry("bodypart",	TRUE)); -	addEntry(LLFolderType::FT_TRASH, 				new FolderEntry("trash",	TRUE)); -	addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, 	new FolderEntry("snapshot", TRUE)); -	addEntry(LLFolderType::FT_LOST_AND_FOUND, 		new FolderEntry("lstndfnd",	TRUE)); -	addEntry(LLFolderType::FT_ANIMATION, 			new FolderEntry("animatn",	TRUE)); -	addEntry(LLFolderType::FT_GESTURE, 				new FolderEntry("gesture",	TRUE)); -	addEntry(LLFolderType::FT_FAVORITE, 			new FolderEntry("favorite",	TRUE)); +	//       													    TYPE NAME, PROTECTED, AUTOMATIC, SINGLETON +	addEntry(LLFolderType::FT_TEXTURE, 				new FolderEntry("texture",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_SOUND, 				new FolderEntry("sound",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_CALLINGCARD, 			new FolderEntry("callcard",	TRUE, TRUE, FALSE)); +	addEntry(LLFolderType::FT_LANDMARK, 			new FolderEntry("landmark",	TRUE, FALSE, FALSE)); +	addEntry(LLFolderType::FT_CLOTHING, 			new FolderEntry("clothing",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_OBJECT, 				new FolderEntry("object",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_NOTECARD, 			new FolderEntry("notecard",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_ROOT_INVENTORY, 		new FolderEntry("root_inv",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_LSL_TEXT, 			new FolderEntry("lsltext",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_BODYPART, 			new FolderEntry("bodypart",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_TRASH, 				new FolderEntry("trash",	TRUE, FALSE, TRUE)); +	addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, 	new FolderEntry("snapshot", TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_LOST_AND_FOUND, 		new FolderEntry("lstndfnd",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_ANIMATION, 			new FolderEntry("animatn",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_GESTURE, 				new FolderEntry("gesture",	TRUE, TRUE, TRUE)); +	addEntry(LLFolderType::FT_FAVORITE, 			new FolderEntry("favorite",	TRUE, FALSE, TRUE));  	for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)  	{ -		addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));  +		addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE, FALSE, FALSE)); // Not used  	} -	addEntry(LLFolderType::FT_CURRENT_OUTFIT, 		new FolderEntry("current",	TRUE)); -	addEntry(LLFolderType::FT_OUTFIT, 				new FolderEntry("outfit",	FALSE)); -	addEntry(LLFolderType::FT_MY_OUTFITS, 			new FolderEntry("my_otfts",	TRUE)); +	addEntry(LLFolderType::FT_CURRENT_OUTFIT, 		new FolderEntry("current",	TRUE, FALSE, TRUE)); +	addEntry(LLFolderType::FT_OUTFIT, 				new FolderEntry("outfit",	FALSE, FALSE, FALSE)); +	addEntry(LLFolderType::FT_MY_OUTFITS, 			new FolderEntry("my_otfts",	TRUE, FALSE, TRUE)); -	addEntry(LLFolderType::FT_MESH, 				new FolderEntry("mesh",	TRUE)); +	addEntry(LLFolderType::FT_MESH, 				new FolderEntry("mesh",		TRUE, FALSE, FALSE)); // Not used? -	addEntry(LLFolderType::FT_INBOX, 				new FolderEntry("inbox",	TRUE)); -	addEntry(LLFolderType::FT_OUTBOX, 				new FolderEntry("outbox",	TRUE)); +	addEntry(LLFolderType::FT_INBOX, 				new FolderEntry("inbox",	TRUE, FALSE, TRUE)); +	addEntry(LLFolderType::FT_OUTBOX, 				new FolderEntry("outbox",	TRUE, FALSE, FALSE)); -	addEntry(LLFolderType::FT_BASIC_ROOT,			new FolderEntry("basic_rt", TRUE)); +	addEntry(LLFolderType::FT_BASIC_ROOT,			new FolderEntry("basic_rt", TRUE, FALSE, FALSE));  -	addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE)); -	addEntry(LLFolderType::FT_MARKETPLACE_STOCK,    new FolderEntry("stock",    FALSE)); -	addEntry(LLFolderType::FT_MARKETPLACE_VERSION,  new FolderEntry("version",    FALSE)); +	addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE, FALSE, FALSE)); +	addEntry(LLFolderType::FT_MARKETPLACE_STOCK,    new FolderEntry("stock",    FALSE, FALSE, FALSE)); +	addEntry(LLFolderType::FT_MARKETPLACE_VERSION,  new FolderEntry("version",  FALSE, FALSE, FALSE)); -    addEntry(LLFolderType::FT_SETTINGS,             new FolderEntry("settings", TRUE)); +    addEntry(LLFolderType::FT_SETTINGS,             new FolderEntry("settings", TRUE, FALSE, TRUE)); -	addEntry(LLFolderType::FT_NONE, 				new FolderEntry("-1",		FALSE)); +	addEntry(LLFolderType::FT_NONE, 				new FolderEntry("-1",		FALSE, FALSE, FALSE));  };  // static @@ -126,8 +147,8 @@ const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)  }  // static -// Only ensembles and plain folders aren't protected.  "Protected" means -// you can't change certain properties such as their type. +// Only plain folders and a few other types aren't protected.  "Protected" means +// you can't move, deleted, or change certain properties such as their type.  bool LLFolderType::lookupIsProtectedType(EType folder_type)  {  	const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); @@ -138,6 +159,32 @@ bool LLFolderType::lookupIsProtectedType(EType folder_type)  	}  	return true;  } +  +// static +// Is this folder type automatically created outside the viewer?  +bool LLFolderType::lookupIsAutomaticType(EType folder_type) +{ +	const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); +	const FolderEntry *entry = dict->lookup(folder_type); +	if (entry) +	{ +		return entry->mIsAutomatic; +	} +	return true; +} + +// static +// Should this folder always exist as a single copy under (or as) the root? +bool LLFolderType::lookupIsSingletonType(EType folder_type) +{ +	const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); +	const FolderEntry *entry = dict->lookup(folder_type); +	if (entry) +	{ +		return entry->mIsSingleton; +	} +	return true; +}  // static  bool LLFolderType::lookupIsEnsembleType(EType folder_type) diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 85b86f9ce5..1f174520da 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -102,6 +102,8 @@ public:  	static const std::string&	lookup(EType folder_type);  	static bool 				lookupIsProtectedType(EType folder_type); +	static bool 				lookupIsAutomaticType(EType folder_type); +	static bool 				lookupIsSingletonType(EType folder_type);  	static bool 				lookupIsEnsembleType(EType folder_type);  	static LLAssetType::EType	folderTypeToAssetType(LLFolderType::EType folder_type); diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index dfa29fb539..33e90555fa 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -198,6 +198,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa  	}  	LLVolumeFace::VertexMapData::PointMap point_map; + +    if (idx_stride <= 0 +        || (pos_source && pos_offset >= idx_stride) +        || (tc_source && tc_offset >= idx_stride) +        || (norm_source && norm_offset >= idx_stride)) +    { +        // Looks like these offsets should fit inside idx_stride +        // Might be good idea to also check idx.getCount()%idx_stride != 0 +        LL_WARNS() << "Invalid pos_offset " << pos_offset <<  ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; +        return LLModel::BAD_ELEMENT; +    }  	for (U32 i = 0; i < idx.getCount(); i += idx_stride)  	{ diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 622c9edba7..54fdee6901 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -257,6 +257,8 @@ LLFolderView::LLFolderView(const Params& p)  	mPopupMenuHandle = menu->getHandle();  	mViewModelItem->openItem(); + +	mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited.  }  // Destroys the object diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 285bf9f484..eba93beed9 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -132,7 +132,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)  	mCutGeneration(0),  	mLabelStyle( LLFontGL::NORMAL ),  	mHasVisibleChildren(FALSE), -	mIsFolderComplete(true),      mLocalIndentation(p.folder_indentation),  	mIndentation(0),  	mItemHeight(p.item_height), @@ -1003,11 +1002,11 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):  	mCurHeight(0.f),  	mTargetHeight(0.f),  	mAutoOpenCountdown(0.f), +	mIsFolderComplete(false), // folder might have children that are not loaded yet. +	mAreChildrenInited(false), // folder might have children that are not built yet.  	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() @@ -1063,13 +1062,16 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )  {  	// Sort before laying out contents      // Note that we sort from the root (CHUI-849) -	getRoot()->getFolderViewModel()->sort(this); +    if (mAreChildrenInited) +    { +        getRoot()->getFolderViewModel()->sort(this); +    }  	LL_RECORD_BLOCK_TIME(FTM_ARRANGE);  	// evaluate mHasVisibleChildren  	mHasVisibleChildren = false; -	if (getViewModelItem()->descendantsPassedFilter()) +	if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter())  	{  		// We have to verify that there's at least one child that's not filtered out  		bool found = false; @@ -1095,7 +1097,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )  		mHasVisibleChildren = found;  	} -	if (!mIsFolderComplete) +	if (!mIsFolderComplete && mAreChildrenInited)  	{  		mIsFolderComplete = getFolderViewModel()->isFolderComplete(this);  	} diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 616d2e7d86..ee20d048fd 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -116,7 +116,6 @@ protected:  	F32							mControlLabelRotation;  	LLFolderView*				mRoot;  	bool						mHasVisibleChildren, -								mIsFolderComplete, // indicates that some children were not loaded/added yet  								mIsCurSelection,  								mDragAndDropTarget,  								mIsMouseOverTitle, @@ -219,7 +218,10 @@ public:  	BOOL hasVisibleChildren() { return mHasVisibleChildren; }  	// true if object can't have children -	BOOL isFolderComplete() { return mIsFolderComplete; } +	virtual bool isFolderComplete() { return true; } +    // true if object can't have children +    virtual bool areChildrenInited() { return true; } +    virtual void setChildrenInited(bool inited) { }  	// Call through to the viewed object and return true if it can be  	// removed. Returns true if it's removed. @@ -334,6 +336,8 @@ protected:  	S32			mLastArrangeGeneration;  	S32			mLastCalculatedWidth;  	bool		mNeedsSort; +	bool		mIsFolderComplete; // indicates that some children were not loaded/added yet +	bool		mAreChildrenInited; // indicates that no children were initialized  public:  	typedef enum e_recurse_type @@ -385,6 +389,13 @@ public:  	// destroys this folder, and all children  	virtual void destroyView(); +    // whether known children are fully loaded (arrange sets to true) +    virtual bool isFolderComplete() { return mIsFolderComplete; } + +    // whether known children are fully built +    virtual bool areChildrenInited() { return mAreChildrenInited; } +    virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; } +  	// extractItem() removes the specified item from the folder, but  	// doesn't delete it.  	virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index 4f6deb1f98..1a5157838c 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -126,7 +126,6 @@      <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>      <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> -    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>    </third_person>    <sitting>      <binding key="A" mask="ALT" command="spin_around_cw"/> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b1120c18b2..390cf5b6b2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8337,7 +8337,18 @@      <key>QAModeMetrics</key>      <map>        <key>Comment</key> -      <string>"Enables QA features (logging, faster cycling) for metrics collector"</string> +      <string>Enables QA features (logging, faster cycling) for metrics collector</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>QAModeFakeSystemFolderIssues</key> +    <map> +      <key>Comment</key> +      <string>Simulates system folder issues in inventory</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ed6c3c307f..e10244aad6 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2501,8 +2501,16 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick)  	{  		// focus on object plus designated offset  		// which may or may not be same as pick.mPosGlobal +		// except for rigged items to prevent wrong focus position +		if (objectp->isRiggedMesh()) +		{ +			setFocusGlobal(pick.mPosGlobal, pick.mObjectID); +		} +		else +		{  		setFocusGlobal(objectp->getPositionGlobal() + LLVector3d(pick.mObjectOffset), pick.mObjectID);  	} +	}  	else  	{  		// focus directly on point where user clicked diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 891722e1bd..7b642386d0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4437,120 +4437,6 @@ void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)  void LLAppViewer::loadKeyBindings()  {  	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); -#if 1 -	// Legacy support -	// Remove #if-#endif section half a year after DRTVWR-501 releases. -	// Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in -	// settings.xml. To support legacy viewers that were storing in  settings.xml we need to -	// transfer old variables to new format. -	// Also part of backward compatibility is present in LLKeyConflictHandler to modify -	// legacy variables on changes in new system (to make sure we won't enforce -	// legacy values again if user dropped to defaults in new system) -	if (LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion -		|| !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet -	{ -		// copy mouse actions and voice key changes to new file -		LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL; -		// Load settings from file -		LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON); -		LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING); - -		// Since we are only modifying keybindings if personal file doesn't exist yet, -		// it should be safe to just overwrite the value -		// If key is already in use somewhere by default, LLKeyConflictHandler should resolve it. -		BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot"); -		third_person_view.registerControl("walk_to", -			0, -			value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, -			KEY_NONE, -			MASK_NONE, -			value); - -		U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second -		value = gSavedSettings.getBOOL("ClickToWalk"); -		third_person_view.registerControl("walk_to", -			index, -			value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE, -			KEY_NONE, -			MASK_NONE, -			value); - -		value = gSavedSettings.getBOOL("DoubleClickTeleport"); -		third_person_view.registerControl("teleport_to", -			0, -			value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, -			KEY_NONE, -			MASK_NONE, -			value); - -		// sitting also supports teleport -		sitting_view.registerControl("teleport_to", -			0, -			value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, -			KEY_NONE, -			MASK_NONE, -			value); - -		std::string key_string = gSavedSettings.getString("PushToTalkButton"); -		EMouseClickType mouse = EMouseClickType::CLICK_NONE; -		KEY key = KEY_NONE; -		if (key_string == "MiddleMouse") -		{ -			mouse = EMouseClickType::CLICK_MIDDLE; -		} -		else if (key_string == "MouseButton4") -		{ -			mouse = EMouseClickType::CLICK_BUTTON4; -		} -		else if (key_string == "MouseButton5") -		{ -			mouse = EMouseClickType::CLICK_BUTTON5; -		} -		else -		{ -			LLKeyboard::keyFromString(key_string, &key); -		} - -		value = gSavedSettings.getBOOL("PushToTalkToggle"); -		std::string control_name = value ? "toggle_voice" : "voice_follow_key"; -		third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); -		sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - -		if (third_person_view.hasUnsavedChanges()) -		{ -			// calls loadBindingsXML() -			third_person_view.saveToSettings(); -		} - -		if (sitting_view.hasUnsavedChanges()) -		{ -			// calls loadBindingsXML() -			sitting_view.saveToSettings(); -		} - -		// in case of voice we need to repeat this in other modes - -		for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) -		{ -			// edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment -			if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) -			{ -				LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); - -				handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - -				if (handler.hasUnsavedChanges()) -				{ -					// calls loadBindingsXML() -					handler.saveToSettings(); -				} -			} -		} -	} -	// since something might have gone wrong or there might have been nothing to save -	// (and because otherwise following code will have to be encased in else{}), -	// load everything one last time -#endif  	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))  	{  		// Failed to load custom bindings, try default ones diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 0fd6009074..d43048a8b6 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -99,22 +99,22 @@ void LLAttachmentsMgr::onIdle()  		return;  	} -    if (LLApp::isExiting()) -    { -        return; -    } +	if (LLApp::isExiting()) +	{ +		return; +	}  	requestPendingAttachments(); -    linkRecentlyArrivedAttachments(); +	linkRecentlyArrivedAttachments(); -    expireOldAttachmentRequests(); +	expireOldAttachmentRequests(); -    expireOldDetachRequests(); +	expireOldDetachRequests(); -    checkInvalidCOFLinks(); -     -    spamStatusInfo(); +	checkInvalidCOFLinks(); +	 +	spamStatusInfo();  }  void LLAttachmentsMgr::requestPendingAttachments() @@ -453,51 +453,55 @@ bool LLAttachmentsMgr::isAttachmentStateComplete() const  //  void LLAttachmentsMgr::checkInvalidCOFLinks()  { -        LLInventoryModel::cat_array_t cat_array; -        LLInventoryModel::item_array_t item_array; -        gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -                                      cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -        for (S32 i=0; i<item_array.size(); i++) -        { -            const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -            const LLUUID& item_id = inv_item->getLinkedUUID(); -            if (inv_item->getType() == LLAssetType::AT_OBJECT) -            { -                LLTimer timer; -                bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); -                bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); -                if (is_wearing_attachment && is_flagged_questionable) -                { -                    LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now "  -                                        << (is_wearing_attachment ? "attached " : "")  -                                        <<"removing flag after " -                                        << timer.getElapsedTimeF32() << " item " -                                        << inv_item->getName() << " id " << item_id << LL_ENDL; -                    mQuestionableCOFLinks.removeTime(item_id); -                } -            } -        } +	if (!gInventory.isInventoryUsable()) +	{ +		return; +	} +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +	for (S32 i=0; i<item_array.size(); i++) +	{ +		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +		const LLUUID& item_id = inv_item->getLinkedUUID(); +		if (inv_item->getType() == LLAssetType::AT_OBJECT) +		{ +			LLTimer timer; +			bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); +			bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); +			if (is_wearing_attachment && is_flagged_questionable) +			{ +				LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now "  +									<< (is_wearing_attachment ? "attached " : "")  +									<<"removing flag after " +									<< timer.getElapsedTimeF32() << " item " +									<< inv_item->getName() << " id " << item_id << LL_ENDL; +				mQuestionableCOFLinks.removeTime(item_id); +			} +		} +	} -        for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); -            it != mQuestionableCOFLinks.end(); ) -        { -            LLItemRequestTimes::iterator curr_it = it; -            ++it; -            const LLUUID& item_id = curr_it->first; -            LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); -            if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) -            { -                if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) -                { -                    LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " -                                        << curr_it->second.getElapsedTimeF32() << " seconds for "  -                                        << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; -                    LLAppearanceMgr::instance().removeCOFItemLinks(item_id); -                } -				mQuestionableCOFLinks.erase(curr_it); -                continue; -            } -        } +	for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); +		it != mQuestionableCOFLinks.end(); ) +	{ +		LLItemRequestTimes::iterator curr_it = it; +		++it; +		const LLUUID& item_id = curr_it->first; +		LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); +		if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) +		{ +			if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) +			{ +				LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " +									<< curr_it->second.getElapsedTimeF32() << " seconds for "  +									<< (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; +				LLAppearanceMgr::instance().removeCOFItemLinks(item_id); +			} +			mQuestionableCOFLinks.erase(curr_it); +			continue; +		} +	}  }  void LLAttachmentsMgr::spamStatusInfo() diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 65cec68884..fee85d50bd 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -89,6 +89,7 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes  	mFlashStarted(false)  {  	mFlashTimer = new LLFlashTimer(); +	mAreChildrenInited = true; // inventory only  }  LLConversationViewSession::~LLConversationViewSession() diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 83b5bf3f25..3fdf7d8aa0 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1917,9 +1917,17 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)  	pref_changed |= mRecreateFavoriteStorage;  	mRecreateFavoriteStorage = false; +	// Can get called before inventory is done initializing. +	if (!gInventory.isInventoryUsable()) +	{ +		return FALSE; +	} +	  	LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);  	if (favorite_folder.isNull()) -			return FALSE; +	{ +		return FALSE; +	}  	LLInventoryModel::item_array_t items;  	LLInventoryModel::cat_array_t cats; diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index e075a311c2..a24d1d1436 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -734,11 +734,14 @@ void LLVolumeImplFlexible::preRebuild()  void LLVolumeImplFlexible::doFlexibleRebuild(bool rebuild_volume)  {  	LLVolume* volume = mVO->getVolume(); -	if(rebuild_volume) -	{ -		volume->setDirty(); -	} -	volume->regen(); +    if (volume) +    { +        if (rebuild_volume) +        { +            volume->setDirty(); +        } +        volume->regen(); +    }  	mUpdated = TRUE;  } diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index d40a7234e2..b6d856e31b 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -66,7 +66,7 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )  {  	LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SORT); -	if (!needsSort(folder->getViewModelItem())) return; +	if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return;  	LLFolderViewModelItemInventory* modelp =   static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());  	if (modelp->getUUID().isNull()) return; @@ -132,6 +132,16 @@ bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder)  	return false;  } +//virtual +void LLFolderViewModelItemInventory::addChild(LLFolderViewModelItem* child) +{ +    LLFolderViewModelItemInventory* model_child = static_cast<LLFolderViewModelItemInventory*>(child); +    mLastAddedChildCreationDate = model_child->getCreationDate(); + +    // this will requestSort() +    LLFolderViewModelItemCommon::addChild(child); +} +  void LLFolderViewModelItemInventory::requestSort()  {  	LLFolderViewModelItemCommon::requestSort(); @@ -140,15 +150,31 @@ void LLFolderViewModelItemInventory::requestSort()  	{  		folderp->requestArrange();  	} -	if (static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter().isByDate()) -	{ -		// sort by date potentially affects parent folders which use a date -		// derived from newest item in them -		if (mParent) -		{ -			mParent->requestSort(); -		} -	} +    LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); + +    // Sort by date potentially affects parent folders which use a date +    // derived from newest item in them +    if (sorter.isByDate() && mParent) +    { +        // If this is an item, parent needs to be resorted +        // This case shouldn't happen, unless someone calls item->requestSort() +        if (!folderp) +        { +            mParent->requestSort(); +        } +        // if this is a folder, check sort rules for folder first +        else if (sorter.isFoldersByDate()) +        { +            if (mLastAddedChildCreationDate == -1  // nothing was added, some other reason for resort +                || mLastAddedChildCreationDate > getCreationDate()) // newer child +            { +                LLFolderViewModelItemInventory* model_parent = static_cast<LLFolderViewModelItemInventory*>(mParent); +                model_parent->mLastAddedChildCreationDate = mLastAddedChildCreationDate; +                mParent->requestSort(); +            } +        } +    } +    mLastAddedChildCreationDate = -1;  }  void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size) @@ -387,6 +413,7 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a,  LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) :      LLFolderViewModelItemCommon(root_view_model), -    mPrevPassedAllFilters(false) +    mPrevPassedAllFilters(false), +    mLastAddedChildCreationDate(-1)  {  } diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 51b98339c4..de28091c32 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -47,6 +47,7 @@ public:  	virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make   into pure virtual.  	virtual BOOL isAgentInventory() const { return FALSE; }  	virtual BOOL isUpToDate() const = 0; +    virtual void addChild(LLFolderViewModelItem* child);  	virtual bool hasChildren() const = 0;  	virtual LLInventoryType::EType getInventoryType() const = 0;  	virtual void performAction(LLInventoryModel* model, std::string action)   = 0; @@ -63,6 +64,7 @@ public:  	virtual LLToolDragAndDrop::ESource getDragSource() const = 0;  protected:      bool mPrevPassedAllFilters; +    time_t mLastAddedChildCreationDate; // -1 if nothing was added  };  class LLInventorySort @@ -83,6 +85,8 @@ public:  	}  	bool isByDate() const { return mByDate; } +	bool isFoldersByName() const { return (!mByDate || mFoldersByName) && !mFoldersByWeight; } +    bool isFoldersByDate() const { return mByDate && !mFoldersByName && !mFoldersByWeight; }  	U32 getSortOrder() const { return mSortOrder; }  	void toParams(Params& p) { p.order(mSortOrder);}  	void fromParams(Params& p)  diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 12d82d101f..9dca509262 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -372,6 +372,11 @@ void LLGroupActions::show(const LLUUID& group_id)  	params["open_tab_name"] = "panel_group_info_sidetray";  	LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); +    LLFloater *floater = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("people"); +    if (!floater->isFrontmost()) +    { +        floater->setVisibleAndFrontmost(TRUE, params); +    }  }  void LLGroupActions::refresh_notices() diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index fc8179f3b4..a77b9b7839 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1888,7 +1888,8 @@ void LLItemBridge::buildDisplayName() const  	LLStringUtil::toUpper(mSearchableName);  	//Name set, so trigger a sort -	if(mParent) +    LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); +	if(mParent && !sorter.isByDate())  	{  		mParent->requestSort();  	} @@ -2187,7 +2188,8 @@ void LLFolderBridge::buildDisplayName() const  	LLStringUtil::toUpper(mSearchableName);      //Name set, so trigger a sort -    if(mParent) +    LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); +    if(mParent && sorter.isFoldersByName())      {          mParent->requestSort();      } @@ -3420,9 +3422,22 @@ void LLFolderBridge::copyOutfitToClipboard()  void LLFolderBridge::openItem()  {  	LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL; -	LLInventoryModel* model = getInventoryModel(); -	if(!model) return; -	if(mUUID.isNull()) return; + +    LLInventoryPanel* panel = mInventoryPanel.get(); +    if (!panel) +    { +        return; +    } +    LLInventoryModel* model = getInventoryModel(); +    if (!model) +    { +        return; +    } +    if (mUUID.isNull()) +    { +        return; +    } +    panel->onFolderOpening(mUUID);  	bool fetching_inventory = model->fetchDescendentsOf(mUUID);  	// Only change folder type if we have the folder contents.  	if (!fetching_inventory) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 28db6a5808..6e30a31e6d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include <typeinfo> +#include <random>  #include "llinventorymodel.h" @@ -67,6 +68,9 @@  #include "process.h"  #endif +#include <algorithm> +#include <boost/algorithm/string/join.hpp> +  // Increment this if the inventory contents change in a non-backwards-compatible way.  // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.  const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -129,6 +133,54 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  }  ///---------------------------------------------------------------------------- +/// Class LLInventoryValidationInfo +///---------------------------------------------------------------------------- +LLInventoryValidationInfo::LLInventoryValidationInfo(): +	mFatalErrorCount(0), +	mWarningCount(0), +	mInitialized(false) +{ +} + +void LLInventoryValidationInfo::toOstream(std::ostream& os) const +{ +	os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; +} + + +std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) +{ +	v.toOstream(os); +	return os; +} + +void LLInventoryValidationInfo::asLLSD(LLSD& sd) const +{ +	sd["fatal_error_count"] = mFatalErrorCount; +	sd["warning_count"] = mWarningCount; +	sd["initialized"] = mInitialized; +	sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); +	if (mMissingRequiredSystemFolders.size()>0) +	{ +		sd["missing_system_folders"] = LLSD::emptyArray(); +		for(auto ft: mMissingRequiredSystemFolders) +		{ +			sd["missing_system_folders"].append(LLFolderType::lookup(ft));  +		} +	} +	sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); +	if (mDuplicateRequiredSystemFolders.size()>0) +	{ +		sd["duplicate_system_folders"] = LLSD::emptyArray(); +		for(auto ft: mDuplicateRequiredSystemFolders) +		{ +			sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); +		} +	} +	 +} + +///----------------------------------------------------------------------------  /// Class LLInventoryModel  ///---------------------------------------------------------------------------- @@ -160,7 +212,8 @@ LLInventoryModel::LLInventoryModel()  	mHttpPriorityFG(0),  	mHttpPriorityBG(0),  	mCategoryLock(), -	mItemLock() +	mItemLock(), +	mValidationInfo(new LLInventoryValidationInfo)  {} @@ -499,12 +552,18 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(  		}  	} -	if(rv.isNull() && isInventoryUsable() && create_folder) +	if(rv.isNull() && create_folder && root_id.notNull())  	{ -		if(root_id.notNull()) + +		if (isInventoryUsable())  		{  			return createNewCategory(root_id, preferred_type, LLStringUtil::null);  		} +		else +		{ +			LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type +								  << " because inventory is not usable" << LL_ENDL; +		}  	}  	return rv;  } @@ -568,20 +627,30 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  										   const std::string& pname,  										   inventory_func_type callback)  { -	  	LLUUID id; -	if(!isInventoryUsable()) +	if (!isInventoryUsable())  	{ -		LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; +		LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " +						  << preferred_type << LL_ENDL; +		// FIXME failing but still returning an id?  		return id;  	}  	if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())  	{  		LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; +		// FIXME failing but still returning an id?  		return id;  	} +	if (preferred_type != LLFolderType::FT_NONE) +	{ +		// Ultimately this should only be done for non-singleton +		// types. Requires back-end changes to guarantee that others +		// already exist. +		LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; +	} +  	id.generate();  	std::string name = pname;  	if(!pname.empty()) @@ -611,7 +680,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  		request["message"] = "CreateInventoryCategory";  		request["payload"] = body; -		LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; +		LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL;          LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",              boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); @@ -623,6 +692,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  		return LLUUID::null;  	} +	// FIXME this UDP code path needs to be removed. Requires +	// reworking many of the callers to use callbacks rather than +	// assuming instant success. +  	// Add the category to the internal representation  	LLPointer<LLViewerInventoryCategory> cat =  		new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); @@ -632,6 +705,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	accountForUpdate(update);  	updateCategory(cat); +	LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL; +  	// Create the category on the server. We do this to prevent people  	// from munging their protected folders.  	LLMessageSystem* msg = gMessageSystem; @@ -2247,11 +2322,11 @@ bool LLInventoryModel::loadSkeleton(  					}  				} - 				LL_INFOS(LOG_INV) << "Attempted to add " << bad_link_count -								  << " cached link items without baseobj present. " -								  << good_link_count << " link items were successfully added. " -								  << recovered_link_count << " links added in recovery. " -								  << "The corresponding categories were invalidated." << LL_ENDL; + 				LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count +								   << " cached link items without baseobj present. " +								   << good_link_count << " link items were successfully added. " +								   << recovered_link_count << " links added in recovery. " +								   << "The corresponding categories were invalidated." << LL_ENDL;  			}  		} @@ -2277,7 +2352,10 @@ bool LLInventoryModel::loadSkeleton(  			cat->setVersion(NO_VERSION);  			LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL;  		} -		LL_INFOS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; +		if (invalid_categories.size() > 0) +		{ +			LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; +		}  		// At this point, we need to set the known descendents for each  		// category which successfully cached so that we do not @@ -2565,10 +2643,22 @@ void LLInventoryModel::buildParentChildMap()  				}  			} -			// 'My Inventory', -			// root of the agent's inv found. -			// The inv tree is built. -			mIsAgentInvUsable = true; +			LLPointer<LLInventoryValidationInfo> validation_info = validate(); +			if (validation_info->mFatalErrorCount > 0) +			{ +				// Fatal inventory error. Will not be able to engage in many inventory operations. +				// This should be followed by an error dialog leading to logout. +				LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " +									  << "Will not be able to do normal inventory operations in this session." +									  << LL_ENDL; +				mIsAgentInvUsable = false; +			} +			else +			{ +				mIsAgentInvUsable = true; +			} +			validation_info->mInitialized = true; +			mValidationInfo = validation_info;  			// notifyObservers() has been moved to  			// llstartup/idle_startup() after this func completes. @@ -2576,11 +2666,6 @@ void LLInventoryModel::buildParentChildMap()  			// observers start firing.  		}  	} - -	if (!gInventory.validate()) -	{ -	 	LL_WARNS(LOG_INV) << "model failed validity check!" << LL_ENDL; -	}  }  // Would normally do this at construction but that's too early @@ -3702,56 +3787,68 @@ void LLInventoryModel::dumpInventory() const  }  // Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. -bool LLInventoryModel::validate() const +// returning an overall good/bad flag.  +LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const  { -	bool valid = true; +	LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; +	S32 fatalities = 0; +	S32 warnings = 0;  	if (getRootFolderID().isNull())  	{ -		LL_WARNS() << "no root folder id" << LL_ENDL; -		valid = false; +		LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; +		fatalities++;  	}  	if (getLibraryRootFolderID().isNull())  	{ -		LL_WARNS() << "no root folder id" << LL_ENDL; -		valid = false; +		LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; +		fatalities++;  	}  	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())  	{  		// ParentChild should be one larger because of the special entry for null uuid. -		LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() -				<< " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; -		valid = false; +		LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() +							  << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; +		warnings++;  	}  	S32 cat_lock = 0;  	S32 item_lock = 0;  	S32 desc_unknown_count = 0;  	S32 version_unknown_count = 0; + +	typedef std::map<LLFolderType::EType, S32> ft_count_map; +	ft_count_map ft_counts_under_root; +	ft_count_map ft_counts_elsewhere; +	 +	// Loop over all categories and check.  	for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)  	{  		const LLUUID& cat_id = cit->first;  		const LLViewerInventoryCategory *cat = cit->second;  		if (!cat)  		{ -			LL_WARNS() << "invalid cat" << LL_ENDL; -			valid = false; +			LL_WARNS("Inventory") << "null cat" << LL_ENDL; +			warnings++;  			continue;  		} +		LLUUID topmost_ancestor_id; +		// Will leave as null uuid on failure +		getObjectTopmostAncestor(cat_id, topmost_ancestor_id);  		if (cat_id != cat->getUUID())  		{ -			LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; -			valid = false; +			LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; +			warnings++;  		}  		if (cat->getParentUUID().isNull())  		{  			if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID())  			{ -				LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" -						<< getRootFolderID() << ") or library root (" -						<< getLibraryRootFolderID() << ")" << LL_ENDL; +				LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" +									  << getRootFolderID() << ") or library root (" +									  << getLibraryRootFolderID() << ")" << LL_ENDL; +				warnings++;  			}  		}  		cat_array_t* cats; @@ -3759,8 +3856,8 @@ bool LLInventoryModel::validate() const  		getDirectDescendentsOf(cat_id,cats,items);  		if (!cats || !items)  		{ -			LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; -			valid = false; +			LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; +			warnings++;  			continue;  		}  		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) @@ -3769,22 +3866,29 @@ bool LLInventoryModel::validate() const  		}  		else if (cats->size() + items->size() != cat->getDescendentCount())  		{ -			LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() -					<< "] parent " << cat->getParentUUID() -					<< " cached " << cat->getDescendentCount() -					<< " expected " << cats->size() << "+" << items->size() -					<< "=" << cats->size() +items->size() << LL_ENDL; -			valid = false; +			// In the case of library this is not unexpected, since +			// different user accounts may be getting the library +			// contents from different inventory hosts. +			if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) +			{ +				LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" +									  << " cached " << cat->getDescendentCount() +									  << " expected " << cats->size() << "+" << items->size() +									  << "=" << cats->size() +items->size() << LL_ENDL; +				warnings++; +			}  		}  		if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)  		{  			version_unknown_count++;  		} -		if (mCategoryLock.count(cat_id)) +		auto cat_lock_it = mCategoryLock.find(cat_id); +		if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second)  		{  			cat_lock++;  		} -		if (mItemLock.count(cat_id)) +		auto item_lock_it = mItemLock.find(cat_id); +		if (item_lock_it != mItemLock.end() && item_lock_it->second)  		{  			item_lock++;  		} @@ -3794,8 +3898,8 @@ bool LLInventoryModel::validate() const  			if (!item)  			{ -				LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; -				valid = false; +				LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; +				warnings++;  				continue;  			} @@ -3803,10 +3907,10 @@ bool LLInventoryModel::validate() const  			if (item->getParentUUID() != cat_id)  			{ -				LL_WARNS() << "wrong parent for " << item_id << " found " -						<< item->getParentUUID() << " expected " << cat_id -						<< LL_ENDL; -				valid = false; +				LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " +									  << item->getParentUUID() << " expected " << cat_id +									  << LL_ENDL; +				warnings++;  			} @@ -3814,17 +3918,17 @@ bool LLInventoryModel::validate() const  			item_map_t::const_iterator it = mItemMap.find(item_id);  			if (it == mItemMap.end())  			{ -				LL_WARNS() << "item " << item_id << " found as child of " -						<< cat_id << " but not in top level mItemMap" << LL_ENDL; -				valid = false; +				LL_WARNS("Inventory") << "item " << item_id << " found as child of " +									  << cat_id << " but not in top level mItemMap" << LL_ENDL; +				warnings++;  			}  			else  			{  				LLViewerInventoryItem *top_item = it->second;  				if (top_item != item)  				{ -					LL_WARNS() << "item mismatch, item_id " << item_id -							<< " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; +					LL_WARNS("Inventory") << "item mismatch, item_id " << item_id +										  << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL;  				}  			} @@ -3833,19 +3937,19 @@ bool LLInventoryModel::validate() const  			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);  			if (!found)  			{ -				LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; -				valid = false; +				LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; +				warnings++;  			}  			else  			{  				if (topmost_ancestor_id != getRootFolderID() &&  					topmost_ancestor_id != getLibraryRootFolderID())  				{ -					LL_WARNS() << "unrecognized top level ancestor for " << item_id -							<< " got " << topmost_ancestor_id -							<< " expected " << getRootFolderID() -							<< " or " << getLibraryRootFolderID() << LL_ENDL; -					valid = false; +					LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id +										  << " got " << topmost_ancestor_id +										  << " expected " << getRootFolderID() +										  << " or " << getLibraryRootFolderID() << LL_ENDL; +					warnings++;  				}  			}  		} @@ -3859,9 +3963,9 @@ bool LLInventoryModel::validate() const  			getDirectDescendentsOf(parent_id,cats,items);  			if (!cats)  			{ -				LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() -						<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; -				valid = false; +				LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() +									  << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; +				warnings++;  			}  			else  			{ @@ -3877,27 +3981,56 @@ bool LLInventoryModel::validate() const  				}  				if (!found)  				{ -					LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() -							<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; +					LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() +										  << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; +				} +			} +		} + +		// Update count of preferred types +		LLFolderType::EType folder_type = cat->getPreferredType(); +		bool cat_is_in_library = false; +		LLUUID topmost_id; +		if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID()) +		{ +			cat_is_in_library = true; +		} +		if (!cat_is_in_library) +		{ +			if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) +			{ +				ft_counts_under_root[folder_type]++; +				if (folder_type != LLFolderType::FT_NONE) +				{ +					LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; +				} +			} +			else +			{ +				ft_counts_elsewhere[folder_type]++; +				if (folder_type != LLFolderType::FT_NONE) +				{ +					LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL;  				}  			}  		}  	} +	// Loop over all items and check  	for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)  	{  		const LLUUID& item_id = iit->first;  		LLViewerInventoryItem *item = iit->second;  		if (item->getUUID() != item_id)  		{ -			LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; -			valid = false; +			LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; +			warnings++;  		}  		const LLUUID& parent_id = item->getParentUUID();  		if (parent_id.isNull())  		{ -			LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; +			LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL;  		}  		else  		{ @@ -3906,8 +4039,8 @@ bool LLInventoryModel::validate() const  			getDirectDescendentsOf(parent_id,cats,items);  			if (!items)  			{ -				LL_WARNS() << "item " << item_id << " name [" << item->getName() -						<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; +				LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() +									  << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL;  			}  			else  			{ @@ -3922,8 +4055,8 @@ bool LLInventoryModel::validate() const  				}  				if (!found)  				{ -					LL_WARNS() << "item " << item_id << " name [" << item->getName() -							<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; +					LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() +										  << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL;  				}  			} @@ -3938,30 +4071,30 @@ bool LLInventoryModel::validate() const  			// Linked-to UUID should have back reference to this link.  			if (!hasBacklinkInfo(link_id, target_id))  			{ -				LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() -						<< " missing backlink info at target_id " << target_id -						<< LL_ENDL; +				LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() +									  << " missing backlink info at target_id " << target_id +									  << LL_ENDL;  			}  			// Links should have referents.  			if (item->getActualType() == LLAssetType::AT_LINK && !target_item)  			{ -				LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +				LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL;  			}  			else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat)  			{ -				LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +				LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL;  			}  			if (target_item && target_item->getIsLinkType())  			{ -				LL_WARNS() << "link " << item->getName() << " references a link item " -						<< target_item->getName() << " " << target_item->getUUID() << LL_ENDL; +				LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " +									  << target_item->getName() << " " << target_item->getUUID() << LL_ENDL;  			}  			// Links should not have backlinks.  			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id);  			if (range.first != range.second)  			{ -				LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; +				LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL;  			}  		}  		else @@ -3975,29 +4108,116 @@ bool LLInventoryModel::validate() const  				LLViewerInventoryItem *link_item = getItem(link_id);  				if (!link_item || !link_item->getIsLinkType())  				{ -					LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; +					LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL;  				}  			}  		}  	} -	 + +	// Check system folders +	for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) +	{ +		LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; +	} +	for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) +	{ +		LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; +	} + +	static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); +	static std::default_random_engine e{}; +    static std::uniform_int_distribution<> distrib(0, 1); +	for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) +	{ +		LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); +		if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) +		{ +			continue; +		} +		bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); +		bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); +		S32 count_under_root = ft_counts_under_root[folder_type]; +		S32 count_elsewhere = ft_counts_elsewhere[folder_type]; +		if (fake_system_folder_issues) +		{ +			// Force all counts to be either 0 or 2, thus flagged as an error. +			count_under_root = 2*distrib(e);  +			count_elsewhere = 2*distrib(e); +		} +		if (is_singleton) +		{ +			if (count_under_root==0) +			{ +				LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; +				// Need to create, if allowed. +				if (is_automatic) +				{ +					LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; +					fatalities++; +					validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft)); +				} +				else +				{ +					// Can create, and will when needed. +					warnings++; +				} +			} +			else if (count_under_root > 1) +			{ +				LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; +				validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft)); +				fatalities++; +			} +			if (count_elsewhere > 0) +			{ +				LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; +				warnings++; +			} +		} +	} + +  	if (cat_lock > 0 || item_lock > 0)  	{ -		LL_INFOS() << "Found locks on some categories: sub-cat arrays " +		LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays "  				<< cat_lock << ", item arrays " << item_lock << LL_ENDL;  	}  	if (desc_unknown_count != 0)  	{ -		LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL;  +		LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL;   	}  	if (version_unknown_count != 0)  	{ -		LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; +		LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL;  	} -	LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; +	// FIXME need to fail login and tell user to retry, contact support if problem persists. +	bool valid = (fatalities == 0); +	LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; + +	validation_info->mFatalErrorCount = fatalities; +	validation_info->mWarningCount = warnings; -	return valid; +	return validation_info;  +} + +// Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" +std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const +{ +	std::vector<std::string> path_elts; +	std::map<LLUUID,bool> visited; +	while (obj != NULL && !visited[obj->getUUID()]) +	{ +		path_elts.push_back(obj->getName()); +		// avoid infinite loop in the unlikely event of a cycle +		visited[obj->getUUID()] = true; +		obj = getObject(obj->getParentUUID()); +	} +	std::stringstream s; +	std::string delim("/"); +	std::reverse(path_elts.begin(), path_elts.end()); +	std::string result = "/" + boost::algorithm::join(path_elts, delim); +	return result;  }  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a4326aaeed..bddaf3a147 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -55,7 +55,26 @@ class LLInventoryCategory;  class LLMessageSystem;  class LLInventoryCollectFunctor; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///---------------------------------------------------------------------------- +/// LLInventoryValidationInfo  +///---------------------------------------------------------------------------- +class LLInventoryValidationInfo: public LLRefCount +{ +public: +	LLInventoryValidationInfo(); +	void toOstream(std::ostream& os) const; +	void asLLSD(LLSD& sd) const; +	 + +	S32 mFatalErrorCount; +	S32 mWarningCount; +	bool mInitialized; +	std::set<LLFolderType::EType> mMissingRequiredSystemFolders; +	std::set<LLFolderType::EType> mDuplicateRequiredSystemFolders; +}; +std::ostream& operator<<(std::ostream& s, const LLInventoryValidationInfo& v); + +///----------------------------------------------------------------------------  // LLInventoryModel  //  // Represents a collection of inventory, and provides efficient ways to access  @@ -63,7 +82,7 @@ class LLInventoryCollectFunctor;  //   NOTE: This class could in theory be used for any place where you need   //   inventory, though it optimizes for time efficiency - not space efficiency,   //   probably making it inappropriate for use on tasks. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///----------------------------------------------------------------------------  class LLInventoryModel  {  	LOG_CLASS(LLInventoryModel); @@ -656,7 +675,9 @@ private:  	//--------------------------------------------------------------------  public:  	void dumpInventory() const; -	bool validate() const; +	LLPointer<LLInventoryValidationInfo> validate() const; +	LLPointer<LLInventoryValidationInfo> mValidationInfo; +	std::string getFullPath(const LLInventoryObject *obj) const;  /**                    Miscellaneous   **                                                                            ** diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 3608f9e23f..288da1cac7 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -283,17 +283,18 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)  	mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));  	mInventory->addObserver(mCompletionObserver); -    if (mBuildViewsOnInit) +    if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED)      {          // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.          // Initializing views takes a while so always do it onIdle if viewer already loaded. -        if (mInventory->isInventoryUsable() -            && mViewsInitialized == VIEWS_UNINITIALIZED +        if (mInventory->isInventoryUsable()                          && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)          { -            initializeViews(); +            // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect +            const F64 max_time = 20.f; +            initializeViews(max_time);          } -        else if (mViewsInitialized != VIEWS_INITIALIZING) +        else          {              mViewsInitialized = VIEWS_INITIALIZING;              gIdleCallbacks.addFunction(onIdle, (void*)this); @@ -498,6 +499,19 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve  		view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);  	} +    // if folder is not fully initialized (likely due to delayed load on idle) +    // and we are not rebuilding, try updating children +    if (view_folder +        && !view_folder->areChildrenInited() +        && ( (mask & LLInventoryObserver::REBUILD) == 0)) +    { +        LLInventoryObject const* objectp = mInventory->getObject(item_id); +        if (objectp) +        { +            view_item = buildNewViews(item_id, objectp, view_item, BUILD_ONE_FOLDER); +        } +    } +  	//////////////////////////////  	// LABEL Operation  	// Empty out the display name for relabel. @@ -538,7 +552,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve          if (objectp)          {              // providing NULL directly avoids unnessesary getItemByID calls -            view_item = buildNewViews(item_id, objectp, NULL); +            view_item = buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);          }          else          { @@ -591,7 +605,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve              if (objectp)              {                  // providing NULL directly avoids unnessesary getItemByID calls -                buildNewViews(item_id, objectp, NULL); +                buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);              }  			// Select any newly created object that has the auto rename at top of folder root set. @@ -743,12 +757,12 @@ void LLInventoryPanel::onIdle(void *userdata)  		return;  	LLInventoryPanel *self = (LLInventoryPanel*)userdata; -	// Inventory just initialized, do complete build -	if (self->mViewsInitialized != VIEWS_INITIALIZED) +	if (self->mViewsInitialized <= VIEWS_INITIALIZING)  	{ -		self->initializeViews(); +		const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders +		self->initializeViews(max_time); // Shedules LLInventoryPanel::idle()  	} -	if (self->mViewsInitialized == VIEWS_INITIALIZED) +	if (self->mViewsInitialized >= VIEWS_BUILDING)  	{  		gIdleCallbacks.deleteFunction(onIdle, (void*)self);  	} @@ -783,6 +797,49 @@ void LLInventoryPanel::idle(void* user_data)  	} +    bool in_visible_chain = panel->isInVisibleChain(); + +    if (!panel->mBuildViewsQueue.empty()) +    { +        const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms +        F64 curent_time = LLTimer::getTotalSeconds(); +        panel->mBuildViewsEndTime = curent_time + max_time; + +        // things added last are closer to root thus of higher priority +        std::deque<LLUUID> priority_list; +        priority_list.swap(panel->mBuildViewsQueue); + +        while (curent_time < panel->mBuildViewsEndTime +            && !priority_list.empty()) +        { +            LLUUID item_id = priority_list.back(); +            priority_list.pop_back(); + +            LLInventoryObject const* objectp = panel->mInventory->getObject(item_id); +            if (objectp && panel->typedViewsFilter(item_id, objectp)) +            { +                LLFolderViewItem* folder_view_item = panel->getItemByID(item_id); +                if (!folder_view_item || !folder_view_item->areChildrenInited()) +                { +                    const LLUUID &parent_id = objectp->getParentUUID(); +                    LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id); +                    panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT); +                } +            } +            curent_time = LLTimer::getTotalSeconds(); +        } +        while (!priority_list.empty()) +        { +            // items in priority_list are of higher priority +            panel->mBuildViewsQueue.push_back(priority_list.front()); +            priority_list.pop_front(); +        } +        if (panel->mBuildViewsQueue.empty()) +        { +            panel->mViewsInitialized = VIEWS_INITIALIZED; +        } +    } +      // Take into account the fact that the root folder might be invalidated      if (panel->mFolderRoot.get())      { @@ -813,10 +870,16 @@ void LLInventoryPanel::idle(void* user_data)  } -void LLInventoryPanel::initializeViews() +void LLInventoryPanel::initializeViews(F64 max_time)  {  	if (!gInventory.isInventoryUsable()) return; +    mViewsInitialized = VIEWS_BUILDING; + +    F64 curent_time = LLTimer::getTotalSeconds(); +    mBuildViewsEndTime = curent_time + max_time; + +	// init everything  	LLUUID root_id = getRootFolderID();  	if (root_id.notNull())  	{ @@ -824,14 +887,18 @@ void LLInventoryPanel::initializeViews()  	}  	else  	{ -		// Default case: always add "My Inventory" first, "Library" second +		// Default case: always add "My Inventory" root first, "Library" root second +		// If we run out of time, this still should create root folders  		buildNewViews(gInventory.getRootFolderID());		// My Inventory  		buildNewViews(gInventory.getLibraryRootFolderID());	// Library  	} -	gIdleCallbacks.addFunction(idle, this); +    if (mBuildViewsQueue.empty()) +    { +        mViewsInitialized = VIEWS_INITIALIZED; +    } -	mViewsInitialized = VIEWS_INITIALIZED; +	gIdleCallbacks.addFunction(idle, this);  	openStartFolderOrMyInventory(); @@ -910,10 +977,13 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO      LLFolderViewItem* folder_view_item = getItemByID(id);      LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); -    return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); +    return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT);  } -LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item) +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, +                                                  LLInventoryObject const* objectp, +                                                  LLFolderViewItem *folder_view_item, +                                                  const EBuildModes &mode)  {      if (!objectp)      { @@ -928,14 +998,15 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO      const LLUUID &parent_id = objectp->getParentUUID();      LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); -    return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); +    return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, mode);  }  LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,                                                    const LLUUID& parent_id,                                                    LLInventoryObject const* objectp,                                                    LLFolderViewItem *folder_view_item, -                                                  LLFolderViewFolder *parent_folder) +                                                  LLFolderViewFolder *parent_folder, +                                                  const EBuildModes &mode)  {      // Force the creation of an extra root level folder item if required by the inventory panel (default is "false")      bool allow_drop = true; @@ -1036,9 +1107,64 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,          }  	} +    bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY; + +    if (create_children) +    { +        switch (mode) +        { +            case BUILD_TIMELIMIT: +            { +                F64 curent_time = LLTimer::getTotalSeconds(); +                // If function is out of time, we want to shedule it into mBuildViewsQueue +                // If we have time, no matter how little, create views for all children +                // +                // This creates children in 'bulk' to make sure folder has either +                // 'empty and incomplete' or 'complete' states with nothing in between. +                // Folders are marked as mIsFolderComplete == false by default, +                // later arrange() will update mIsFolderComplete by child count +                if (mBuildViewsEndTime < curent_time) +                { +                    create_children = false; +                    // run it again for the sake of creating children +                    mBuildViewsQueue.push_back(id); +                } +                else +                { +                    create_children = true; +                    folder_view_item->setChildrenInited(true); +                } +                break; +            } +            case BUILD_NO_CHILDREN: +            { +                create_children = false; +                // run it to create children, current caller is only interested in current view +                mBuildViewsQueue.push_back(id); +                break; +            } +            case BUILD_ONE_FOLDER: +            { +                // This view loads chindren, following ones don't +                // Note: Might be better idea to do 'depth' instead, +                // It also will help to prioritize root folder's content +                create_children = true; +                folder_view_item->setChildrenInited(true); +                break; +            } +            case BUILD_NO_LIMIT: +            default: +            { +                // keep working till everything exists +                create_children = true; +                folder_view_item->setChildrenInited(true); +            } +        } +    } +  	// If this is a folder, add the children of the folder and recursively add any   	// child folders. -	if (folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY) +	if (create_children)  	{  		LLViewerInventoryCategory::cat_array_t* categories;  		LLViewerInventoryItem::item_array_t* items; @@ -1054,7 +1180,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,  				 ++cat_iter)  			{  				const LLViewerInventoryCategory* cat = (*cat_iter); -                if (typedViewsFilter(cat->getUUID(), cat)) +                if (typedViewsFilter(cat->getUUID(), cat))                   {                      if (has_folders)                      { @@ -1062,11 +1188,11 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,                          // each time, especially since content is growing, we can just                          // iter over copy of mItemMap in some way                          LLFolderViewItem* view_itemp = getItemByID(cat->getUUID()); -                        buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp); +                        buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));                      }                      else                      { -                        buildViewsTree(cat->getUUID(), id, cat, NULL, parentp); +                        buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode));                      }                  }  			} @@ -1078,17 +1204,16 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,  				 item_iter != items->end();  				 ++item_iter)  			{ +                // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime  				const LLViewerInventoryItem* item = (*item_iter);                  if (typedViewsFilter(item->getUUID(), item))                  { -                      // This can be optimized: we don't need to call getItemByID()                      // each time, especially since content is growing, we can just                      // iter over copy of mItemMap in some way                      LLFolderViewItem* view_itemp = getItemByID(item->getUUID()); -                    buildViewsTree(item->getUUID(), id, item, view_itemp, parentp); +                    buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode);                  } -  			}  		}  		mInventory->unlockDirectDescendentArrays(id); @@ -1201,6 +1326,18 @@ void LLInventoryPanel::onFocusReceived()  	LLPanel::onFocusReceived();  } +void LLInventoryPanel::onFolderOpening(const LLUUID &id) +{ +    LLFolderViewItem* folder = getItemByID(id); +    if (folder && !folder->areChildrenInited()) +    { +        // Last item in list will be processed first. +        // This might result in dupplicates in list, but it +        // isn't critical, views won't be created twice +        mBuildViewsQueue.push_back(id); +    } +} +  bool LLInventoryPanel::addBadge(LLBadge * badge)  {  	bool badge_added = false; @@ -1222,7 +1359,7 @@ void LLInventoryPanel::openAllFolders()  void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus)  {  	// Don't select objects in COF (e.g. to prevent refocus when items are worn). -	const LLInventoryObject *obj = gInventory.getObject(obj_id); +	const LLInventoryObject *obj = mInventory->getObject(obj_id);  	if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())  	{  		return; @@ -1259,6 +1396,12 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it  		if (view_model)  		{  			LLUUID id = view_model->getUUID(); +            if (!(*it)->areChildrenInited()) +            { +                const F64 max_time = 0.0001f; +                mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time; +                buildNewViews(id); +            }  			LLViewerInventoryItem* inv_item = mInventory->getItem(id);  			if (inv_item && !inv_item->isFinished()) @@ -1716,7 +1859,17 @@ LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id)  void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL    take_keyboard_focus )  {  	LLFolderViewItem* itemp = getItemByID(obj_id); -	if(itemp && itemp->getViewModelItem() && itemp->passedFilter()) + +    if (itemp && !itemp->areChildrenInited()) +    { +        LLInventoryObject const* objectp = mInventory->getObject(obj_id); +        if (objectp) +        { +            buildNewViews(obj_id, objectp, itemp, BUILD_ONE_FOLDER); +        } +    } + +	if(itemp && itemp->getViewModelItem())  	{  		itemp->arrangeAndSet(TRUE, take_keyboard_focus);  		mSelectThisID.setNull(); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index a019fc2231..552c61b915 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -171,6 +171,7 @@ public:  	// LLUICtrl methods  	 /*virtual*/ void onFocusLost();  	 /*virtual*/ void onFocusReceived(); +     void onFolderOpening(const LLUUID &id);  	// LLBadgeHolder methods  	bool addBadge(LLBadge * badge); @@ -318,12 +319,9 @@ private:  	//--------------------------------------------------------------------  public:  	void addHideFolderType(LLFolderType::EType folder_type); - -public: -	bool getViewsInitialized() const { return mViewsInitialized == VIEWS_INITIALIZED; }  protected:  	// Builds the UI.  Call this once the inventory is usable. -	void 				initializeViews(); +	void 				initializeViews(F64 max_time);  	// Specific inventory colors  	static bool                 sColorSetInitialized; @@ -331,13 +329,25 @@ protected:  	static LLUIColor			sDefaultHighlightColor;  	static LLUIColor			sLibraryColor;  	static LLUIColor			sLinkColor; -	 + +    enum EBuildModes +    { +        BUILD_NO_LIMIT, +        BUILD_TIMELIMIT, // requires mBuildViewsEndTime +        BUILD_ONE_FOLDER, +        BUILD_NO_CHILDREN, +    }; + +    // All buildNewViews() use BUILD_TIMELIMIT by default +    // and expect time limit mBuildViewsEndTime to be set  	LLFolderViewItem*			buildNewViews(const LLUUID& id);      LLFolderViewItem*			buildNewViews(const LLUUID& id,                                                LLInventoryObject const* objectp);      LLFolderViewItem*			buildNewViews(const LLUUID& id,                                                LLInventoryObject const* objectp, -                                              LLFolderViewItem *target_view); +                                              LLFolderViewItem *target_view, +                                              const EBuildModes &mode = BUILD_TIMELIMIT); +      // if certain types are not allowed, no reason to create views      virtual bool				typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) { return true; } @@ -354,17 +364,21 @@ private:                                                const LLUUID& parent_id,                                                LLInventoryObject const* objectp,                                                LLFolderViewItem *target_view, -                                              LLFolderViewFolder *parent_folder_view); +                                              LLFolderViewFolder *parent_folder_view, +                                              const EBuildModes &mode);      typedef enum e_views_initialization_state      {          VIEWS_UNINITIALIZED = 0,          VIEWS_INITIALIZING, +        VIEWS_BUILDING, // Root folder exists          VIEWS_INITIALIZED,      } EViewsInitializationState;  	bool						mBuildViewsOnInit;      EViewsInitializationState	mViewsInitialized; // Whether views have been generated +    F64							mBuildViewsEndTime; // Stop building views past this timestamp +    std::deque<LLUUID>			mBuildViewsQueue;  };  /************************************************************************/ diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index b6107eeedf..b5ac94b1cd 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -619,74 +619,11 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)          }      } -#if 1 -    // Legacy support -    // Remove #if-#endif section half a year after DRTVWR-501 releases. -    // Update legacy settings in settings.xml -    // We only care for third person view since legacy settings can't store -    // more than one mode. -    // We are saving this even if we are in temporary mode - preferences -    // will restore values on cancel -    if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) -    { -        bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE); -        gSavedSettings.setBOOL("DoubleClickAutoPilot", value); - -        value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE); -        gSavedSettings.setBOOL("ClickToWalk", value); - -        // new method can save both toggle and push-to-talk values simultaneously, -        // but legacy one can save only one. It also doesn't support mask. -        LLKeyData data = getControl("toggle_voice", 0); -        bool can_toggle = !data.isEmpty(); -        if (!can_toggle) -        { -            data = getControl("voice_follow_key", 0); -        } - -        gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); -        if (data.isEmpty()) -        { -            // legacy viewer has a bug that might crash it if NONE value is assigned. -            // just reset to default -            gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false); -        } -        else -        { -            if (data.mKey != KEY_NONE) -            { -                gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey)); -            } -            else -            { -                std::string ctrl_value; -                switch (data.mMouse) -                { -                case CLICK_MIDDLE: -                    ctrl_value = "MiddleMouse"; -                    break; -                case CLICK_BUTTON4: -                    ctrl_value = "MouseButton4"; -                    break; -                case CLICK_BUTTON5: -                    ctrl_value = "MouseButton5"; -                    break; -                default: -                    ctrl_value = "MiddleMouse"; -                    break; -                } -                gSavedSettings.setString("PushToTalkButton", ctrl_value); -            } -        } -    } -#endif -      if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)      {          // Map floater should react to doubleclick if doubleclick for teleport is set -        // Todo: Seems conterintuitive for map floater to share inworld controls -        // after these changes release, discuss with UI UX engineer if this should just -        // be set to 1 by default (before release this also doubles as legacy support) +        // Todo: Seems conterintuitive for map floater to share inworld controls, +        // discuss with UI UX engineer if this should just be set to 1 by default          bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);          gSavedSettings.setBOOL("DoubleClickTeleport", value);      } diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index c63d04cd55..ab32ea3956 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -305,8 +305,11 @@ BOOL LLPanelGroupNotices::postBuild()  void LLPanelGroupNotices::activate()  { -	if(mNoticesList) -		mNoticesList->deleteAllItems(); +    if (mNoticesList) +    { +        mNoticesList->deleteAllItems(); +        mKnownNoticeIds.clear(); +    }  	mPrevSelectedNotice = LLUUID(); @@ -413,6 +416,7 @@ void LLPanelGroupNotices::onClickSendMessage(void* data)  	row["columns"][4]["value"] = llformat( "%u", timestamp);  	self->mNoticesList->addElement(row, ADD_BOTTOM); +	self->mKnownNoticeIds.insert(id);  	self->mCreateMessage->clear();  	self->mCreateSubject->clear(); @@ -443,27 +447,13 @@ void LLPanelGroupNotices::onClickNewMessage(void* data)  void LLPanelGroupNotices::refreshNotices()  {  	onClickRefreshNotices(this); -	/* -	LL_DEBUGS() << "LLPanelGroupNotices::onClickGetPastNotices" << LL_ENDL; -	 -	mNoticesList->deleteAllItems(); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessage("GroupNoticesListRequest"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID",gAgent.getID()); -	msg->addUUID("SessionID",gAgent.getSessionID()); -	msg->nextBlock("Data"); -	msg->addUUID("GroupID",self->mGroupID); -	gAgent.sendReliableMessage(); -	*/ -	  }  void LLPanelGroupNotices::clearNoticeList()  {  	mPrevSelectedNotice = mNoticesList->getStringUUIDSelectedItem();  	mNoticesList->deleteAllItems(); +	mKnownNoticeIds.clear();  }  void LLPanelGroupNotices::onClickRefreshNotices(void* data) @@ -541,13 +531,14 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)  			return;  		} -		//with some network delays we can receive notice list more then once... -		//so add only unique notices -		S32 pos = mNoticesList->getItemIndex(id); +        // Due to some network delays we can receive notice list more than once... +        // So add only unique notices +        if (mKnownNoticeIds.find(id) != mKnownNoticeIds.end()) +        { +            // If items with this ID already in the list - skip it +            continue; +        } -		if(pos!=-1)//if items with this ID already in the list - skip it -			continue; -			  		msg->getString("Data","Subject",subj,i);  		msg->getString("Data","FromName",name,i);  		msg->getBOOL("Data","HasAttachment",has_attachment,i); @@ -582,6 +573,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)  		row["columns"][4]["value"] = llformat( "%u", timestamp);  		mNoticesList->addElement(row, ADD_BOTTOM); +		mKnownNoticeIds.insert(id);  	}  	mNoticesList->setNeedsSort(save_sort); diff --git a/indra/newview/llpanelgroupnotices.h b/indra/newview/llpanelgroupnotices.h index 46c8c241c6..55319cb9ae 100644 --- a/indra/newview/llpanelgroupnotices.h +++ b/indra/newview/llpanelgroupnotices.h @@ -110,6 +110,7 @@ private:  	LLIconCtrl		 *mViewInventoryIcon;  	LLScrollListCtrl *mNoticesList; +    std::set<LLUUID>  mKnownNoticeIds; // Dupplicate avoidance, to avoid searching and inserting dupplciates into mNoticesList  	std::string		mNoNoticesStr; diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 880323ce16..834e664723 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -371,6 +371,11 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled)  	setFocus(TRUE);  } +void LLPanelLandmarkInfo::setCanEdit(BOOL enabled) +{ +    getChild<LLButton>("edit_btn")->setEnabled(enabled); +} +  const std::string& LLPanelLandmarkInfo::getLandmarkTitle() const  {  	return mLandmarkTitleEditor->getText(); diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h index f727f286b5..46e2a1935b 100644 --- a/indra/newview/llpanellandmarkinfo.h +++ b/indra/newview/llpanellandmarkinfo.h @@ -56,6 +56,7 @@ public:  	void displayItemInfo(const LLInventoryItem* pItem);  	void toggleLandmarkEditMode(BOOL enabled); +	void setCanEdit(BOOL enabled);  	const std::string& getLandmarkTitle() const;  	const std::string getLandmarkNotes() const; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 9c67ec40fe..69f181e1b3 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -469,10 +469,15 @@ void LLPanelPlaces::onOpen(const LLSD& key)  			{  				mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); -				LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); +				LLUUID id = key["id"].asUUID(); +				LLInventoryItem* item = gInventory.getItem(id);  				if (!item)  					return; +                BOOL is_editable = gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()) +                                   && item->getPermissions().allowModifyBy(gAgent.getID()); +                mLandmarkInfo->setCanEdit(is_editable); +  				setItem(item);  			}  			else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index b41aa2be1a..9ac15d1639 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -104,7 +104,7 @@ public:  	// llview  	/*virtual*/ void draw(); -	void refreshFromItem(); +	virtual void refreshFromItem();  	// We can't modify Item or description in preview if either in-world Object  	// or Item  itself is unmodifiable diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 12ac9e6fc5..97f1dcd5d0 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -35,14 +35,17 @@  #include "llkeyframemotion.h"  #include "llfilepicker.h"  #include "lllineeditor.h" +#include "lltrans.h"  #include "lluictrlfactory.h"  #include "lluictrlfactory.h"  #include "lldatapacker.h"  extern LLAgent gAgent; +const S32 ADVANCED_VPAD = 3;  LLPreviewAnim::LLPreviewAnim(const LLSD& key) -	: LLPreview( key ) +	: LLPreview( key ), +	pMotion(NULL)  {  	mCommitCallbackRegistrar.add("PreviewAnim.Play", boost::bind(&LLPreviewAnim::play, this, _2));  } @@ -50,20 +53,19 @@ LLPreviewAnim::LLPreviewAnim(const LLSD& key)  // virtual  BOOL LLPreviewAnim::postBuild()  { -	const LLInventoryItem* item = getItem(); -	if(item) -	{ -		gAgentAvatarp->createMotion(item->getAssetUUID()); // preload the animation -		getChild<LLUICtrl>("desc")->setValue(item->getDescription()); -	} -  	childSetCommitCallback("desc", LLPreview::onText, this);  	getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); +	getChild<LLTextBox>("adv_trigger")->setClickedCallback(boost::bind(&LLPreviewAnim::showAdvanced, this)); +	pAdvancedStatsTextBox = getChild<LLTextBox>("AdvancedStats"); + +    // Assume that advanced stats start visible (for XUI preview tool's purposes) +    pAdvancedStatsTextBox->setVisible(FALSE); +    LLRect rect = getRect(); +    reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE);  	return LLPreview::postBuild();  } -// static  // llinventorybridge also calls into here  void LLPreviewAnim::play(const LLSD& param)  { @@ -161,14 +163,28 @@ void LLPreviewAnim::draw()  }  // virtual +void LLPreviewAnim::refreshFromItem() +{ +    const LLInventoryItem* item = getItem(); +    if (!item) +    { +        return; +    } + +    // Preload motion +    pMotion = gAgentAvatarp->createMotion(item->getAssetUUID()); + +    LLPreview::refreshFromItem(); +} +  void LLPreviewAnim::cleanup()  {  	this->mItemID = LLUUID::null;  	this->mDidStart = false;  	getChild<LLUICtrl>("Inworld")->setValue(FALSE);  	getChild<LLUICtrl>("Locally")->setValue(FALSE); -	getChild<LLUICtrl>("Inworld")->setEnabled(true); -	getChild<LLUICtrl>("Locally")->setEnabled(true); +	getChild<LLUICtrl>("Inworld")->setEnabled(TRUE); +	getChild<LLUICtrl>("Locally")->setEnabled(TRUE);  }  // virtual @@ -182,3 +198,32 @@ void LLPreviewAnim::onClose(bool app_quitting)  		gAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP);  	}  } + +void LLPreviewAnim::showAdvanced() +{ +    BOOL was_visible =  pAdvancedStatsTextBox->getVisible(); + +    if (was_visible) +    { +        pAdvancedStatsTextBox->setVisible(FALSE); +        LLRect rect = getRect(); +        reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); +    } +    else +    { +        pAdvancedStatsTextBox->setVisible(TRUE); +        LLRect rect = getRect(); +        reshape(rect.getWidth(), rect.getHeight() + pAdvancedStatsTextBox->getRect().getHeight() + ADVANCED_VPAD, FALSE); + +        // set text +        if (pMotion) +        { +            pAdvancedStatsTextBox->setTextArg("[PRIORITY]", llformat("%d", pMotion->getPriority())); +            pAdvancedStatsTextBox->setTextArg("[DURATION]", llformat("%.2f", pMotion->getDuration())); +            pAdvancedStatsTextBox->setTextArg("[EASE_IN]", llformat("%.2f", pMotion->getEaseInDuration())); +            pAdvancedStatsTextBox->setTextArg("[EASE_OUT]", llformat("%.2f", pMotion->getEaseOutDuration())); +            pAdvancedStatsTextBox->setTextArg("[IS_LOOP]", (pMotion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); +            pAdvancedStatsTextBox->setTextArg("[NUM_JOINTS]", llformat("%d", pMotion->getNumJointMotions())); +        } +    } +} diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index 8eaed6ca1f..14cd53b500 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -30,21 +30,29 @@  #include "llpreview.h"  #include "llcharacter.h" +class LLMotion; +class LLTextBox; +  class LLPreviewAnim : public LLPreview  {  public:  	LLPreviewAnim(const LLSD& key); -	/*virtual*/	BOOL postBuild(); -	/*virtual*/ void onClose(bool app_quitting); -	void draw(); -	void cleanup(); +	BOOL postBuild() override; +	void onClose(bool app_quitting) override; +	void draw() override; +	void refreshFromItem() override; + +	void cleanup(); // cleanup 'playing' state  	void play(const LLSD& param); -	 +	void showAdvanced(); +  protected: -	LLUUID	mItemID; +	LLUUID	mItemID; // Not an item id, but a playing asset id  	bool	mDidStart; +	LLMotion* pMotion; +	LLTextBox* pAdvancedStatsTextBox;  };  #endif  // LL_LLPREVIEWANIM_H diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 4b36822e9a..74844a80e8 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -96,7 +96,7 @@ BOOL LLSetKeyBindDialog::postBuild()      getChild<LLUICtrl>("Cancel")->setFocus(TRUE);      pCheckBox = getChild<LLCheckBoxCtrl>("apply_all"); -    pDesription = getChild<LLTextBase>("descritption"); +    pDescription = getChild<LLTextBase>("description");      gFocusMgr.setKeystrokesOnly(TRUE); @@ -160,8 +160,8 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView*          }          input += getString("keyboard");      } -    pDesription->setText(getString("basic_description")); -    pDesription->setTextArg("[INPUT]", input); +    pDescription->setText(getString("basic_description")); +    pDescription->setTextArg("[INPUT]", input);  }  // static @@ -257,8 +257,8 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down)      if (LLKeyConflictHandler::isReservedByMenu(key, mask))      { -        pDesription->setText(getString("reserved_by_menu")); -        pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); +        pDescription->setText(getString("reserved_by_menu")); +        pDescription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));          mLastMaskKey = 0;          return true;      } diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h index a34b952233..461965720a 100644 --- a/indra/newview/llsetkeybinddialog.h +++ b/indra/newview/llsetkeybinddialog.h @@ -83,7 +83,7 @@ private:      void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);      LLKeyBindResponderInterface *pParent;      LLCheckBoxCtrl *pCheckBox; -    LLTextBase *pDesription; +    LLTextBase *pDescription;      U32 mKeyFilterMask;      Updater *pUpdater; diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index ea7e649792..a5dcdc41ed 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -653,7 +653,12 @@ bool LLSidepanelInventory::canWearSelected()  LLInventoryItem *LLSidepanelInventory::getSelectedItem()  { -	LLFolderViewItem* current_item = mPanelMainInventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); +    LLFolderView* root = mPanelMainInventory->getActivePanel()->getRootFolder(); +    if (!root) +    { +        return NULL; +    } +	LLFolderViewItem* current_item = root->getCurSelectedItem();  	if (!current_item)  	{ diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 1242131534..a9e94dd795 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -310,6 +310,13 @@ void update_texture_fetch()  	gTextureList.updateImages(0.10f);  } +bool finish_force_quit(const LLSD& notification, const LLSD& response) +{ +	LLAppViewer::instance()->forceQuit(); +	return false; +} + +  void set_flags_and_update_appearance()  {  	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); @@ -1827,6 +1834,17 @@ bool idle_startup()  		// This method MUST be called before gInventory.findCategoryUUIDForType because of   		// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.  		gInventory.buildParentChildMap(); + +		// If buildParentChildMap succeeded, inventory will now be in +		// a usable state and gInventory.isInventoryUsable() will be +		// true. + +		// if inventory is unusable, we need to bail out. +		if (!gInventory.isInventoryUsable()) +		{ +			LLNotificationsUtil::add("InventoryUnusable", LLSD(), LLSD(), &finish_force_quit ); +		} +		  		gInventory.createCommonSystemCategories();  		// It's debatable whether this flag is a good idea - sets all @@ -1859,6 +1877,7 @@ bool idle_startup()  		display_startup();  		LLStartUp::setStartupState( STATE_MISC );  		display_startup(); +  		return FALSE;  	} @@ -2148,7 +2167,10 @@ bool idle_startup()  		if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time))  		{ -			LLNotificationsUtil::add("ClothingLoading"); +			if (gInventory.isInventoryUsable()) +			{ +				LLNotificationsUtil::add("ClothingLoading"); +			}			  			record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time);  			LLStartUp::setStartupState( STATE_CLEANUP );  		} diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698..71986d21f9 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -73,7 +73,7 @@ BOOL LLToolFace::handleDoubleClick(S32 x, S32 y, MASK mask)  BOOL LLToolFace::handleMouseDown(S32 x, S32 y, MASK mask)  { -	gViewerWindow->pickAsync(x, y, mask, pickCallback); +	gViewerWindow->pickAsync(x, y, mask, pickCallback, false, gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"));  	return TRUE;  } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 07f46c5fbe..d8cb70dd3c 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -135,7 +135,7 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask)  	gViewerWindow->hideCursor(); -	gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ FALSE, /*BOOL pick_unselectable*/ TRUE); +	gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"), /*BOOL pick_unselectable*/ TRUE);  	return TRUE;  } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 75a5fabdc2..dc13e19dd8 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -78,6 +78,10 @@ static void handle_click_action_play();  static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp);  static ECursorType cursor_from_parcel_media(U8 click_action); +BOOL rigged_hovering_keep_hand = false; +U64 last_rigged_hovering_check_clock_count = 0; +U64 last_rigged_pick_clock_count = 0; +  LLToolPie::LLToolPie()  :	LLTool(std::string("Pie")),  	mMouseButtonDown( false ), @@ -112,7 +116,7 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)  	mMouseDownX = x;  	mMouseDownY = y;  	LLTimer pick_timer; -	BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); +	BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");  	LLPickInfo transparent_pick = gViewerWindow->pickImmediate(x, y, TRUE /*includes transparent*/, pick_rigged);  	LLPickInfo visible_pick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);  	LLViewerObject *transp_object = transparent_pick.getObject(); @@ -173,7 +177,9 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)  	mMouseButtonDown = true; -    return handleLeftClickPick(); +	handleLeftClickPick(); + +	return TRUE;  }  // Spawn context menus on right mouse down so you can drag over and select @@ -722,7 +728,21 @@ void LLToolPie::selectionPropertiesReceived()  BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  { -    BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); +	// prevent rigged item hovering causing FPS to drop by faking we're still hovering it for 0.25 seconds +	U64 current_clock_count = LLTimer::getCurrentClockCount(); +	if (current_clock_count - last_rigged_pick_clock_count < 2500000) { +		if(rigged_hovering_keep_hand) gViewerWindow->setCursor(UI_CURSOR_HAND); +		return TRUE; +	} +	rigged_hovering_keep_hand = 0; + +    static LLCachedControl<bool> pick_rigged_setting(gSavedSettings, "AnimatedObjectsAllowLeftClick"); +    BOOL pick_rigged = pick_rigged_setting; +	if (pick_rigged) { +		pick_rigged = (current_clock_count - last_rigged_hovering_check_clock_count > 1000000); // only 10 per seconds +		if (pick_rigged) last_rigged_hovering_check_clock_count = current_clock_count; +	} +	  	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);  	LLViewerObject *parent = NULL;  	LLViewerObject *object = mHoverPick.getObject(); @@ -730,6 +750,10 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  	if (object)  	{  		parent = object->getRootEdit(); +		// Update gLastRiggedPickClockCount if we're hovering a rigged item +		if (object->isRiggedMesh()) { +			last_rigged_pick_clock_count = current_clock_count; +		}  	}  	// Show screen-space highlight glow effect @@ -794,6 +818,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  		{  			show_highlight = true;  			gViewerWindow->setCursor(UI_CURSOR_HAND); +			rigged_hovering_keep_hand = true;  			LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;  		}  		else diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 39c891c9c1..15d78c0e5b 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3850,7 +3850,12 @@ void process_sound_trigger(LLMessageSystem *msg, void **)  	}  	// Don't play sounds from gestures if they are not enabled. -	if (object_id == owner_id && !gSavedSettings.getBOOL("EnableGestureSounds")) +	// Do play sounds triggered by avatar, since muting your own +	// gesture sounds and your own sounds played inworld from  +	// Inventory can cause confusion. +	if (object_id == owner_id +        && owner_id != gAgentID +        && !gSavedSettings.getBOOL("EnableGestureSounds"))  	{  		return;  	} diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 314c1a1f1e..606e679ab1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -63,6 +63,7 @@  #include "llsdutil.h"  #include "llcorehttputil.h"  #include "llvoicevivox.h" +#include "llinventorymodel.h"  #include "lluiusage.h"  namespace LLStatViewer @@ -578,6 +579,11 @@ void send_viewer_stats(bool include_preferences)  	fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets;  	fail["missing_updater"] = (S32) LLAppViewer::instance()->isUpdaterMissing(); +	LLSD &inventory = body["inventory"]; +	inventory["usable"] = gInventory.isInventoryUsable(); +	LLSD& validation_info = inventory["validation_info"]; +	gInventory.mValidationInfo->asLLSD(validation_info); +  	body["ui"] = LLUIUsage::instance().asLLSD();  	body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f063800587..5cb7b16bbc 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6065,14 +6065,25 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  				LLVOVolume* vobj = drawablep->getVOVolume();                  if (debugLoggingEnabled("AnimatedObjectsLinkset"))                  { -                    if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) +                    if (vobj && vobj->isAnimatedObject() && vobj->isRiggedMesh())                      {                          std::string vobj_name = llformat("Vol%p", vobj);                          F32 est_tris = vobj->getEstTrianglesMax(); -                        LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;  +                        LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;                      }                  } -				if (vobj->isNoLOD()) continue; + +                if (!vobj || vobj->isNoLOD()) +                { +                    continue; +                } + +                LLVolume* volume = vobj->getVolume(); + +                if (!volume) +                { +                    continue; +                }  				vobj->preRebuild(); @@ -6081,7 +6092,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  					vobj->updateRelativeXform(true);  				} -				LLVolume* volume = vobj->getVolume();  				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)  				{  					LLFace* face = drawablep->getFace(i); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index cd1b9c7c69..365f793ed7 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7175,6 +7175,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,  	if (!sPickAvatar)  	{ +		pick_rigged = false;  		//save hit info in case we need to restore  		//due to attachment override  		LLVector4a local_normal; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 7f863756eb..f4cf2cb512 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1624,7 +1624,7 @@ Analysed:           wrap="true"           width="462"           visible="true"> -         You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. +         You don't have rights to upload mesh models. [[VURL] Find out how] to get certified.         </text>          <text           text_color="Yellow" diff --git a/indra/newview/skins/default/xui/en/floater_preview_animation.xml b/indra/newview/skins/default/xui/en/floater_preview_animation.xml index 3ea5f54f2c..d1f8da55be 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_animation.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_animation.xml @@ -1,66 +1,126 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <floater   legacy_header_height="18" - height="85" + height="241"   layout="topleft"   name="preview_anim"   help_topic="preview_anim" - width="280"> + width="320">      <floater.string       name="Title">          Animation: [NAME]      </floater.string> -    <text -     type="string" -     length="1" -     follows="left|top" -     font="SansSerif" -     height="19" -     layout="topleft" -     left="10" -     name="desc txt" -     top="25" -     width="80"> -        Description: -    </text> -    <line_editor -     border_style="line" -     border_thickness="1" -     follows="left|top|right" -     font="SansSerifSmall" -     height="19" -     layout="topleft" -     left_delta="95" -     max_length_bytes="127" -     name="desc" -     top="19" -     width="170" />      <button       height="20"       label="Play Inworld"       label_selected="Stop" +     follows="left|top"       layout="topleft"       left="10"       name="Inworld"       tool_tip="Play this animation so that others can see it" -     top="47" +     top="25"       width="125">         <button.commit_callback          function="PreviewAnim.Play"          parameter="Inworld" />       </button> +    <text +     type="string" +     length="1" +     follows="left|top" +     font="SansSerif" +     height="19" +     layout="topleft" +     left_pad="10" +     name="desc inworld" +     top_delta="3" +     width="160"> +        Other people can see +    </text>      <button       height="20"       label="Play Locally"       label_selected="Stop" +     follows="left|top"       layout="topleft" -     left_pad="5" +     left="10"       name="Locally"       tool_tip="Play this animation so that only you can see it" -     top_delta="0" +     top_pad="5"       width="125">         <button.commit_callback          function="PreviewAnim.Play"          parameter="Locally" />       </button> +    <text +     type="string" +     length="1" +     follows="left|top" +     font="SansSerif" +     height="19" +     layout="topleft" +     left_pad="10" +     name="desc local" +     top_delta="3" +     width="160"> +        Only you can see +    </text> +    <text +     type="string" +     length="1" +     follows="left|top" +     font="SansSerif" +     height="19" +     layout="topleft" +     left="10" +     name="desc txt" +     top_pad="7" +     width="80"> +        Description: +    </text> +    <line_editor +     border_style="line" +     border_thickness="1" +     follows="left|top|right" +     font="SansSerifSmall" +     height="19" +     layout="topleft" +     left="10" +     right="-10" +     max_length_bytes="127" +     name="desc" +     top_pad="0" /> +    <text +     type="string" +     length="1" +     follows="left|top" +     font="SansSerif" +     height="19" +     layout="topleft" +     left="10" +     name="adv_trigger" +     top_pad="7" +     width="100" +     text_color="EmphasisColor"> +        Advanced +    </text> +    <text +     type="string" +     length="1" +     follows="left|top" +     font="SansSerif" +     height="91" +     layout="topleft" +     left="10" +     name="AdvancedStats" +     top_pad="3" +     width="200"> +Priority: [PRIORITY] +Duration: [DURATION]s +Ease In: [EASE_IN]s +Ease Out: [EASE_OUT]s +Loop: [IS_LOOP] +Joints: [NUM_JOINTS] +    </text>  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 48d9eee4cd..998948fca1 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -33,7 +33,7 @@ Combination [KEYSTR] is reserved by menu.       height="30"       layout="topleft"       left="30" -     name="descritption" +     name="description"       top="25"       word_wrap="true"       width="212"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d4f71fb370..70fe84736f 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2949,6 +2949,17 @@ Darn. You have been logged out of [SECOND_LIFE].    <notification     icon="alertmodal.tga" +   name="InventoryUnusable" +   type="alertmodal"> +There is a problem with your inventory. First, try logging out and logging in again. If you see this message again, contact Support and ask them to correct the problem. +    <tag>fail</tag> +    <usetemplate +     name="okbutton" +     yestext="Log out"/> +  </notification> + +  <notification +   icon="alertmodal.tga"     name="OnlyOfficerCanBuyLand"     type="alertmodal">  Unable to buy land for the group: diff --git a/indra/newview/skins/default/xui/es/floater_buy_contents.xml b/indra/newview/skins/default/xui/es/floater_buy_contents.xml index 3563d4bd0f..d078868db2 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_contents.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_contents.xml @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?>  <floater name="floater_buy_contents" title="COMPRAR LOS CONTENIDOS">  	<text name="contains_text"> -		<nolink>[NOMBRE]</nolink> contiene: +		<nolink>[NAME]</nolink> contiene:  	</text>  	<text name="buy_text">  		¿Comprar por [AMOUNT] L$ a [NAME]? diff --git a/indra/newview/skins/default/xui/es/floater_import_collada.xml b/indra/newview/skins/default/xui/es/floater_import_collada.xml index 7e9a00797a..24df8e41a3 100644 --- a/indra/newview/skins/default/xui/es/floater_import_collada.xml +++ b/indra/newview/skins/default/xui/es/floater_import_collada.xml @@ -1,13 +1,13 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?>  <floater name="Import Collada" title="Importar escena">  	<text name="mesh count"> -		Redes: [RECUENTO] +		Redes: [COUNT]  	</text>  	<text name="texture count"> -		Texturas: [RECUENTO] +		Texturas: [COUNT]  	</text>  	<text name="status"> -		Estado: [ESTADO] +		Estado: [STATUS]  	</text>  	<button label="Cancelar" name="cancel"/>  	<button label="OK" name="ok"/> @@ -15,9 +15,9 @@  		Inactivo  	</string>  	<string name="status_uploading"> -		Cargando [NOMBRE] +		Cargando [NAME]  	</string>  	<string name="status_creating"> -		Creando objeto [NOMBRE] +		Creando objeto [NAME]  	</string>  </floater> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index c7750320d5..54707116d4 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -3389,15 +3389,15 @@ Con los siguientes Residentes:  		Error de transferencia a grupo.  	</notification>  	<notification name="ReleaseLandThrottled"> -		La parcela [NOMBRE_PARCELA] no se puede abandonar en este momento. +		La parcela [PARCEL_NAME] no se puede abandonar en este momento.  	</notification>  	<notification name="ReleasedLandWithReclaim"> -		Ya está disponible la parcela [NOMBRE_PARCELA] de [ÁREA] m². +		Ya está disponible la parcela [PARCEL_NAME] de [AREA] m². -Dispondrás de [PERÍODO_DE_RECLAMACIÓN] horas para reclamar la cantidad de 0 L$ antes de que se ponga en venta. +Dispondrás de [RECLAIM_PERIOD] horas para reclamar la cantidad de 0 L$ antes de que se ponga en venta.  	</notification>  	<notification name="ReleasedLandNoReclaim"> -		Ya está disponible la parcela [NOMBRE_PARCELA] de [ÁREA] m². +		Ya está disponible la parcela [PARCEL_NAME] de [AREA] m².  Ya está en venta.  	</notification> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index f5e7d0bf4e..7017a7a5ab 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -208,10 +208,10 @@ Si deseas obtener más información, consulta las preguntas frecuentes que apare  http://secondlife.com/viewer-access-faq  	</string>  	<string name="LoginIntermediateOptionalUpdateAvailable"> -		Actualización opcional del visor disponible: [VERSIÓN] +		Actualización opcional del visor disponible: [VERSION]  	</string>  	<string name="LoginFailedRequiredUpdate"> -		Actualización necesaria del visor: [VERSIÓN] +		Actualización necesaria del visor: [VERSION]  	</string>  	<string name="LoginFailedAlreadyLoggedIn">  		El agente ya ha iniciado sesión. @@ -252,7 +252,7 @@ support@secondlife.com.  	</string>  	<string name="LoginFailedAcountSuspended">  		No se podrá acceder a tu cuenta hasta las -[HORA] (horario de la costa del Pacífico). +[TIME] (horario de la costa del Pacífico).  	</string>  	<string name="LoginFailedAccountDisabled">  		En este momento no podemos completar la solicitud.  @@ -265,7 +265,7 @@ Ponte en contacto con support@secondlife.com.  	<string name="LoginFailedAccountMaintenance">  		Se están realizando tareas rutinarias de mantenimiento en tu cuenta.  No se podrá acceder a tu cuenta hasta las -[HORA] (horario de la costa del Pacífico). +[TIME] (horario de la costa del Pacífico).  Si crees que se trata de un error, ponte en contacto con support@secondlife.com.  	</string>  	<string name="LoginFailedPendingLogoutFault"> @@ -283,7 +283,7 @@ Por favor, aguarda un momento antes de intentar conectarte nuevamente.  	</string>  	<string name="LoginFailedRestrictedHours">  		Tu cuenta solo puede acceder a Second Life -entre las [INICIO] y las [FIN] (horario de la costa del Pacífico). +entre las [START] y las [END] (horario de la costa del Pacífico).  Inténtalo de nuevo durante ese horario.  Si crees que se trata de un error, ponte en contacto con support@secondlife.com.  	</string> | 
