diff options
| author | Mike Antipov <mantipov@productengine.com> | 2010-03-31 10:08:50 +0300 | 
|---|---|---|
| committer | Mike Antipov <mantipov@productengine.com> | 2010-03-31 10:08:50 +0300 | 
| commit | bba457e889e45a43d1aba2541ee1dab1e07dd979 (patch) | |
| tree | 19c5e5c364c1fa1764d615e89683244aecf6373b /indra/newview | |
| parent | 1751e6add7e9957106f628816f0808c92a67cc6c (diff) | |
| parent | d99a7d2f1d5d839131919d17173f5197c04083a6 (diff) | |
Merge from default branch
--HG--
branch : product-engine
Diffstat (limited to 'indra/newview')
44 files changed, 2104 insertions, 1963 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 9bdf9d8893..47fde08a9d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -74,6 +74,7 @@ set(viewer_SOURCE_FILES      llagentpilot.cpp      llagentui.cpp      llagentwearables.cpp +    llagentwearablesfetch.cpp      llanimstatelabels.cpp      llappearancemgr.cpp      llappviewer.cpp @@ -253,6 +254,7 @@ set(viewer_SOURCE_FILES      llinventoryfilter.cpp      llinventoryfunctions.cpp      llinventorymodel.cpp +    llinventorymodelbackgroundfetch.cpp      llinventoryobserver.cpp      llinventorypanel.cpp      lljoystickbutton.cpp @@ -573,6 +575,7 @@ set(viewer_HEADER_FILES      llagentpilot.h      llagentui.h      llagentwearables.h +    llagentwearablesfetch.h      llanimstatelabels.h      llappearance.h      llappearancemgr.h @@ -754,6 +757,7 @@ set(viewer_HEADER_FILES      llinventoryfilter.h      llinventoryfunctions.h      llinventorymodel.h +    llinventorymodelbackgroundfetch.h      llinventoryobserver.h      llinventorypanel.h      lljoystickbutton.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index a764932815..f434782977 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -44,7 +44,6 @@  #include "llcallingcard.h"  #include "llchannelmanager.h"  #include "llconsole.h" -//#include "llfirstuse.h"  #include "llfloatercamera.h"  #include "llfloatercustomize.h"  #include "llfloaterreg.h" @@ -90,41 +89,18 @@ const BOOL ANIMATE = TRUE;  const U8 AGENT_STATE_TYPING =	0x04;  const U8 AGENT_STATE_EDITING =  0x10; -//drone wandering constants -const F32 MAX_WANDER_TIME = 20.f;						// seconds -const F32 MAX_HEADING_HALF_ERROR = 0.2f;				// radians -const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD;		// radians / frame -const F32 WANDER_TARGET_MIN_DISTANCE = 10.f;			// meters -  // Autopilot constants -const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD;	// radians -const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD;		// radians / frame -const F32 AUTOPILOT_STOP_DISTANCE = 2.f;					// meters  const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f;			// meters  const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f;	// meters  const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f;		// seconds -// face editing constants -const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f); -const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f); - -const F32 METERS_PER_WHEEL_CLICK = 1.f; - -const F32 MAX_TIME_DELTA = 1.f; +const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f; +const F64 CHAT_AGE_FAST_RATE = 3.0;  // fidget constants  const F32 MIN_FIDGET_TIME = 8.f; // seconds  const F32 MAX_FIDGET_TIME = 20.f; // seconds -const S32 MAX_NUM_CHAT_POSITIONS = 10; - -const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f; - -const F32 MAX_FOCUS_OFFSET = 20.f; - -const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f; - -const F64 CHAT_AGE_FAST_RATE = 3.0;  // The agent instance.  LLAgent gAgent; @@ -218,13 +194,6 @@ LLAgent::LLAgent() :  	mIsBusy(FALSE), -	mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed -	mWalkKey(0), // like AtKey, but causes less forward thrust -	mLeftKey(0), -	mUpKey(0), -	mYawKey(0.f), -	mPitchKey(0.f), -  	mControlFlags(0x00000000),  	mbFlagsDirty(FALSE),  	mbFlagsNeedReset(FALSE), @@ -339,7 +308,7 @@ void LLAgent::moveAt(S32 direction, bool reset)  	// age chat timer so it fades more quickly when you are intentionally moving  	ageChat(); -	setKey(direction, mAtKey); +	gAgentCamera.setAtKey(LLAgentCamera::directionToKey(direction));  	if (direction > 0)  	{ @@ -364,7 +333,7 @@ void LLAgent::moveAtNudge(S32 direction)  	// age chat timer so it fades more quickly when you are intentionally moving  	ageChat(); -	setKey(direction, mWalkKey); +	gAgentCamera.setWalkKey(LLAgentCamera::directionToKey(direction));  	if (direction > 0)  	{ @@ -386,7 +355,7 @@ void LLAgent::moveLeft(S32 direction)  	// age chat timer so it fades more quickly when you are intentionally moving  	ageChat(); -	setKey(direction, mLeftKey); +	gAgentCamera.setLeftKey(LLAgentCamera::directionToKey(direction));  	if (direction > 0)  	{ @@ -408,7 +377,7 @@ void LLAgent::moveLeftNudge(S32 direction)  	// age chat timer so it fades more quickly when you are intentionally moving  	ageChat(); -	setKey(direction, mLeftKey); +	gAgentCamera.setLeftKey(LLAgentCamera::directionToKey(direction));  	if (direction > 0)  	{ @@ -430,7 +399,7 @@ void LLAgent::moveUp(S32 direction)  	// age chat timer so it fades more quickly when you are intentionally moving  	ageChat(); -	setKey(direction, mUpKey); +	gAgentCamera.setUpKey(LLAgentCamera::directionToKey(direction));  	if (direction > 0)  	{ @@ -449,7 +418,7 @@ void LLAgent::moveUp(S32 direction)  //-----------------------------------------------------------------------------  void LLAgent::moveYaw(F32 mag, bool reset_view)  { -	mYawKey = mag; +	gAgentCamera.setYawKey(mag);  	if (mag > 0)  	{ @@ -471,7 +440,7 @@ void LLAgent::moveYaw(F32 mag, bool reset_view)  //-----------------------------------------------------------------------------  void LLAgent::movePitch(F32 mag)  { -	mPitchKey = mag; +	gAgentCamera.setPitchKey(mag);  	if (mag > 0)  	{ @@ -1049,26 +1018,6 @@ LLQuaternion LLAgent::getQuat() const  }  //----------------------------------------------------------------------------- -// setKey() -//----------------------------------------------------------------------------- -void LLAgent::setKey(const S32 direction, S32 &key) -{ -	if (direction > 0) -	{ -		key = 1; -	} -	else if (direction < 0) -	{ -		key = -1; -	} -	else -	{ -		key = 0; -	} -} - - -//-----------------------------------------------------------------------------  // getControlFlags()  //-----------------------------------------------------------------------------  U32 LLAgent::getControlFlags() @@ -1537,20 +1486,20 @@ void LLAgent::propagate(const F32 dt)  	LLFloaterMove *floater_move = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview");  	if (floater_move)  	{ -		floater_move->mForwardButton   ->setToggleState( mAtKey > 0 || mWalkKey > 0 ); -		floater_move->mBackwardButton  ->setToggleState( mAtKey < 0 || mWalkKey < 0 ); -		floater_move->mTurnLeftButton  ->setToggleState( mYawKey > 0.f ); -		floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f ); -		floater_move->mMoveUpButton    ->setToggleState( mUpKey > 0 ); -		floater_move->mMoveDownButton  ->setToggleState( mUpKey < 0 ); +		floater_move->mForwardButton   ->setToggleState( gAgentCamera.getAtKey() > 0 || gAgentCamera.getWalkKey() > 0 ); +		floater_move->mBackwardButton  ->setToggleState( gAgentCamera.getAtKey() < 0 || gAgentCamera.getWalkKey() < 0 ); +		floater_move->mTurnLeftButton  ->setToggleState( gAgentCamera.getYawKey() > 0.f ); +		floater_move->mTurnRightButton ->setToggleState( gAgentCamera.getYawKey() < 0.f ); +		floater_move->mMoveUpButton    ->setToggleState( gAgentCamera.getUpKey() > 0 ); +		floater_move->mMoveDownButton  ->setToggleState( gAgentCamera.getUpKey() < 0 );  	}  	// handle rotation based on keyboard levels  	const F32 YAW_RATE = 90.f * DEG_TO_RAD;				// radians per second -	yaw(YAW_RATE * mYawKey * dt); +	yaw(YAW_RATE * gAgentCamera.getYawKey() * dt);  	const F32 PITCH_RATE = 90.f * DEG_TO_RAD;			// radians per second -	pitch(PITCH_RATE * mPitchKey * dt); +	pitch(PITCH_RATE * gAgentCamera.getPitchKey() * dt);  	// handle auto-land behavior  	if (isAgentAvatarValid()) @@ -1560,7 +1509,7 @@ void LLAgent::propagate(const F32 dt)  		land_vel.mV[VZ] = 0.f;  		if (!in_air  -			&& mUpKey < 0  +			&& gAgentCamera.getUpKey() < 0   			&& land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED  			&& gSavedSettings.getBOOL("AutomaticFly"))  		{ @@ -1569,13 +1518,7 @@ void LLAgent::propagate(const F32 dt)  		}  	} -	// clear keys -	mAtKey = 0; -	mWalkKey = 0; -	mLeftKey = 0; -	mUpKey = 0; -	mYawKey = 0.f; -	mPitchKey = 0.f; +	gAgentCamera.clearGeneralKeys();  }  //----------------------------------------------------------------------------- diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 55d9b292d7..a460077b7e 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -39,9 +39,6 @@  #include "llagentconstants.h"  #include "llagentdata.h" 			// gAgentID, gAgentSessionID  #include "llcharacter.h" 			// LLAnimPauseRequest -#include "llfollowcam.h" 			// Ventrella -#include "llhudeffectlookat.h" 		// EPointAtType -#include "llhudeffectpointat.h" 	// ELookAtType  #include "llpointer.h"  #include "lluicolor.h"  #include "llvoavatardefines.h" @@ -434,19 +431,6 @@ private:   **                                                                            **   **                    MOVEMENT   **/ -	 -	//-------------------------------------------------------------------- -	// Keys -	//-------------------------------------------------------------------- -public: -	void			setKey(const S32 direction, S32 &key); // Sets key to +1 for +direction, -1 for -direction -private: -	S32 			mAtKey;				// Either 1, 0, or -1. Indicates that movement key is pressed -	S32				mWalkKey; 			// Like AtKey, but causes less forward thrust -	S32 			mLeftKey; -	S32				mUpKey; -	F32				mYawKey; -	F32				mPitchKey;  	//--------------------------------------------------------------------  	// Movement from user input diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 8ff55cafca..bb06255fd1 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -35,50 +35,25 @@  #include "pipeline.h" -#include "llagentlistener.h" -#include "llagentwearables.h" -#include "llagentui.h" +#include "llagent.h"  #include "llanimationstates.h" -#include "llbottomtray.h" -#include "llcallingcard.h" -#include "llchannelmanager.h" -#include "llconsole.h" -//#include "llfirstuse.h"  #include "llfloatercamera.h"  #include "llfloatercustomize.h"  #include "llfloaterreg.h" -#include "llfloatertools.h" -#include "llgroupactions.h" -#include "llgroupmgr.h" -#include "llhomelocationresponder.h"  #include "llhudmanager.h"  #include "lljoystickbutton.h" -#include "llmorphview.h" -#include "llmoveview.h" -#include "llnavigationbar.h" // to show/hide navigation bar when changing mouse look state -#include "llnearbychatbar.h" -#include "llnotificationsutil.h" -#include "llparcel.h" -#include "llsdutil.h" -#include "llsidetray.h" -#include "llsky.h" +#include "llselectmgr.h"  #include "llsmoothstep.h" -#include "llstatusbar.h" -#include "llteleportflags.h" -#include "lltool.h"  #include "lltoolmgr.h" -#include "lltrans.h" +#include "llviewercamera.h"  #include "llviewercontrol.h" -#include "llviewerdisplay.h"  #include "llviewerjoystick.h" -#include "llviewermediafocus.h"  #include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerstats.h" +#include "llviewerregion.h" +#include "llviewerwindow.h"  #include "llvoavatarself.h"  #include "llwindow.h"  #include "llworld.h" -#include "llworldmap.h"  using namespace LLVOAvatarDefines; @@ -181,6 +156,13 @@ LLAgentCamera::LLAgentCamera() :  	mTrackFocusObject(TRUE),  	mUIOffset(0.f), +	mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed +	mWalkKey(0), // like AtKey, but causes less forward thrust +	mLeftKey(0), +	mUpKey(0), +	mYawKey(0.f), +	mPitchKey(0.f), +  	mOrbitLeftKey(0.f),  	mOrbitRightKey(0.f),  	mOrbitUpKey(0.f), @@ -196,6 +178,10 @@ LLAgentCamera::LLAgentCamera() :  	mPanOutKey(0.f)  {  	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT ); + +	clearGeneralKeys(); +	clearOrbitKeys(); +	clearPanKeys();  }  // Requires gSavedSettings to be initialized. @@ -1204,17 +1190,15 @@ void LLAgentCamera::updateCamera()  	LLFloaterCamera* camera_floater = LLFloaterReg::findTypedInstance<LLFloaterCamera>("camera");  	if (camera_floater)  	{ -		camera_floater->mRotate->setToggleState( -		mOrbitRightKey > 0.f,	// left -		mOrbitUpKey > 0.f,		// top -		mOrbitLeftKey > 0.f,	// right -		mOrbitDownKey > 0.f);	// bottom - -		camera_floater->mTrack->setToggleState( -		mPanLeftKey > 0.f,		// left -		mPanUpKey > 0.f,		// top -		mPanRightKey > 0.f,		// right -		mPanDownKey > 0.f);		// bottom +		camera_floater->mRotate->setToggleState(gAgentCamera.getOrbitRightKey() > 0.f,	// left +												gAgentCamera.getOrbitUpKey() > 0.f,		// top +												gAgentCamera.getOrbitLeftKey() > 0.f,	// right +												gAgentCamera.getOrbitDownKey() > 0.f);	// bottom +		 +		camera_floater->mTrack->setToggleState(gAgentCamera.getPanLeftKey() > 0.f,		// left +											   gAgentCamera.getPanUpKey() > 0.f,			// top +											   gAgentCamera.getPanRightKey() > 0.f,		// right +											   gAgentCamera.getPanDownKey() > 0.f);		// bottom  	}  	// Handle camera movement based on keyboard. @@ -1222,21 +1206,21 @@ void LLAgentCamera::updateCamera()  	const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD;		// radians per second  	const F32 PAN_RATE = 5.f;								// meters per second -	if( mOrbitUpKey || mOrbitDownKey ) +	if (gAgentCamera.getOrbitUpKey() || gAgentCamera.getOrbitDownKey())  	{ -		F32 input_rate = mOrbitUpKey - mOrbitDownKey; +		F32 input_rate = gAgentCamera.getOrbitUpKey() - gAgentCamera.getOrbitDownKey();  		cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );  	} -	if( mOrbitLeftKey || mOrbitRightKey) +	if (gAgentCamera.getOrbitLeftKey() || gAgentCamera.getOrbitRightKey())  	{ -		F32 input_rate = mOrbitLeftKey - mOrbitRightKey; -		cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped ); +		F32 input_rate = gAgentCamera.getOrbitLeftKey() - gAgentCamera.getOrbitRightKey(); +		cameraOrbitAround(input_rate * ORBIT_AROUND_RATE / gFPSClamped);  	} -	if( mOrbitInKey || mOrbitOutKey ) +	if (gAgentCamera.getOrbitInKey() || gAgentCamera.getOrbitOutKey())  	{ -		F32 input_rate = mOrbitInKey - mOrbitOutKey; +		F32 input_rate = gAgentCamera.getOrbitInKey() - gAgentCamera.getOrbitOutKey();  		LLVector3d to_focus = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()) - calcFocusPositionTargetGlobal();  		F32 distance_to_focus = (F32)to_focus.magVec(); @@ -1244,38 +1228,27 @@ void LLAgentCamera::updateCamera()  		cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );  	} -	if( mPanInKey || mPanOutKey ) +	if (gAgentCamera.getPanInKey() || gAgentCamera.getPanOutKey())  	{ -		F32 input_rate = mPanInKey - mPanOutKey; -		cameraPanIn( input_rate * PAN_RATE / gFPSClamped ); +		F32 input_rate = gAgentCamera.getPanInKey() - gAgentCamera.getPanOutKey(); +		cameraPanIn(input_rate * PAN_RATE / gFPSClamped);  	} -	if( mPanRightKey || mPanLeftKey ) +	if (gAgentCamera.getPanRightKey() || gAgentCamera.getPanLeftKey())  	{ -		F32 input_rate = mPanRightKey - mPanLeftKey; -		cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped ); +		F32 input_rate = gAgentCamera.getPanRightKey() - gAgentCamera.getPanLeftKey(); +		cameraPanLeft(input_rate * -PAN_RATE / gFPSClamped );  	} -	if( mPanUpKey || mPanDownKey ) +	if (gAgentCamera.getPanUpKey() || gAgentCamera.getPanDownKey())  	{ -		F32 input_rate = mPanUpKey - mPanDownKey; -		cameraPanUp( input_rate * PAN_RATE / gFPSClamped ); +		F32 input_rate = gAgentCamera.getPanUpKey() - gAgentCamera.getPanDownKey(); +		cameraPanUp(input_rate * PAN_RATE / gFPSClamped );  	}  	// Clear camera keyboard keys. -	mOrbitLeftKey		= 0.f; -	mOrbitRightKey		= 0.f; -	mOrbitUpKey			= 0.f; -	mOrbitDownKey		= 0.f; -	mOrbitInKey			= 0.f; -	mOrbitOutKey		= 0.f; - -	mPanRightKey		= 0.f; -	mPanLeftKey			= 0.f; -	mPanUpKey			= 0.f; -	mPanDownKey			= 0.f; -	mPanInKey			= 0.f; -	mPanOutKey			= 0.f; +	gAgentCamera.clearOrbitKeys(); +	gAgentCamera.clearPanKeys();  	// lerp camera focus offset  	mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE)); @@ -2850,5 +2823,44 @@ EPointAtType LLAgentCamera::getPointAtType()  	return POINTAT_TARGET_NONE;  } +void LLAgentCamera::clearGeneralKeys() +{ +	mAtKey 				= 0; +	mWalkKey 			= 0; +	mLeftKey 			= 0; +	mUpKey 				= 0; +	mYawKey 			= 0.f; +	mPitchKey 			= 0.f; +} + +void LLAgentCamera::clearOrbitKeys() +{ +	mOrbitLeftKey		= 0.f; +	mOrbitRightKey		= 0.f; +	mOrbitUpKey			= 0.f; +	mOrbitDownKey		= 0.f; +	mOrbitInKey			= 0.f; +	mOrbitOutKey		= 0.f; +} + +void LLAgentCamera::clearPanKeys() +{ +	mPanRightKey		= 0.f; +	mPanLeftKey			= 0.f; +	mPanUpKey			= 0.f; +	mPanDownKey			= 0.f; +	mPanInKey			= 0.f; +	mPanOutKey			= 0.f; +} + +// static +S32 LLAgentCamera::directionToKey(S32 direction) +{ +	if (direction > 0) return 1; +	if (direction < 0) return -1; +	return 0; +} + +  // EOF diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index 2074864336..3ba24ef32b 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -33,32 +33,12 @@  #ifndef LL_LLAGENTCAMERA_H  #define LL_LLAGENTCAMERA_H -#include "indra_constants.h" -#include "llevent.h" 				// LLObservable base class -#include "llagent.h" -#include "llagentaccess.h" -#include "llagentconstants.h" -#include "llagentdata.h" 			// gAgentID, gAgentSessionID -#include "llcharacter.h" 			// LLAnimPauseRequest  #include "llfollowcam.h" 			// Ventrella  #include "llhudeffectlookat.h" 		// EPointAtType  #include "llhudeffectpointat.h" 	// ELookAtType -#include "llpointer.h" -#include "lluicolor.h" -#include "llvoavatardefines.h" -class LLChat; -class LLVOAvatarSelf; -class LLViewerRegion; -class LLMotion; -class LLToolset; -class LLMessageSystem; -class LLPermissions; -class LLHost; -class LLFriendObserver;  class LLPickInfo; -class LLViewerObject; -class LLAgentDropGroupViewerNode; +class LLVOAvatarSelf;  //--------------------------------------------------------------------  // Types @@ -176,42 +156,6 @@ private:  	LLVector3		mCameraUpVector;				// Camera's up direction in world coordinates (determines the 'roll' of the view)  	//-------------------------------------------------------------------- -	// Orbit -	//-------------------------------------------------------------------- -public: -	void			setOrbitLeftKey(F32 mag)	{ mOrbitLeftKey = mag; } -	void			setOrbitRightKey(F32 mag)	{ mOrbitRightKey = mag; } -	void			setOrbitUpKey(F32 mag)		{ mOrbitUpKey = mag; } -	void			setOrbitDownKey(F32 mag)	{ mOrbitDownKey = mag; } -	void			setOrbitInKey(F32 mag)		{ mOrbitInKey = mag; } -	void			setOrbitOutKey(F32 mag)		{ mOrbitOutKey = mag; } -private: -	F32				mOrbitLeftKey; -	F32				mOrbitRightKey; -	F32				mOrbitUpKey; -	F32				mOrbitDownKey; -	F32				mOrbitInKey; -	F32				mOrbitOutKey; - -	//-------------------------------------------------------------------- -	// Pan -	//-------------------------------------------------------------------- -public: -	void			setPanLeftKey(F32 mag)		{ mPanLeftKey = mag; } -	void			setPanRightKey(F32 mag)		{ mPanRightKey = mag; } -	void			setPanUpKey(F32 mag)		{ mPanUpKey = mag; } -	void			setPanDownKey(F32 mag)		{ mPanDownKey = mag; } -	void			setPanInKey(F32 mag)		{ mPanInKey = mag; } -	void			setPanOutKey(F32 mag)		{ mPanOutKey = mag; } -private: -	F32				mPanUpKey;						 -	F32				mPanDownKey;					 -	F32				mPanLeftKey;					 -	F32				mPanRightKey;					 -	F32				mPanInKey; -	F32				mPanOutKey;	 -	 -	//--------------------------------------------------------------------  	// Follow  	//--------------------------------------------------------------------  public: @@ -358,6 +302,97 @@ private:  public:  	F32				mHUDTargetZoom;	// Target zoom level for HUD objects (used when editing)  	F32				mHUDCurZoom; 	// Current animated zoom level for HUD objects + + +/******************************************************************************** + **                                                                            ** + **                    KEYS + **/ + +public: +	S32				getAtKey() const		{ return mAtKey; } +	S32				getWalkKey() const		{ return mWalkKey; } +	S32				getLeftKey() const		{ return mLeftKey; } +	S32				getUpKey() const		{ return mUpKey; } +	F32				getYawKey() const		{ return mYawKey; } +	F32				getPitchKey() const		{ return mPitchKey; } + +	void			setAtKey(S32 mag)		{ mAtKey = mag; } +	void			setWalkKey(S32 mag)		{ mWalkKey = mag; } +	void			setLeftKey(S32 mag)		{ mLeftKey = mag; } +	void			setUpKey(S32 mag)		{ mUpKey = mag; } +	void			setYawKey(F32 mag)		{ mYawKey = mag; } +	void			setPitchKey(F32 mag)	{ mPitchKey = mag; } + +	void			clearGeneralKeys(); +	static S32		directionToKey(S32 direction); // Changes direction to -1/0/1 + +private: +	S32 			mAtKey;				// Either 1, 0, or -1. Indicates that movement key is pressed +	S32				mWalkKey; 			// Like AtKey, but causes less forward thrust +	S32 			mLeftKey; +	S32				mUpKey; +	F32				mYawKey; +	F32				mPitchKey; + +	//-------------------------------------------------------------------- +	// Orbit +	//-------------------------------------------------------------------- +public: +	F32				getOrbitLeftKey() const		{ return mOrbitLeftKey; } +	F32				getOrbitRightKey() const	{ return mOrbitRightKey; } +	F32				getOrbitUpKey() const		{ return mOrbitUpKey; } +	F32				getOrbitDownKey() const		{ return mOrbitDownKey; } +	F32				getOrbitInKey() const		{ return mOrbitInKey; } +	F32				getOrbitOutKey() const		{ return mOrbitOutKey; } + +	void			setOrbitLeftKey(F32 mag)	{ mOrbitLeftKey = mag; } +	void			setOrbitRightKey(F32 mag)	{ mOrbitRightKey = mag; } +	void			setOrbitUpKey(F32 mag)		{ mOrbitUpKey = mag; } +	void			setOrbitDownKey(F32 mag)	{ mOrbitDownKey = mag; } +	void			setOrbitInKey(F32 mag)		{ mOrbitInKey = mag; } +	void			setOrbitOutKey(F32 mag)		{ mOrbitOutKey = mag; } + +	void			clearOrbitKeys(); +private: +	F32				mOrbitLeftKey; +	F32				mOrbitRightKey; +	F32				mOrbitUpKey; +	F32				mOrbitDownKey; +	F32				mOrbitInKey; +	F32				mOrbitOutKey; + +	//-------------------------------------------------------------------- +	// Pan +	//-------------------------------------------------------------------- +public: +	F32				getPanLeftKey() const		{ return mPanLeftKey; } +	F32				getPanRightKey() const	{ return mPanRightKey; } +	F32				getPanUpKey() const		{ return mPanUpKey; } +	F32				getPanDownKey() const		{ return mPanDownKey; } +	F32				getPanInKey() const		{ return mPanInKey; } +	F32				getPanOutKey() const		{ return mPanOutKey; } + +	void			setPanLeftKey(F32 mag)		{ mPanLeftKey = mag; } +	void			setPanRightKey(F32 mag)		{ mPanRightKey = mag; } +	void			setPanUpKey(F32 mag)		{ mPanUpKey = mag; } +	void			setPanDownKey(F32 mag)		{ mPanDownKey = mag; } +	void			setPanInKey(F32 mag)		{ mPanInKey = mag; } +	void			setPanOutKey(F32 mag)		{ mPanOutKey = mag; } + +	void			clearPanKeys(); +private: +	F32				mPanUpKey;						 +	F32				mPanDownKey;					 +	F32				mPanLeftKey;					 +	F32				mPanRightKey;					 +	F32				mPanInKey; +	F32				mPanOutKey; + +/**                    Keys + **                                                                            ** + *******************************************************************************/ +  };  extern LLAgentCamera gAgentCamera; diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 1fb4cff31a..2bc6d28daa 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -31,102 +31,33 @@   */  #include "llviewerprecompiledheaders.h" +#include "llagentwearables.h" +#include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentcamera.h" -#include "llagentwearables.h" - +#include "llagentwearablesfetch.h" +#include "llappearancemgr.h"  #include "llcallbacklist.h"  #include "llfloatercustomize.h" +#include "llfolderview.h" +#include "llgesturemgr.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "llinventorypanel.h" +#include "llmd5.h"  #include "llnotificationsutil.h" +#include "llpaneloutfitsinventory.h" +#include "llsidetray.h" +#include "lltexlayer.h"  #include "llviewerregion.h"  #include "llvoavatarself.h"  #include "llwearable.h"  #include "llwearablelist.h" -#include "llgesturemgr.h" -#include "llappearancemgr.h" -#include "lltexlayer.h" -#include "llsidetray.h" -#include "llpaneloutfitsinventory.h" -#include "llfolderview.h" -#include "llaccordionctrltab.h"  #include <boost/scoped_ptr.hpp> -//-------------------------------------------------------------------- -// Classes for fetching initial wearables data -//-------------------------------------------------------------------- -// Outfit folder fetching callback structure. -class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver -{ -public: -	LLInitialWearablesFetch() {} -	~LLInitialWearablesFetch(); -	virtual void done(); - -	struct InitialWearableData -	{ -		EWearableType mType; -		LLUUID mItemID; -		LLUUID mAssetID; -		InitialWearableData(EWearableType type, LLUUID& itemID, LLUUID& assetID) : -			mType(type), -			mItemID(itemID), -			mAssetID(assetID) -		{} -	}; - -	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; -	initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder -	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg - -protected: -	void processWearablesMessage(); -	void processContents(); -}; - -class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver -{ -public: -	enum ELibraryOutfitFetchStep { -		LOFS_FOLDER = 0, -		LOFS_OUTFITS, -		LOFS_LIBRARY, -		LOFS_IMPORTED, -		LOFS_CONTENTS -	}; -	LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false)  -	{ -		mMyOutfitsID = LLUUID::null; -		mClothingID = LLUUID::null; -		mLibraryClothingID = LLUUID::null; -		mImportedClothingID = LLUUID::null; -		mImportedClothingName = "Imported Library Clothing"; -	} -	~LLLibraryOutfitsFetch() {} -	virtual void done(); -	void doneIdle(); -	LLUUID mMyOutfitsID; -	void importedFolderFetch(); -protected: -	void folderDone(void); -	void outfitsDone(void); -	void libraryDone(void); -	void importedFolderDone(void); -	void contentsDone(void); -	enum ELibraryOutfitFetchStep mCurrFetchStep; -	uuid_vec_t mLibraryClothingFolders; -	uuid_vec_t mImportedClothingFolders; -	bool mOutfitsPopulated; -	LLUUID mClothingID; -	LLUUID mLibraryClothingID; -	LLUUID mImportedClothingID; -	std::string mImportedClothingName; -}; -  LLAgentWearables gAgentWearables;  BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; @@ -1013,8 +944,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data.  				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); // MULTI-WEARABLE: update -				outfit->mAgentInitialWearables.push_back(wearable_data); -				 +				outfit->add(wearable_data);  			}  			lldebugs << "       " << LLWearableDictionary::getTypeLabel(type) << llendl; @@ -1514,6 +1444,7 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a  			{  				LLSD payload;  				payload["wearable_type"] = (S32)type; +				payload["wearable_index"] = (S32)index;  				// Bring up view-modal dialog: Save changes? Yes, No, Cancel  				LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog);  				return; @@ -1527,22 +1458,21 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a  } -// MULTI_WEARABLE: assuming one wearable per type. -// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change.  // static   bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);  	EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger(); +	S32 index = (S32)notification["payload"]["wearable_index"].asInteger();  	switch(option)  	{  		case 0:  // "Save" -			gAgentWearables.saveWearable(type, 0); -			gAgentWearables.removeWearableFinal(type, false, 0); +			gAgentWearables.saveWearable(type, index); +			gAgentWearables.removeWearableFinal(type, false, index);  			break;  		case 1:  // "Don't Save" -			gAgentWearables.removeWearableFinal(type, false, 0); +			gAgentWearables.removeWearableFinal(type, false, index);  			break;  		case 2: // "Cancel" @@ -1601,23 +1531,19 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it  {  	llinfos << "setWearableOutfit() start" << llendl; -	BOOL wearables_to_remove[WT_COUNT]; -	wearables_to_remove[WT_SHAPE]		= FALSE; -	wearables_to_remove[WT_SKIN]		= FALSE; -	wearables_to_remove[WT_HAIR]		= FALSE; -	wearables_to_remove[WT_EYES]		= FALSE; -	wearables_to_remove[WT_SHIRT]		= remove; -	wearables_to_remove[WT_PANTS]		= remove; -	wearables_to_remove[WT_SHOES]		= remove; -	wearables_to_remove[WT_SOCKS]		= remove; -	wearables_to_remove[WT_JACKET]		= remove; -	wearables_to_remove[WT_GLOVES]		= remove; -	wearables_to_remove[WT_UNDERSHIRT]	= (!gAgent.isTeen()) & remove; -	wearables_to_remove[WT_UNDERPANTS]	= (!gAgent.isTeen()) & remove; -	wearables_to_remove[WT_SKIRT]		= remove; -	wearables_to_remove[WT_ALPHA]		= remove; -	wearables_to_remove[WT_TATTOO]		= remove; - +	// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later +	if (remove) +	{ +		// note: shirt is the first non-body part wearable item. Update if wearable order changes. +		// This loop should remove all clothing, but not any body parts +		for (S32 type = 0; type < (S32)WT_COUNT; type++) +		{ +			if (LLWearableDictionary::getAssetType((EWearableType)type) == LLAssetType::AT_CLOTHING) +			{ +				removeWearable((EWearableType)type, true, 0); +			} +		} +	}  	S32 count = wearables.count();  	llassert(items.count() == count); @@ -1632,77 +1558,26 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it  		if (new_wearable)  		{  			const EWearableType type = new_wearable->getType(); -			wearables_to_remove[type] = FALSE; +		 +			new_wearable->setName(new_item->getName()); +			new_wearable->setItemID(new_item->getUUID()); -			// MULTI_WEARABLE: using 0th -			LLWearable* old_wearable = getWearable(type, 0); -			if (old_wearable) +			if (LLWearableDictionary::getAssetType(type) == LLAssetType::AT_BODYPART)  			{ -				// Special case where you're putting on a wearable that has the same assetID -				// as the previous (e.g. wear a shirt then wear a copy of that shirt) since in this -				// case old_wearable == new_wearable. -				if (old_wearable == new_wearable) -				{ -					old_wearable->setLabelUpdated(); -					new_wearable->setName(new_item->getName()); -					new_wearable->setItemID(new_item->getUUID()); -				} - -				const LLUUID& old_item_id = getWearableItemID(type, 0); -				if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && -				    (old_item_id == new_item->getUUID())) -				{ -					lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl; -					continue; -				} -				 -				// Assumes existing wearables are not dirty. -				if (old_wearable->isDirty()) -				{ -					llassert(0); -					continue; -				} +				// exactly one wearable per body part +				setWearable(type,0,new_wearable);  			} -			 -			new_wearable->setItemID(new_item->getUUID()); -			setWearable(type,0,new_wearable); -		} -	} - -	std::vector<LLWearable*> wearables_being_removed; - -	for (i = 0; i < WT_COUNT; i++) -	{ -		if (wearables_to_remove[i]) -		{ -			// MULTI_WEARABLE: assuming 0th -			LLWearable* wearable = getWearable((EWearableType)i, 0); -			const LLUUID &item_id = getWearableItemID((EWearableType)i,0); -			gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); -			if (wearable) +			else  			{ -				wearables_being_removed.push_back(wearable); +				pushWearable(type,new_wearable);  			} -			removeWearable((EWearableType)i,true,0); +			wearableUpdated(new_wearable); +			checkWearableAgainstInventory(new_wearable);  		}  	}  	gInventory.notifyObservers(); - -	std::vector<LLWearable*>::iterator wearable_iter; - -	for (wearable_iter = wearables_being_removed.begin();  -		 wearable_iter != wearables_being_removed.end(); -		 ++wearable_iter) -	{ -		LLWearable* wearablep = *wearable_iter; -		if (wearablep) -		{ -			wearablep->removeFromAvatar(TRUE); -		} -	} -  	if (isAgentAvatarValid())  	{  		gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); @@ -1766,6 +1641,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);  	LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); +	U32 index = gAgentWearables.getWearableIndex(wearable);  	if (!new_item)  	{  		delete wearable; @@ -1775,8 +1651,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&  	switch(option)  	{  		case 0:  // "Save" -// MULTI_WEARABLE: assuming 0th -			gAgentWearables.saveWearable(wearable->getType(),0); +			gAgentWearables.saveWearable(wearable->getType(),index);  			gAgentWearables.setWearableFinal(new_item, wearable);  			break; @@ -1866,30 +1741,35 @@ void LLAgentWearables::queryWearableCache()  	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)  	{  		const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); -		LLUUID hash; +		LLMD5 hash; +		bool hash_computed = false;  		for (U8 i=0; i < baked_dict->mWearables.size(); i++)  		{  			const EWearableType baked_type = baked_dict->mWearables[i]; -			// MULTI_WEARABLE: not order-dependent  			const U32 num_wearables = getWearableCount(baked_type);  			for (U32 index = 0; index < num_wearables; ++index)  			{  				const LLWearable* wearable = getWearable(baked_type,index);  				if (wearable)  				{ -					hash ^= wearable->getAssetID(); +					LLUUID asset_id = wearable->getAssetID(); +					hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); +					hash_computed = true;  				}  			}  		} -		if (hash.notNull()) +		hash.finalize(); +		if (hash_computed)  		{ -			hash ^= baked_dict->mWearablesHashID; +			LLUUID hash_id; +			hash.raw_digest(hash_id.mData); +			hash_id ^= baked_dict->mWearablesHashID;  			num_queries++;  			// *NOTE: make sure at least one request gets packed  			//llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;  			gMessageSystem->nextBlockFast(_PREHASH_WearableData); -			gMessageSystem->addUUIDFast(_PREHASH_ID, hash); +			gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id);  			gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);  		} @@ -2189,463 +2069,3 @@ void LLAgentWearables::populateMyOutfitsFolder(void)  		outfits->done();  	}  } - -void LLLibraryOutfitsFetch::done() -{ -	// Delay this until idle() routine, since it's a heavy operation and -	// we also can't have it run within notifyObservers. -	doOnIdle(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); -	gInventory.removeObserver(this); // Prevent doOnIdle from being added twice. -} - -void LLLibraryOutfitsFetch::doneIdle() -{ -	gInventory.addObserver(this); // Add this back in since it was taken out during ::done() -	 -	switch (mCurrFetchStep) -	{ -		case LOFS_FOLDER: -			folderDone(); -			mCurrFetchStep = LOFS_OUTFITS; -			break; -		case LOFS_OUTFITS: -			outfitsDone(); -			mCurrFetchStep = LOFS_LIBRARY; -			break; -		case LOFS_LIBRARY: -			libraryDone(); -			mCurrFetchStep = LOFS_IMPORTED; -			break; -		case LOFS_IMPORTED: -			importedFolderDone(); -			mCurrFetchStep = LOFS_CONTENTS; -			break; -		case LOFS_CONTENTS: -			contentsDone(); -			break; -		default: -			llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl; -			mOutfitsPopulated = TRUE; -			break; -	} - -	// We're completely done.  Cleanup. -	if (mOutfitsPopulated) -	{ -		gInventory.removeObserver(this); -		delete this; -		return; -	} -} - -void LLLibraryOutfitsFetch::folderDone(void) -{ -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	// Early out if we already have items in My Outfits. -	if (cat_array.count() > 0 || wearable_array.count() > 0) -	{ -		mOutfitsPopulated = true; -		return; -	} - -	mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); -	mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); - -	// If Library->Clothing->Initial Outfits exists, use that. -	LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); -	gInventory.collectDescendentsIf(mLibraryClothingID, -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.count() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.get(0); -		mLibraryClothingID = cat->getUUID(); -	} - -	mCompleteFolders.clear(); -	 -	// Get the complete information on the items in the inventory. -	uuid_vec_t folders; -	folders.push_back(mClothingID); -	folders.push_back(mLibraryClothingID); -	fetchDescendents(folders); -	if (isEverythingComplete()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::outfitsDone(void) -{ -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Library's Clothing folder -	gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	llassert(cat_array.count() > 0); -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the names and id's of every outfit in the library, skip "Ruth" -		// because it's a low quality legacy outfit -		if (cat->getName() != "Ruth") -		{ -			// Get the name of every outfit in the library  -			folders.push_back(cat->getUUID()); -			mLibraryClothingFolders.push_back(cat->getUUID()); -		} -	} -	cat_array.clear(); -	wearable_array.clear(); - -	// Check if you already have an "Imported Library Clothing" folder -	LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); -	gInventory.collectDescendentsIf(mClothingID,  -									cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, -									matchFolderFunctor); -	if (cat_array.size() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.get(0); -		mImportedClothingID = cat->getUUID(); -	} -	 -	mCompleteFolders.clear(); -	 -	fetchDescendents(folders); -	if (isEverythingComplete()) -	{ -		done(); -	} -} - -class LLLibraryOutfitsCopyDone: public LLInventoryCallback -{ -public: -	LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): -	mFireCount(0), mLibraryOutfitsFetcher(fetcher) -	{ -	} -	 -	virtual ~LLLibraryOutfitsCopyDone() -	{ -		if (!LLApp::isExiting() && mLibraryOutfitsFetcher) -		{ -			gInventory.addObserver(mLibraryOutfitsFetcher); -			mLibraryOutfitsFetcher->done(); -		} -	} -	 -	/* virtual */ void fire(const LLUUID& inv_item) -	{ -		mFireCount++; -	} -private: -	U32 mFireCount; -	LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; -}; - -// Copy the clothing folders from the library into the imported clothing folder -void LLLibraryOutfitsFetch::libraryDone(void) -{ -	if (mImportedClothingID != LLUUID::null) -	{ -		// Skip straight to fetching the contents of the imported folder -		importedFolderFetch(); -		return; -	} - -	// Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. -	gInventory.removeObserver(this); -	 -	LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); -	mImportedClothingID = gInventory.createNewCategory(mClothingID, -													   LLFolderType::FT_NONE, -													   mImportedClothingName); -	// Copy each folder from library into clothing unless it already exists. -	for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); -		 iter != mLibraryClothingFolders.end(); -		 ++iter) -	{ -		const LLUUID& src_folder_id = (*iter); // Library clothing folder ID -		const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); -		if (!cat) -		{ -			llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl; -			continue; -		} -		 -		if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) -		{ -			llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl; -			continue; -		} -		 -		// Don't copy the category if it already exists. -		LLNameCategoryCollector matchFolderFunctor(cat->getName()); -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t wearable_array; -		gInventory.collectDescendentsIf(mImportedClothingID,  -										cat_array, wearable_array,  -										LLInventoryModel::EXCLUDE_TRASH, -										matchFolderFunctor); -		if (cat_array.size() > 0) -		{ -			continue; -		} - -		LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, -															LLFolderType::FT_NONE, -															cat->getName()); -		LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); -	} -} - -void LLLibraryOutfitsFetch::importedFolderFetch(void) -{ -	// Fetch the contents of the Imported Clothing Folder -	uuid_vec_t folders; -	folders.push_back(mImportedClothingID); -	 -	mCompleteFolders.clear(); -	 -	fetchDescendents(folders); -	if (isEverythingComplete()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::importedFolderDone(void) -{ -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	uuid_vec_t folders; -	 -	// Collect the contents of the Imported Clothing folder -	gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,  -								  LLInventoryModel::EXCLUDE_TRASH); -	 -	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); -		 iter != cat_array.end(); -		 ++iter) -	{ -		const LLViewerInventoryCategory *cat = iter->get(); -		 -		// Get the name of every imported outfit -		folders.push_back(cat->getUUID()); -		mImportedClothingFolders.push_back(cat->getUUID()); -	} -	 -	mCompleteFolders.clear(); -	fetchDescendents(folders); -	if (isEverythingComplete()) -	{ -		done(); -	} -} - -void LLLibraryOutfitsFetch::contentsDone(void) -{		 -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	 -	for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); -		 folder_iter != mImportedClothingFolders.end(); -		 ++folder_iter) -	{ -		const LLUUID &folder_id = (*folder_iter); -		const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); -		if (!cat) -		{ -			llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; -			continue; -		} -		 -		// First, make a folder in the My Outfits directory. -		LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); -		 -		cat_array.clear(); -		wearable_array.clear(); -		// Collect the contents of each imported clothing folder, so we can create new outfit links for it -		gInventory.collectDescendents(folder_id, cat_array, wearable_array,  -									  LLInventoryModel::EXCLUDE_TRASH); -		 -		for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); -			 wearable_iter != wearable_array.end(); -			 ++wearable_iter) -		{ -			const LLViewerInventoryItem *item = wearable_iter->get(); -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								new_outfit_folder_id, -								item->getName(), -								LLAssetType::AT_LINK, -								NULL); -		} -	} - -	mOutfitsPopulated = true; -} - -//-------------------------------------------------------------------- -// InitialWearablesFetch -//  -// This grabs contents from the COF and processes them. -// The processing is handled in idle(), i.e. outside of done(), -// to avoid gInventory.notifyObservers recursion. -//-------------------------------------------------------------------- - -LLInitialWearablesFetch::~LLInitialWearablesFetch() -{ -} - -// virtual -void LLInitialWearablesFetch::done() -{ -	// Delay processing the actual results of this so it's not handled within -	// gInventory.notifyObservers.  The results will be handled in the next -	// idle tick instead. -	gInventory.removeObserver(this); -	doOnIdle(boost::bind(&LLInitialWearablesFetch::processContents,this)); -} - -void LLInitialWearablesFetch::processContents() -{ -	// Fetch the wearable items from the Current Outfit Folder -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	LLFindWearables is_wearable; -	gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, is_wearable); - -	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); -	if (wearable_array.count() > 0) -	{ -		LLAppearanceMgr::instance().updateAppearanceFromCOF(); -	} -	else -	{ -		// if we're constructing the COF from the wearables message, we don't have a proper outfit link -		LLAppearanceMgr::instance().setOutfitDirty(true); -		processWearablesMessage(); -	} -	delete this; -} - -class LLFetchAndLinkObserver: public LLInventoryFetchObserver -{ -public: -	LLFetchAndLinkObserver(LLInventoryFetchObserver::item_ref_t& ids): -		m_ids(ids), -		LLInventoryFetchObserver(true) // retry for missing items -	{ -	} -	~LLFetchAndLinkObserver() -	{ -	} -	virtual void done() -	{ -		gInventory.removeObserver(this); - -		// Link to all fetched items in COF. -		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -		for (LLInventoryFetchObserver::item_ref_t::iterator it = m_ids.begin(); -			 it != m_ids.end(); -			 ++it) -		{ -			LLUUID id = *it; -			LLViewerInventoryItem *item = gInventory.getItem(*it); -			if (!item) -			{ -				llwarns << "fetch failed!" << llendl; -				continue; -			} - -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								LLAppearanceMgr::instance().getCOF(), -								item->getName(), -								LLAssetType::AT_LINK, -								link_waiter); -		} -	} -private: -	LLInventoryFetchObserver::item_ref_t m_ids; -}; - -void LLInitialWearablesFetch::processWearablesMessage() -{ -	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. -	{ -		const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); -		LLInventoryFetchObserver::item_ref_t ids; -		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) -		{ -			// Populate the current outfit folder with links to the wearables passed in the message -			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. -			 -			if (wearable_data->mAssetID.notNull()) -			{ -				ids.push_back(wearable_data->mItemID); -			} -			else -			{ -				llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " -				<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; -				delete wearable_data; -			} -		} - -		// Add all current attachments to the requested items as well. -		if (isAgentAvatarValid()) -		{ -			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();  -				 iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) -			{ -				LLViewerJointAttachment* attachment = iter->second; -				if (!attachment) continue; -				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); -					 attachment_iter != attachment->mAttachedObjects.end(); -					 ++attachment_iter) -				{ -					LLViewerObject* attached_object = (*attachment_iter); -					if (!attached_object) continue; -					const LLUUID& item_id = attached_object->getItemID(); -					if (item_id.isNull()) continue; -					ids.push_back(item_id); -				} -			} -		} - -		// Need to fetch the inventory items for ids, then create links to them after they arrive. -		LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); -		fetcher->fetchItems(ids); -		// If no items to be fetched, done will never be triggered. -		// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition. -		if (fetcher->isEverythingComplete()) -		{ -			fetcher->done(); -		} -		else -		{ -			gInventory.addObserver(fetcher); -		} -	} -	else -	{ -		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; -	} -} - - diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp new file mode 100644 index 0000000000..45274a8e2c --- /dev/null +++ b/indra/newview/llagentwearablesfetch.cpp @@ -0,0 +1,516 @@ +/**  + * @file llagentwearablesfetch.cpp + * @brief LLAgentWearblesFetch class implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llagentwearablesfetch.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llvoavatarself.h" + +LLInitialWearablesFetch::LLInitialWearablesFetch() +{ +} + +LLInitialWearablesFetch::~LLInitialWearablesFetch() +{ +} + +// virtual +void LLInitialWearablesFetch::done() +{ +	// Delay processing the actual results of this so it's not handled within +	// gInventory.notifyObservers.  The results will be handled in the next +	// idle tick instead. +	gInventory.removeObserver(this); +	doOnIdle(boost::bind(&LLInitialWearablesFetch::processContents,this)); +} + +void LLInitialWearablesFetch::add(InitialWearableData &data) + +{ +	mAgentInitialWearables.push_back(data); +} + +void LLInitialWearablesFetch::processContents() +{ +	// Fetch the wearable items from the Current Outfit Folder +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	LLFindWearables is_wearable; +	gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,  +									LLInventoryModel::EXCLUDE_TRASH, is_wearable); + +	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); +	if (wearable_array.count() > 0) +	{ +		LLAppearanceMgr::instance().updateAppearanceFromCOF(); +	} +	else +	{ +		// if we're constructing the COF from the wearables message, we don't have a proper outfit link +		LLAppearanceMgr::instance().setOutfitDirty(true); +		processWearablesMessage(); +	} +	delete this; +} + +class LLFetchAndLinkObserver: public LLInventoryFetchObserver +{ +public: +	LLFetchAndLinkObserver(LLInventoryFetchObserver::item_ref_t& ids): +		m_ids(ids), +		LLInventoryFetchObserver(true) // retry for missing items +	{ +	} +	~LLFetchAndLinkObserver() +	{ +	} +	virtual void done() +	{ +		gInventory.removeObserver(this); + +		// Link to all fetched items in COF. +		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; +		for (LLInventoryFetchObserver::item_ref_t::iterator it = m_ids.begin(); +			 it != m_ids.end(); +			 ++it) +		{ +			LLUUID id = *it; +			LLViewerInventoryItem *item = gInventory.getItem(*it); +			if (!item) +			{ +				llwarns << "fetch failed!" << llendl; +				continue; +			} + +			link_inventory_item(gAgent.getID(), +								item->getLinkedUUID(), +								LLAppearanceMgr::instance().getCOF(), +								item->getName(), +								LLAssetType::AT_LINK, +								link_waiter); +		} +	} +private: +	LLInventoryFetchObserver::item_ref_t m_ids; +}; + +void LLInitialWearablesFetch::processWearablesMessage() +{ +	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. +	{ +		const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); +		LLInventoryFetchObserver::item_ref_t ids; +		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) +		{ +			// Populate the current outfit folder with links to the wearables passed in the message +			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. +			 +			if (wearable_data->mAssetID.notNull()) +			{ +				ids.push_back(wearable_data->mItemID); +			} +			else +			{ +				llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " +				<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; +				delete wearable_data; +			} +		} + +		// Add all current attachments to the requested items as well. +		if (isAgentAvatarValid()) +		{ +			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();  +				 iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) +			{ +				LLViewerJointAttachment* attachment = iter->second; +				if (!attachment) continue; +				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +					 attachment_iter != attachment->mAttachedObjects.end(); +					 ++attachment_iter) +				{ +					LLViewerObject* attached_object = (*attachment_iter); +					if (!attached_object) continue; +					const LLUUID& item_id = attached_object->getItemID(); +					if (item_id.isNull()) continue; +					ids.push_back(item_id); +				} +			} +		} + +		// Need to fetch the inventory items for ids, then create links to them after they arrive. +		LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); +		fetcher->fetchItems(ids); +		// If no items to be fetched, done will never be triggered. +		// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition. +		if (fetcher->isEverythingComplete()) +		{ +			fetcher->done(); +		} +		else +		{ +			gInventory.addObserver(fetcher); +		} +	} +	else +	{ +		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; +	} +} + +LLLibraryOutfitsFetch::LLLibraryOutfitsFetch() :  +	mCurrFetchStep(LOFS_FOLDER),  +	mOutfitsPopulated(false)  +{ +	mMyOutfitsID = LLUUID::null; +	mClothingID = LLUUID::null; +	mLibraryClothingID = LLUUID::null; +	mImportedClothingID = LLUUID::null; +	mImportedClothingName = "Imported Library Clothing"; +} + +LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() +{ +} + +void LLLibraryOutfitsFetch::done() +{ +	// Delay this until idle() routine, since it's a heavy operation and +	// we also can't have it run within notifyObservers. +	doOnIdle(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); +	gInventory.removeObserver(this); // Prevent doOnIdle from being added twice. +} + +void LLLibraryOutfitsFetch::doneIdle() +{ +	gInventory.addObserver(this); // Add this back in since it was taken out during ::done() +	 +	switch (mCurrFetchStep) +	{ +		case LOFS_FOLDER: +			folderDone(); +			mCurrFetchStep = LOFS_OUTFITS; +			break; +		case LOFS_OUTFITS: +			outfitsDone(); +			mCurrFetchStep = LOFS_LIBRARY; +			break; +		case LOFS_LIBRARY: +			libraryDone(); +			mCurrFetchStep = LOFS_IMPORTED; +			break; +		case LOFS_IMPORTED: +			importedFolderDone(); +			mCurrFetchStep = LOFS_CONTENTS; +			break; +		case LOFS_CONTENTS: +			contentsDone(); +			break; +		default: +			llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl; +			mOutfitsPopulated = TRUE; +			break; +	} + +	// We're completely done.  Cleanup. +	if (mOutfitsPopulated) +	{ +		gInventory.removeObserver(this); +		delete this; +		return; +	} +} + +void LLLibraryOutfitsFetch::folderDone(void) +{ +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); +	// Early out if we already have items in My Outfits. +	if (cat_array.count() > 0 || wearable_array.count() > 0) +	{ +		mOutfitsPopulated = true; +		return; +	} + +	mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); +	mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); + +	// If Library->Clothing->Initial Outfits exists, use that. +	LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); +	gInventory.collectDescendentsIf(mLibraryClothingID, +									cat_array, wearable_array,  +									LLInventoryModel::EXCLUDE_TRASH, +									matchFolderFunctor); +	if (cat_array.count() > 0) +	{ +		const LLViewerInventoryCategory *cat = cat_array.get(0); +		mLibraryClothingID = cat->getUUID(); +	} + +	mCompleteFolders.clear(); +	 +	// Get the complete information on the items in the inventory. +	uuid_vec_t folders; +	folders.push_back(mClothingID); +	folders.push_back(mLibraryClothingID); +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +void LLLibraryOutfitsFetch::outfitsDone(void) +{ +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	uuid_vec_t folders; +	 +	// Collect the contents of the Library's Clothing folder +	gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); +	 +	llassert(cat_array.count() > 0); +	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); +		 iter != cat_array.end(); +		 ++iter) +	{ +		const LLViewerInventoryCategory *cat = iter->get(); +		 +		// Get the names and id's of every outfit in the library, skip "Ruth" +		// because it's a low quality legacy outfit +		if (cat->getName() != "Ruth") +		{ +			// Get the name of every outfit in the library  +			folders.push_back(cat->getUUID()); +			mLibraryClothingFolders.push_back(cat->getUUID()); +		} +	} +	cat_array.clear(); +	wearable_array.clear(); + +	// Check if you already have an "Imported Library Clothing" folder +	LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); +	gInventory.collectDescendentsIf(mClothingID,  +									cat_array, wearable_array,  +									LLInventoryModel::EXCLUDE_TRASH, +									matchFolderFunctor); +	if (cat_array.size() > 0) +	{ +		const LLViewerInventoryCategory *cat = cat_array.get(0); +		mImportedClothingID = cat->getUUID(); +	} +	 +	mCompleteFolders.clear(); +	 +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +class LLLibraryOutfitsCopyDone: public LLInventoryCallback +{ +public: +	LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): +	mFireCount(0), mLibraryOutfitsFetcher(fetcher) +	{ +	} +	 +	virtual ~LLLibraryOutfitsCopyDone() +	{ +		if (!LLApp::isExiting() && mLibraryOutfitsFetcher) +		{ +			gInventory.addObserver(mLibraryOutfitsFetcher); +			mLibraryOutfitsFetcher->done(); +		} +	} +	 +	/* virtual */ void fire(const LLUUID& inv_item) +	{ +		mFireCount++; +	} +private: +	U32 mFireCount; +	LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; +}; + +// Copy the clothing folders from the library into the imported clothing folder +void LLLibraryOutfitsFetch::libraryDone(void) +{ +	if (mImportedClothingID != LLUUID::null) +	{ +		// Skip straight to fetching the contents of the imported folder +		importedFolderFetch(); +		return; +	} + +	// Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. +	gInventory.removeObserver(this); +	 +	LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); +	mImportedClothingID = gInventory.createNewCategory(mClothingID, +													   LLFolderType::FT_NONE, +													   mImportedClothingName); +	// Copy each folder from library into clothing unless it already exists. +	for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); +		 iter != mLibraryClothingFolders.end(); +		 ++iter) +	{ +		const LLUUID& src_folder_id = (*iter); // Library clothing folder ID +		const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); +		if (!cat) +		{ +			llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl; +			continue; +		} +		 +		if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) +		{ +			llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl; +			continue; +		} +		 +		// Don't copy the category if it already exists. +		LLNameCategoryCollector matchFolderFunctor(cat->getName()); +		LLInventoryModel::cat_array_t cat_array; +		LLInventoryModel::item_array_t wearable_array; +		gInventory.collectDescendentsIf(mImportedClothingID,  +										cat_array, wearable_array,  +										LLInventoryModel::EXCLUDE_TRASH, +										matchFolderFunctor); +		if (cat_array.size() > 0) +		{ +			continue; +		} + +		LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, +															LLFolderType::FT_NONE, +															cat->getName()); +		LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); +	} +} + +void LLLibraryOutfitsFetch::importedFolderFetch(void) +{ +	// Fetch the contents of the Imported Clothing Folder +	uuid_vec_t folders; +	folders.push_back(mImportedClothingID); +	 +	mCompleteFolders.clear(); +	 +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +void LLLibraryOutfitsFetch::importedFolderDone(void) +{ +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	uuid_vec_t folders; +	 +	// Collect the contents of the Imported Clothing folder +	gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,  +								  LLInventoryModel::EXCLUDE_TRASH); +	 +	for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); +		 iter != cat_array.end(); +		 ++iter) +	{ +		const LLViewerInventoryCategory *cat = iter->get(); +		 +		// Get the name of every imported outfit +		folders.push_back(cat->getUUID()); +		mImportedClothingFolders.push_back(cat->getUUID()); +	} +	 +	mCompleteFolders.clear(); +	fetchDescendents(folders); +	if (isEverythingComplete()) +	{ +		done(); +	} +} + +void LLLibraryOutfitsFetch::contentsDone(void) +{		 +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t wearable_array; +	 +	for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); +		 folder_iter != mImportedClothingFolders.end(); +		 ++folder_iter) +	{ +		const LLUUID &folder_id = (*folder_iter); +		const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); +		if (!cat) +		{ +			llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; +			continue; +		} +		 +		// First, make a folder in the My Outfits directory. +		LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); +		 +		cat_array.clear(); +		wearable_array.clear(); +		// Collect the contents of each imported clothing folder, so we can create new outfit links for it +		gInventory.collectDescendents(folder_id, cat_array, wearable_array,  +									  LLInventoryModel::EXCLUDE_TRASH); +		 +		for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); +			 wearable_iter != wearable_array.end(); +			 ++wearable_iter) +		{ +			const LLViewerInventoryItem *item = wearable_iter->get(); +			link_inventory_item(gAgent.getID(), +								item->getLinkedUUID(), +								new_outfit_folder_id, +								item->getName(), +								LLAssetType::AT_LINK, +								NULL); +		} +	} + +	mOutfitsPopulated = true; +} + diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h new file mode 100644 index 0000000000..72063114b8 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.h @@ -0,0 +1,118 @@ +/**  + * @file llagentwearablesinitialfetch.h + * @brief LLAgentWearablesInitialFetch class header file + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + *  + * Copyright (c) 2000-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H +#define LL_LLAGENTWEARABLESINITIALFETCH_H + +#include "llinventoryobserver.h" +#include "llwearabledictionary.h" +#include "lluuid.h" + +//-------------------------------------------------------------------- +// InitialWearablesFetch +//  +// This grabs contents from the COF and processes them. +// The processing is handled in idle(), i.e. outside of done(), +// to avoid gInventory.notifyObservers recursion. +//-------------------------------------------------------------------- +class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver +{ +public: +	LLInitialWearablesFetch(); +	~LLInitialWearablesFetch(); +	virtual void done(); + +	struct InitialWearableData +	{ +		EWearableType mType; +		LLUUID mItemID; +		LLUUID mAssetID; +		InitialWearableData(EWearableType type, LLUUID& itemID, LLUUID& assetID) : +			mType(type), +			mItemID(itemID), +			mAssetID(assetID) +		{} +	}; + +	void add(InitialWearableData &data); + +protected: +	void processWearablesMessage(); +	void processContents(); + +private: +	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; +	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg +}; + +//-------------------------------------------------------------------- +// InitialWearablesFetch +//  +// This grabs outfits from the Library and copies those over to the user's +// outfits folder, typically during first-ever login. +//-------------------------------------------------------------------- +class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver +{ +public: +	enum ELibraryOutfitFetchStep +	{ +		LOFS_FOLDER = 0, +		LOFS_OUTFITS, +		LOFS_LIBRARY, +		LOFS_IMPORTED, +		LOFS_CONTENTS +	}; + +	LLLibraryOutfitsFetch(); +	~LLLibraryOutfitsFetch(); + +	virtual void done(); +	void doneIdle(); +	LLUUID mMyOutfitsID; +	void importedFolderFetch(); +protected: +	void folderDone(void); +	void outfitsDone(void); +	void libraryDone(void); +	void importedFolderDone(void); +	void contentsDone(void); +	enum ELibraryOutfitFetchStep mCurrFetchStep; +	uuid_vec_t mLibraryClothingFolders; +	uuid_vec_t mImportedClothingFolders; +	bool mOutfitsPopulated; +	LLUUID mClothingID; +	LLUUID mLibraryClothingID; +	LLUUID mImportedClothingID; +	std::string mImportedClothingName; +}; + +#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 80d24f75b9..8c5352ded7 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -39,6 +39,7 @@  #include "llfloatercustomize.h"  #include "llgesturemgr.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "llnotificationsutil.h"  #include "llsidepanelappearance.h" @@ -1032,7 +1033,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);  	// Reduce wearables to max of one per type.  	removeDuplicateItems(wear_items); -	filterWearableItems(wear_items, 1); +	filterWearableItems(wear_items, 5);  	// - Attachments: include COF contents only if appending.  	LLInventoryModel::item_array_t obj_items; @@ -1122,7 +1123,6 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo  					items.put(item);  					wearables.put(wearable);  				} -				break;  			}  		}  	} diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index bf7c735488..ba92c33d59 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -31,7 +31,6 @@   */  #include "llviewerprecompiledheaders.h" -  #include "llfavoritesbar.h"  #include "llfloaterreg.h" @@ -47,6 +46,7 @@  #include "llclipboard.h"  #include "llinventoryclipboard.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llfloaterworldmap.h"  #include "lllandmarkactions.h"  #include "llnotificationsutil.h" diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index bea4013a61..0aca12bc5e 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -36,6 +36,7 @@  #include "llinventory.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llinventorymodel.h"  #include "llinventoryclipboard.h" diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 391e63f730..f17c9765b9 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -51,7 +51,9 @@  //#include "llfirstuse.h"  #include "llfloaterreg.h"		// getTypedInstance()  #include "llfocusmgr.h" +#include "llinventoryfunctions.h"  #include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventoryobserver.h"  #include "lllandmarklist.h"  #include "lllineeditor.h" @@ -322,7 +324,7 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)  		// Start speculative download of landmarks  		const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); -		gInventory.startBackgroundFetch(landmark_folder_id); +		LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);  		childSetFocus("location", TRUE);  		gFocusMgr.triggerFocusFlash(); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 90a100bd9b..43743ec37a 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -39,6 +39,7 @@  #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone.  #include "llinventoryfilter.h"  #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventorypanel.h"  #include "llfoldertype.h"  #include "llfloaterinventory.h"// hacked in for the bonus context menu items. @@ -943,7 +944,7 @@ void LLFolderView::draw()  	}  	else  	{ -		if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) +		if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration())  		{  			mStatusText = LLTrans::getString("Searching");  			//font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL,  LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index bb4c75d3ac..ecbaac5743 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -38,6 +38,7 @@  #include "llfoldervieweventlistener.h"  #include "llinventorybridge.h"	// for LLItemBridge in LLInventorySort::operator()  #include "llinventoryfilter.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llpanel.h"  #include "llviewercontrol.h"	// gSavedSettings  #include "llviewerwindow.h"		// Argh, only for setCursor() @@ -992,16 +993,16 @@ void LLFolderViewItem::draw()  		if (getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(),gInventory.getRootFolderID()))  		{  			// Descendent of my inventory. -			root_is_loading = gInventory.myInventoryFetchInProgress(); +			root_is_loading = LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress();  		}  		if (getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(),gInventory.getLibraryRootFolderID()))  		{  			// Descendent of library -			root_is_loading = gInventory.libraryFetchInProgress(); +			root_is_loading = LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress();  		}  		if ( (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) -			|| (LLInventoryModel::backgroundFetchActive() && root_is_loading && mShowLoadStatus) ) +			|| (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && root_is_loading && mShowLoadStatus) )  		{  			std::string load_string = " ( " + LLTrans::getString("LoadingData") + " ) ";  			font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor, @@ -1317,7 +1318,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter)  	// when applying a filter, matching folders get their contents downloaded first  	if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID())))  	{ -		gInventory.startBackgroundFetch(mListener->getUUID()); +		LLInventoryModelBackgroundFetch::instance().start(mListener->getUUID());  	}  	// now query children diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 1a06bef6cb..a848128d67 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -33,6 +33,7 @@  #include "llviewerprecompiledheaders.h"  #include "llinventory.h" +#include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "lltrans.h" diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index dc55aba0db..2b73ed1dcd 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -43,6 +43,7 @@  #include "llhudeffectbeam.h"  #include "llhudeffecttrail.h"  #include "llhudeffectlookat.h" +#include "llhudeffectpointat.h"  #include "llvoicevisualizer.h" diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 9c477791b3..3ec8d11fb0 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -44,6 +44,7 @@  #include "llchiclet.h"  #include "llfloaterreg.h"  #include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container +#include "llinventoryfunctions.h"  #include "lllayoutstack.h"  #include "lllineeditor.h"  #include "lllogchat.h" diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index a6473fb34b..e0f155a6a9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -36,6 +36,7 @@  #include "llfloaterreg.h"  #include "llfontgl.h" +#include "llgl.h"  #include "llrect.h"  #include "llerror.h"  #include "llbutton.h" diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index efd23c36ca..1b6fa6dd9a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -31,10 +31,12 @@   */  #include "llviewerprecompiledheaders.h" +#include "llinventorybridge.h" +  // external projects  #include "lltransfersourceasset.h" -#include "llinventorybridge.h" +  #include "llagent.h"  #include "llagentcamera.h" @@ -52,6 +54,7 @@  #include "llinventoryclipboard.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventorypanel.h"  #include "llnotifications.h"  #include "llnotificationsutil.h" @@ -729,7 +732,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const  		if (*type == DAD_CATEGORY)  		{ -			gInventory.startBackgroundFetch(obj->getUUID()); +			LLInventoryModelBackgroundFetch::instance().start(obj->getUUID());  		}  		rv = TRUE; @@ -1922,50 +1925,6 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id,  	return accept;  } -bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, -									 LLInventoryItem* item) -{ -	// Valid COF items are: -	// - links to wearables (body parts or clothing) -	// - links to attachments -	// - links to gestures -	// - links to ensemble folders -	LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); -	if (linked_item) -	{ -		LLAssetType::EType type = linked_item->getType(); -		return (type == LLAssetType::AT_CLOTHING || -				type == LLAssetType::AT_BODYPART || -				type == LLAssetType::AT_GESTURE || -				type == LLAssetType::AT_OBJECT); -	} -	else -	{ -		LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); -		// BAP remove AT_NONE support after ensembles are fully working? -		return (linked_category && -				((linked_category->getPreferredType() == LLFolderType::FT_NONE) || -				 (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); -	} -} - - -bool LLFindWearables::operator()(LLInventoryCategory* cat, -								 LLInventoryItem* item) -{ -	if(item) -	{ -		if((item->getType() == LLAssetType::AT_CLOTHING) -		   || (item->getType() == LLAssetType::AT_BODYPART)) -		{ -			return TRUE; -		} -	} -	return FALSE; -} - - -  //Used by LLFolderBridge as callback for directory recursion.  class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver  { @@ -4946,9 +4905,9 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,  			if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&&  				//!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )  			{ -				// MULTI_WEARABLE: FIXME HACK - always remove all  				bool do_remove_all = false; -				gAgentWearables.removeWearable( type, do_remove_all, 0 ); +				U32 index = gAgentWearables.getWearableIndex(wearable); +				gAgentWearables.removeWearable( type, do_remove_all, index );  			}  		}  	} diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index cd20d64ca8..1a488175ac 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -37,7 +37,8 @@  // viewer includes  #include "llfoldervieweventlistener.h"  #include "llfolderviewitem.h" -#include "llinventorymodel.h"	// gInventory.backgroundFetchActive() +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llviewercontrol.h"  #include "llfolderview.h" @@ -713,7 +714,7 @@ const std::string& LLInventoryFilter::getFilterText()  		filtered_by_all_types = FALSE;  	} -	if (!gInventory.backgroundFetchActive() +	if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()  		&& filtered_by_type  		&& !filtered_by_all_types)  	{ diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 1e0abeadf1..3e16dfea5f 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -86,6 +86,218 @@  BOOL LLInventoryState::sWearNewClothing = FALSE;  LLUUID LLInventoryState::sWearNewClothingTransactionID; + +///---------------------------------------------------------------------------- +/// LLInventoryCollectFunctor implementations +///---------------------------------------------------------------------------- + +// static +bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item) +{ +	if (!item) +		return false; + +	bool allowed = false; + +	switch(item->getType()) +	{ +	case LLAssetType::AT_CALLINGCARD: +		// not allowed +		break; +		 +	case LLAssetType::AT_OBJECT: +		if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID())) +		{ +			allowed = true; +		} +		break; +		 +	case LLAssetType::AT_BODYPART: +	case LLAssetType::AT_CLOTHING: +		if(!gAgentWearables.isWearingItem(item->getUUID())) +		{ +			allowed = true; +		} +		break; +		 +	default: +		allowed = true; +		break; +	} + +	return allowed; +} + +bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	if(mType == LLAssetType::AT_CATEGORY) +	{ +		if(cat) return TRUE; +	} +	if(item) +	{ +		if(item->getType() == mType) return TRUE; +	} +	return FALSE; +} + +bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	if(mType == LLAssetType::AT_CATEGORY) +	{ +		if(cat) return FALSE; +	} +	if(item) +	{ +		if(item->getType() == mType) return FALSE; +		else return TRUE; +	} +	return TRUE; +} + +bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	if(mType == LLAssetType::AT_CATEGORY) +	{ +		if(cat)  +		{ +			return TRUE; +		} +	} +	if(item) +	{ +		if(item->getType() == mType) +		{ +			LLPermissions perm = item->getPermissions(); +			if ((perm.getMaskBase() & mPerm) == mPerm) +			{ +				return TRUE; +			} +		} +	} +	return FALSE; +} + +bool LLBuddyCollector::operator()(LLInventoryCategory* cat, +								  LLInventoryItem* item) +{ +	if(item) +	{ +		if((LLAssetType::AT_CALLINGCARD == item->getType()) +		   && (!item->getCreatorUUID().isNull()) +		   && (item->getCreatorUUID() != gAgent.getID())) +		{ +			return true; +		} +	} +	return false; +} + + +bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat, +										LLInventoryItem* item) +{ +	if(item) +	{ +		if((LLAssetType::AT_CALLINGCARD == item->getType()) + 		   && (item->getCreatorUUID().notNull()) + 		   && (item->getCreatorUUID() != gAgent.getID())) +		{ +			mSeen.insert(item->getCreatorUUID()); +			return true; +		} +	} +	return false; +} + + +bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat, +											LLInventoryItem* item) +{ +	if(item) +	{ +		if((LLAssetType::AT_CALLINGCARD == item->getType()) +		   && (item->getCreatorUUID() == mBuddyID)) +		{ +			return TRUE; +		} +	} +	return FALSE; +} + + +bool LLNameCategoryCollector::operator()( +	LLInventoryCategory* cat, LLInventoryItem* item) +{ +	if(cat) +	{ +		if (!LLStringUtil::compareInsensitive(mName, cat->getName())) +		{ +			return true; +		} +	} +	return false; +} + +bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, +									 LLInventoryItem* item) +{ +	// Valid COF items are: +	// - links to wearables (body parts or clothing) +	// - links to attachments +	// - links to gestures +	// - links to ensemble folders +	LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); +	if (linked_item) +	{ +		LLAssetType::EType type = linked_item->getType(); +		return (type == LLAssetType::AT_CLOTHING || +				type == LLAssetType::AT_BODYPART || +				type == LLAssetType::AT_GESTURE || +				type == LLAssetType::AT_OBJECT); +	} +	else +	{ +		LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); +		// BAP remove AT_NONE support after ensembles are fully working? +		return (linked_category && +				((linked_category->getPreferredType() == LLFolderType::FT_NONE) || +				 (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); +	} +} + +bool LLFindWearables::operator()(LLInventoryCategory* cat, +								 LLInventoryItem* item) +{ +	if(item) +	{ +		if((item->getType() == LLAssetType::AT_CLOTHING) +		   || (item->getType() == LLAssetType::AT_BODYPART)) +		{ +			return TRUE; +		} +	} +	return FALSE; +} + +///---------------------------------------------------------------------------- +/// LLAssetIDMatches  +///---------------------------------------------------------------------------- +bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	return (item && item->getAssetUUID() == mAssetID); +} + +///---------------------------------------------------------------------------- +/// LLLinkedItemIDMatches  +///---------------------------------------------------------------------------- +bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	return (item &&  +			(item->getIsLinkType()) && +			(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. +} +  void LLSaveFolderState::setApply(BOOL apply)  {  	mApply = apply;  diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 968db84819..eb33763670 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -38,15 +38,221 @@  #include "llfolderview.h"  #include "llfolderviewitem.h" +/******************************************************************************** + **                                                                            ** + **                    INVENTORY COLLECTOR FUNCTIONS + **/ + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCollectFunctor +// +// Base class for LLInventoryModel::collectDescendentsIf() method +// which accepts an instance of one of these objects to use as the +// function to determine if it should be added. Derive from this class +// and override the () operator to return TRUE if you want to collect +// the category or item passed in. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryCollectFunctor +{ +public: +	virtual ~LLInventoryCollectFunctor(){}; +	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + +	static bool itemTransferCommonlyAllowed(LLInventoryItem* item); +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLAssetIDMatches +// +// This functor finds inventory items pointing to the specified asset +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLViewerInventoryItem; + +class LLAssetIDMatches : public LLInventoryCollectFunctor +{ +public: +	LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} +	virtual ~LLAssetIDMatches() {} +	bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +	 +protected: +	LLUUID mAssetID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLinkedItemIDMatches +// +// This functor finds inventory items linked to the specific inventory id. +// Assumes the inventory id is itself not a linked item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLinkedItemIDMatches : public LLInventoryCollectFunctor +{ +public: +	LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} +	virtual ~LLLinkedItemIDMatches() {} +	bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +	 +protected: +	LLUUID mBaseItemID; +}; +  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsType  // -// This is a collection of miscellaneous functions and classes -// that don't fit cleanly into any other class header.  Eventually, -// we should figure out where to put these functions so that we can -// get rid of this generic file. +// Implementation of a LLInventoryCollectFunctor which returns TRUE if +// the type is the type passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLIsType : public LLInventoryCollectFunctor +{ +public: +	LLIsType(LLAssetType::EType type) : mType(type) {} +	virtual ~LLIsType() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +protected: +	LLAssetType::EType mType; +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsNotType  // +// Implementation of a LLInventoryCollectFunctor which returns FALSE if the +// type is the type passed in during construction, otherwise false.  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLIsNotType : public LLInventoryCollectFunctor +{ +public: +	LLIsNotType(LLAssetType::EType type) : mType(type) {} +	virtual ~LLIsNotType() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +protected: +	LLAssetType::EType mType; +}; + +class LLIsTypeWithPermissions : public LLInventoryCollectFunctor +{ +public: +	LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id)  +		: mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} +	virtual ~LLIsTypeWithPermissions() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +protected: +	LLAssetType::EType mType; +	PermissionBit mPerm; +	LLUUID			mAgentID; +	LLUUID			mGroupID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLBuddyCollector +// +// Simple class that collects calling cards that are not null, and not +// the agent. Duplicates are possible. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLBuddyCollector : public LLInventoryCollectFunctor +{ +public: +	LLBuddyCollector() {} +	virtual ~LLBuddyCollector() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLUniqueBuddyCollector +// +// Simple class that collects calling cards that are not null, and not +// the agent. Duplicates are discarded. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLUniqueBuddyCollector : public LLInventoryCollectFunctor +{ +public: +	LLUniqueBuddyCollector() {} +	virtual ~LLUniqueBuddyCollector() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); + +protected: +	std::set<LLUUID> mSeen; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLParticularBuddyCollector +// +// Simple class that collects calling cards that match a particular uuid +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLParticularBuddyCollector : public LLInventoryCollectFunctor +{ +public: +	LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} +	virtual ~LLParticularBuddyCollector() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +protected: +	LLUUID mBuddyID; +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLNameCategoryCollector +// +// Collects categories based on case-insensitive match of prefix +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLNameCategoryCollector : public LLInventoryCollectFunctor +{ +public: +	LLNameCategoryCollector(const std::string& name) : mName(name) {} +	virtual ~LLNameCategoryCollector() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +protected: +	std::string mName; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindCOFValidItems +// +// Collects items that can be legitimately linked to in the COF. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindCOFValidItems : public LLInventoryCollectFunctor +{ +public: +	LLFindCOFValidItems() {} +	virtual ~LLFindCOFValidItems() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +	 +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindWearables +// +// Collects wearables based on item type. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindWearables : public LLInventoryCollectFunctor +{ +public: +	LLFindWearables() {} +	virtual ~LLFindWearables() {} +	virtual bool operator()(LLInventoryCategory* cat, +							LLInventoryItem* item); +}; + +/**                    Inventory Collector Functions + **                                                                            ** + *******************************************************************************/ +  class LLInventoryState  {  public: diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 41f0b430e8..d1cc0ae936 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -57,32 +57,16 @@  #include "process.h"  #endif -BOOL LLInventoryModel::sBackgroundFetchActive = FALSE; -BOOL LLInventoryModel::sAllFoldersFetched = FALSE; -BOOL LLInventoryModel::sMyInventoryFetchStarted = FALSE; -BOOL LLInventoryModel::sLibraryFetchStarted = FALSE; -S32  LLInventoryModel::sNumFetchRetries = 0; -F32  LLInventoryModel::sMinTimeBetweenFetches = 0.3f; -F32  LLInventoryModel::sMaxTimeBetweenFetches = 10.f; -BOOL LLInventoryModel::sTimelyFetchPending = FALSE; -LLFrameTimer LLInventoryModel::sFetchTimer; -S16 LLInventoryModel::sBulkFetchCount = 0; -BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; -  // 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; - -// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue -static std::deque<LLUUID> sFetchQueue; +BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;  ///----------------------------------------------------------------------------  /// Local function declarations, constants, enums, and typedefs  ///----------------------------------------------------------------------------  //BOOL decompress_file(const char* src_filename, const char* dst_filename); -const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; -const S32 MAX_FETCH_RETRIES = 10;  const char CACHE_FORMAT_STRING[] = "%s.inv";   struct InventoryIDPtrLess @@ -1345,542 +1329,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)  	return cat->fetchDescendents();  } -//Initialize statics. -bool LLInventoryModel::isBulkFetchProcessingComplete() -{ -	return sFetchQueue.empty() && sBulkFetchCount<=0; -} - -class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder -{ -	public: -		LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; -		//LLInventoryModelFetchDescendentsResponder() {}; -		void result(const LLSD& content); -		void error(U32 status, const std::string& reason); -	public: -		typedef std::vector<LLViewerInventoryCategory*> folder_ref_t; -	protected: -		LLSD mRequestSD; -}; - -//If we get back a normal response, handle it here -void  LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) -{ -	if (content.has("folders"))	 -	{ - -		for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); -			folder_it != content["folders"].endArray(); -			++folder_it) -		{	 -			LLSD folder_sd = *folder_it; -			 - -			//LLUUID agent_id = folder_sd["agent_id"]; - -			//if(agent_id != gAgent.getID())	//This should never happen. -			//{ -			//	llwarns << "Got a UpdateInventoryItem for the wrong agent." -			//			<< llendl; -			//	break; -			//} - -			LLUUID parent_id = folder_sd["folder_id"]; -			LLUUID owner_id = folder_sd["owner_id"]; -			S32    version  = (S32)folder_sd["version"].asInteger(); -			S32    descendents = (S32)folder_sd["descendents"].asInteger(); -			LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id); - -            if (parent_id.isNull()) -            { -			    LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; -			    for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); -				    item_it != folder_sd["items"].endArray(); -				    ++item_it) -			    {	 -                    const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); -                    if (lost_uuid.notNull()) -                    { -				        LLSD item = *item_it; -				        titem->unpackMessage(item); -				 -                        LLInventoryModel::update_list_t update; -                        LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); -                        update.push_back(new_folder); -                        gInventory.accountForUpdate(update); - -                        titem->setParent(lost_uuid); -                        titem->updateParentOnServer(FALSE); -                        gInventory.updateItem(titem); -                        gInventory.notifyObservers("fetchDescendents"); -                         -                    } -                } -            } - -	        LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); -			if (!pcat) -			{ -				continue; -			} - -			for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); -				category_it != folder_sd["categories"].endArray(); -				++category_it) -			{	 -				LLSD category = *category_it; -				tcategory->fromLLSD(category);  -							 -				if (LLInventoryModel::sMyInventoryFetchStarted || -					LLInventoryModel::sLibraryFetchStarted) -				{ -					sFetchQueue.push_back(tcategory->getUUID()); -				} -				else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) -				{ -					gInventory.updateCategory(tcategory); -				} - -			} -			LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; -			for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); -				item_it != folder_sd["items"].endArray(); -				++item_it) -			{	 -				LLSD item = *item_it; -				titem->unpackMessage(item); -				 -				gInventory.updateItem(titem); -			} - -			// set version and descendentcount according to message. -			LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); -			if(cat) -			{ -				cat->setVersion(version); -				cat->setDescendentCount(descendents); -				cat->determineFolderType(); -			} - -		} -	} -		 -	if (content.has("bad_folders")) -	{ -		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); -			folder_it != content["bad_folders"].endArray(); -			++folder_it) -		{	 -			LLSD folder_sd = *folder_it; -			 -			//These folders failed on the dataserver.  We probably don't want to retry them. -			llinfos << "Folder " << folder_sd["folder_id"].asString()  -					<< "Error: " << folder_sd["error"].asString() << llendl; -		} -	} - -	LLInventoryModel::incrBulkFetch(-1); -	 -	if (LLInventoryModel::isBulkFetchProcessingComplete()) -	{ -		llinfos << "Inventory fetch completed" << llendl; -		LLInventoryModel::setAllFoldersFetched(); -	} -	 -	gInventory.notifyObservers("fetchDescendents"); -} - -//If we get back an error (not found, etc...), handle it here -void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) -{ -	llinfos << "LLInventoryModelFetchDescendentsResponder::error " -		<< status << ": " << reason << llendl; -						 -	LLInventoryModel::incrBulkFetch(-1); - -	if (status==499)		//timed out.  Let's be awesome! -	{ -		for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); -			folder_it != mRequestSD["folders"].endArray(); -			++folder_it) -		{	 -			LLSD folder_sd = *folder_it; -			LLUUID folder_id = folder_sd["folder_id"]; -			sFetchQueue.push_front(folder_id); -		} -	} -	else -	{ -		if (LLInventoryModel::isBulkFetchProcessingComplete()) -		{ -			LLInventoryModel::setAllFoldersFetched(); -		} -	} -	gInventory.notifyObservers("fetchDescendents"); -} - -//static   Bundle up a bunch of requests to send all at once. -void LLInventoryModel::bulkFetch(std::string url) -{ -	//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. -	//If there are items in sFetchQueue, we want to check the time since the last bulkFetch was  -	//sent.  If it exceeds our retry time, go ahead and fire off another batch.   -	//Stopbackgroundfetch will be run from the Responder instead of here.   - -	S16 max_concurrent_fetches=8; -	F32 new_min_time = 0.5f;			//HACK!  Clean this up when old code goes away entirely. -	if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time;  //HACK!  See above. -	 -	if(gDisconnected  -	|| sBulkFetchCount > max_concurrent_fetches -	|| sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches) -	{ -		return; // just bail if we are disconnected. -	}	 - -	U32 folder_count=0; -	U32 max_batch_size=5; - -	U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; - -	LLSD body; -	LLSD body_lib; -	while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) ) -	{ -        if (sFetchQueue.front().isNull()) //DEV-17797 -        { -			LLSD folder_sd; -			folder_sd["folder_id"]		= LLUUID::null.asString(); -			folder_sd["owner_id"]		= gAgent.getID(); -			folder_sd["sort_order"]		= (LLSD::Integer)sort_order; -			folder_sd["fetch_folders"]	= (LLSD::Boolean)FALSE; -			folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE; -			body["folders"].append(folder_sd); -            folder_count++; -        } -        else -        { -				 - -		    LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); -		 -		    if (cat) -		    { -			    if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) -			    { -				    LLSD folder_sd; -				    folder_sd["folder_id"]		= cat->getUUID(); -				    folder_sd["owner_id"]		= cat->getOwnerID(); -				    folder_sd["sort_order"]		= (LLSD::Integer)sort_order; -				    folder_sd["fetch_folders"]	= TRUE; //(LLSD::Boolean)sFullFetchStarted; -				    folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE; -				     -				    if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) -					    body_lib["folders"].append(folder_sd); -				    else -					    body["folders"].append(folder_sd); -				    folder_count++; -			    } -			    if (sMyInventoryFetchStarted || -					sLibraryFetchStarted) -			    {	//Already have this folder but append child folders to list. -				    // add all children to queue -				    parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); -				    if (cat_it != gInventory.mParentChildCategoryTree.end()) -				    { -					    cat_array_t* child_categories = cat_it->second; -     -					    for (S32 child_num = 0; child_num < child_categories->count(); child_num++) -					    { -						    sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); -					    } -				    } -     -			    } -		    } -        } -		sFetchQueue.pop_front(); -	} -		 -		if (folder_count > 0) -		{ -			sBulkFetchCount++; -			if (body["folders"].size()) -			{ -				LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0); -			} -			if (body_lib["folders"].size()) -			{ -				std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); -				LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0); -			} -			sFetchTimer.reset(); -		} -	else if (isBulkFetchProcessingComplete()) -	{ -		setAllFoldersFetched(); -	}	 -} - -bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) -{ -	for (std::deque<LLUUID>::iterator it = sFetchQueue.begin(); -		 it != sFetchQueue.end(); ++it) -	{ -		const LLUUID& fetch_id = *it; -		if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) -			return false; -	} -	return true; -} - -/* static */ -bool LLInventoryModel::libraryFetchStarted() -{ -	return sLibraryFetchStarted; -} - -/* static */ -bool LLInventoryModel::libraryFetchCompleted() -{ -	return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID()); -} - -/* static */ -bool LLInventoryModel::libraryFetchInProgress() -{ -	return libraryFetchStarted() && !libraryFetchCompleted(); -} -	 -/* static */ -bool LLInventoryModel::myInventoryFetchStarted() -{ -	return sMyInventoryFetchStarted; -} - -/* static */ -bool LLInventoryModel::myInventoryFetchCompleted() -{ -	return myInventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID()); -} - -/* static */ -bool LLInventoryModel::myInventoryFetchInProgress() -{ -	return myInventoryFetchStarted() && !myInventoryFetchCompleted(); -} - -// static -bool LLInventoryModel::isEverythingFetched() -{ -	return sAllFoldersFetched; -} - -//static -BOOL LLInventoryModel::backgroundFetchActive() -{ -	return sBackgroundFetchActive; -} - -void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id) -{ -	if (!sAllFoldersFetched) -	{ -		sBackgroundFetchActive = TRUE; -		if (cat_id.isNull()) -		{ -			if (!sMyInventoryFetchStarted) -			{ -				sMyInventoryFetchStarted = TRUE; -				sFetchQueue.push_back(gInventory.getRootFolderID()); -				gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); -			} -			if (!sLibraryFetchStarted) -			{ -				sLibraryFetchStarted = TRUE; -				sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); -				gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); -			} -		} -		else -		{ -			// specific folder requests go to front of queue -			if (sFetchQueue.empty() || sFetchQueue.front() != cat_id) -			{ -				sFetchQueue.push_front(cat_id); -				gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); -			} -			if (cat_id == gInventory.getLibraryRootFolderID()) -			{ -				sLibraryFetchStarted = TRUE; -			} -			if (cat_id == gInventory.getRootFolderID()) -			{ -				sMyInventoryFetchStarted = TRUE; -			} -		} -	} -} - -//static -void LLInventoryModel::findLostItems() -{ -	sBackgroundFetchActive = TRUE; -    sFetchQueue.push_back(LLUUID::null); -    gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); -} - -//static -void LLInventoryModel::stopBackgroundFetch() -{ -	if (sBackgroundFetchActive) -	{ -		sBackgroundFetchActive = FALSE; -		gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL); -		sBulkFetchCount=0; -		sMinTimeBetweenFetches=0.0f; -	} -} - -// static -void LLInventoryModel::setAllFoldersFetched() -{ -	if (sMyInventoryFetchStarted && -		sLibraryFetchStarted) -	{ -		sAllFoldersFetched = TRUE; -	} -	stopBackgroundFetch(); -} - -//static  -void LLInventoryModel::backgroundFetch(void*) -{ -	if (sBackgroundFetchActive && gAgent.getRegion()) -	{ -		//If we'll be using the capability, we'll be sending batches and the background thing isn't as important. -		std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");    -		if (!url.empty())  -		{ -			bulkFetch(url); -			return; -		} -		 -		//DEPRECATED OLD CODE FOLLOWS. -		// no more categories to fetch, stop fetch process -		if (sFetchQueue.empty()) -		{ -			llinfos << "Inventory fetch completed" << llendl; - -			setAllFoldersFetched(); -			return; -		} - -		F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f); -		F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f); -		if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time) -		{ -			// double timeouts on failure -			sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f); -			sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f); -			llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; -			// fetch is no longer considered "timely" although we will wait for full time-out -			sTimelyFetchPending = FALSE; -		} - -		while(1) -		{ -			if (sFetchQueue.empty()) -			{ -				break; -			} - -			if(gDisconnected) -			{ -				// just bail if we are disconnected. -				break; -			} - -			LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); - -			// category has been deleted, remove from queue. -			if (!cat) -			{ -				sFetchQueue.pop_front(); -				continue; -			} -			 -			if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches &&  -				LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) -			{ -				// category exists but has no children yet, fetch the descendants -				// for now, just request every time and rely on retry timer to throttle -				if (cat->fetchDescendents()) -				{ -					sFetchTimer.reset(); -					sTimelyFetchPending = TRUE; -				} -				else -				{ -					//  The catagory also tracks if it has expired and here it says it hasn't -					//  yet.  Get out of here because nothing is going to happen until we -					//  update the timers. -					break; -				} -			} -			// do I have all my children? -			else if (gInventory.isCategoryComplete(sFetchQueue.front())) -			{ -				// finished with this category, remove from queue -				sFetchQueue.pop_front(); - -				// add all children to queue -				parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); -				if (cat_it != gInventory.mParentChildCategoryTree.end()) -				{ -					cat_array_t* child_categories = cat_it->second; - -					for (S32 child_num = 0; child_num < child_categories->count(); child_num++) -					{ -						sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); -					} -				} - -				// we received a response in less than the fast time -				if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time) -				{ -					// shrink timeouts based on success -					sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f); -					sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f); -					//llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; -				} - -				sTimelyFetchPending = FALSE; -				continue; -			} -			else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches) -			{ -				// received first packet, but our num descendants does not match db's num descendants -				// so try again later -				LLUUID fetch_id = sFetchQueue.front(); -				sFetchQueue.pop_front(); - -				if (sNumFetchRetries++ < MAX_FETCH_RETRIES) -				{ -					// push on back of queue -					sFetchQueue.push_back(fetch_id); -				} -				sTimelyFetchPending = FALSE; -				sFetchTimer.reset(); -				break; -			} - -			// not enough time has elapsed to do a new fetch -			break; -		} -	} -}  void LLInventoryModel::cache(  	const LLUUID& parent_folder_id, @@ -3764,205 +3212,6 @@ void LLInventoryModel::dumpInventory() const  }  ///---------------------------------------------------------------------------- -/// LLInventoryCollectFunctor implementations -///---------------------------------------------------------------------------- - -// static -bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item) -{ -	if (!item) -		return false; - -	bool allowed = false; - -	switch(item->getType()) -	{ -	case LLAssetType::AT_CALLINGCARD: -		// not allowed -		break; -		 -	case LLAssetType::AT_OBJECT: -		if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID())) -		{ -			allowed = true; -		} -		break; -		 -	case LLAssetType::AT_BODYPART: -	case LLAssetType::AT_CLOTHING: -		if(!gAgentWearables.isWearingItem(item->getUUID())) -		{ -			allowed = true; -		} -		break; -		 -	default: -		allowed = true; -		break; -	} - -	return allowed; -} - -bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ -	if(mType == LLAssetType::AT_CATEGORY) -	{ -		if(cat) return TRUE; -	} -	if(item) -	{ -		if(item->getType() == mType) return TRUE; -	} -	return FALSE; -} - -bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ -	if(mType == LLAssetType::AT_CATEGORY) -	{ -		if(cat) return FALSE; -	} -	if(item) -	{ -		if(item->getType() == mType) return FALSE; -		else return TRUE; -	} -	return TRUE; -} - -bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ -	if(mType == LLAssetType::AT_CATEGORY) -	{ -		if(cat)  -		{ -			return TRUE; -		} -	} -	if(item) -	{ -		if(item->getType() == mType) -		{ -			LLPermissions perm = item->getPermissions(); -			if ((perm.getMaskBase() & mPerm) == mPerm) -			{ -				return TRUE; -			} -		} -	} -	return FALSE; -} - - -//bool LLIsClone::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -//{ -//	if(cat) return FALSE; -//	if(item) -//	{ -//		if(mItemMap->getType() == LLAssetType::AT_CALLINGCARD) -//		{ -//			if((item->getType() == LLAssetType::AT_CALLINGCARD) -//			   && !(item->getCreatorUUID().isNull()) -//			   && (item->getCreatorUUID() == mItemMap->getCreatorUUID())) -//			{ -//				return TRUE; -//			} -//		} -//		else -//		{ -//			if((item->getType() == mItemMap->getType()) -//			   && !(item->getAssetUUID().isNull()) -//			   && (item->getAssetUUID() == mItemMap->getAssetUUID()) -//			   && (item->getName() == mItemMap->getName())) -//			{ -//				return TRUE; -//			} -//		} -//	} -//	return FALSE; -//} - -bool LLBuddyCollector::operator()(LLInventoryCategory* cat, -								  LLInventoryItem* item) -{ -	if(item) -	{ -		if((LLAssetType::AT_CALLINGCARD == item->getType()) -		   && (!item->getCreatorUUID().isNull()) -		   && (item->getCreatorUUID() != gAgent.getID())) -		{ -			return true; -		} -	} -	return false; -} - - -bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat, -										LLInventoryItem* item) -{ -	if(item) -	{ -		if((LLAssetType::AT_CALLINGCARD == item->getType()) - 		   && (item->getCreatorUUID().notNull()) - 		   && (item->getCreatorUUID() != gAgent.getID())) -		{ -			mSeen.insert(item->getCreatorUUID()); -			return true; -		} -	} -	return false; -} - - -bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat, -											LLInventoryItem* item) -{ -	if(item) -	{ -		if((LLAssetType::AT_CALLINGCARD == item->getType()) -		   && (item->getCreatorUUID() == mBuddyID)) -		{ -			return TRUE; -		} -	} -	return FALSE; -} - - -bool LLNameCategoryCollector::operator()( -	LLInventoryCategory* cat, LLInventoryItem* item) -{ -	if(cat) -	{ -		if (!LLStringUtil::compareInsensitive(mName, cat->getName())) -		{ -			return true; -		} -	} -	return false; -} - -///---------------------------------------------------------------------------- -/// LLAssetIDMatches  -///---------------------------------------------------------------------------- -bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ -	return (item && item->getAssetUUID() == mAssetID); -} - -///---------------------------------------------------------------------------- -/// LLLinkedItemIDMatches  -///---------------------------------------------------------------------------- -bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ -	return (item &&  -			(item->getIsLinkType()) && -			(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. -} - -///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 2a2b48ce3c..b7c1b57397 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -81,7 +81,6 @@ public:  		CHILDREN_MAYBE  	}; -	// These are used a lot...  	typedef LLDynamicArray<LLPointer<LLViewerInventoryCategory> > cat_array_t;  	typedef LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array_t;  	typedef std::set<LLUUID> changed_items_t; @@ -368,8 +367,6 @@ public:  	// Utility Functions  	void removeItem(const LLUUID& item_id); -    static void findLostItems(); -  	// Data about the agent's root folder and root library folder  	// are stored here, rather than in LLAgent where it used to be, because  	// gInventory is a singleton and represents the agent's inventory. @@ -501,12 +498,6 @@ private:  	LLUUID mLibraryRootFolderID;  	LLUUID mLibraryOwnerID; -	static BOOL sTimelyFetchPending; -	static S32  sNumFetchRetries; -	static LLFrameTimer sFetchTimer; -	static F32 sMinTimeBetweenFetches; -	static F32 sMaxTimeBetweenFetches; -  	// Expected inventory cache version  	const static S32 sCurrentInvCacheVersion; @@ -532,41 +523,6 @@ public:  	// *NOTE: DEBUG functionality  	void dumpInventory() const; - -	//////////////////////////////////////////////////////////////////////////////// -	// Bulk fetch -public: -	// Start and stop background breadth-first fetching of inventory contents. -	// This gets triggered when performing a filter-search -	void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null); -	static BOOL backgroundFetchActive(); -	static bool isEverythingFetched(); -	static void backgroundFetch(void*); // background fetch idle function -	static void incrBulkFetch(S16 fetching) {  sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; } -	static void stopBackgroundFetch(); // stop fetch process -	static bool isBulkFetchProcessingComplete(); - -	// Add categories to a list to be fetched in bulk. -	static void bulkFetch(std::string url); - -	static bool libraryFetchStarted(); -	static bool libraryFetchCompleted(); -	static bool libraryFetchInProgress(); -	 -	static bool myInventoryFetchStarted(); -	static bool myInventoryFetchCompleted(); -	static bool myInventoryFetchInProgress(); -	 -private: - 	static BOOL sMyInventoryFetchStarted; -	static BOOL sLibraryFetchStarted; -	static BOOL sAllFoldersFetched;  -	static void setAllFoldersFetched(); - -	// completing the fetch once per session should be sufficient -	static BOOL sBackgroundFetchActive; -	static S16 sBulkFetchCount; -  	////////////////////////////////////////////////////////////////////////////////  	// Login status  public: @@ -578,234 +534,5 @@ private:  // a special inventory model for the agent  extern LLInventoryModel gInventory; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryCollectFunctor -// -// Base class for LLInventoryModel::collectDescendentsIf() method -// which accepts an instance of one of these objects to use as the -// function to determine if it should be added. Derive from this class -// and override the () operator to return TRUE if you want to collect -// the category or item passed in. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryCollectFunctor -{ -public: -	virtual ~LLInventoryCollectFunctor(){}; -	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; - -	static bool itemTransferCommonlyAllowed(LLInventoryItem* item); -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLAssetIDMatches -// -// This functor finds inventory items pointing to the specified asset -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem; - -class LLAssetIDMatches : public LLInventoryCollectFunctor -{ -public: -	LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} -	virtual ~LLAssetIDMatches() {} -	bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); -	 -protected: -	LLUUID mAssetID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLLinkedItemIDMatches -// -// This functor finds inventory items linked to the specific inventory id. -// Assumes the inventory id is itself not a linked item. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLLinkedItemIDMatches : public LLInventoryCollectFunctor -{ -public: -	LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} -	virtual ~LLLinkedItemIDMatches() {} -	bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); -	 -protected: -	LLUUID mBaseItemID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsType -// -// Implementation of a LLInventoryCollectFunctor which returns TRUE if -// the type is the type passed in during construction. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIsType : public LLInventoryCollectFunctor -{ -public: -	LLIsType(LLAssetType::EType type) : mType(type) {} -	virtual ~LLIsType() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -protected: -	LLAssetType::EType mType; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsNotType -// -// Implementation of a LLInventoryCollectFunctor which returns FALSE if the -// type is the type passed in during construction, otherwise false. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIsNotType : public LLInventoryCollectFunctor -{ -public: -	LLIsNotType(LLAssetType::EType type) : mType(type) {} -	virtual ~LLIsNotType() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -protected: -	LLAssetType::EType mType; -}; - -class LLIsTypeWithPermissions : public LLInventoryCollectFunctor -{ -public: -	LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id)  -		: mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} -	virtual ~LLIsTypeWithPermissions() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -protected: -	LLAssetType::EType mType; -	PermissionBit mPerm; -	LLUUID			mAgentID; -	LLUUID			mGroupID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsClone -// -// Implementation of a LLInventoryCollectFunctor which returns TRUE if -// the object is a clone of the item passed in during -// construction. -// -// *NOTE: Since clone information is determined based off of asset id -// (or creator with calling cards), if the id is NULL, it has no -// clones - even itself. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -//class LLIsClone : public LLInventoryCollectFunctor -//{ -//public: -//	LLIsClone(LLViewerInventoryItem* item) : mItem(item) {} -//	virtual ~LLIsClone() {} -//	virtual bool operator()(LLViewerInventoryCategory* cat, -//							LLViewerInventoryItem* item); -//protected: -//	LLPointer<LLViewerInventoryItem> mItem; -//}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLBuddyCollector -// -// Simple class that collects calling cards that are not null, and not -// the agent. Duplicates are possible. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLBuddyCollector : public LLInventoryCollectFunctor -{ -public: -	LLBuddyCollector() {} -	virtual ~LLBuddyCollector() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLUniqueBuddyCollector -// -// Simple class that collects calling cards that are not null, and not -// the agent. Duplicates are discarded. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLUniqueBuddyCollector : public LLInventoryCollectFunctor -{ -public: -	LLUniqueBuddyCollector() {} -	virtual ~LLUniqueBuddyCollector() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); - -protected: -	std::set<LLUUID> mSeen; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLParticularBuddyCollector -// -// Simple class that collects calling cards that match a particular uuid -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLParticularBuddyCollector : public LLInventoryCollectFunctor -{ -public: -	LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} -	virtual ~LLParticularBuddyCollector() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -protected: -	LLUUID mBuddyID; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLNameCategoryCollector -// -// Collects categories based on case-insensitive match of prefix -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLNameCategoryCollector : public LLInventoryCollectFunctor -{ -public: -	LLNameCategoryCollector(const std::string& name) : mName(name) {} -	virtual ~LLNameCategoryCollector() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -protected: -	std::string mName; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFindCOFValidItems -// -// Collects items that can be legitimately linked to in the COF. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLFindCOFValidItems : public LLInventoryCollectFunctor -{ -public: -	LLFindCOFValidItems() {} -	virtual ~LLFindCOFValidItems() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -	 -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFindWearables -// -// Collects wearables based on item type. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLFindWearables : public LLInventoryCollectFunctor -{ -public: -	LLFindWearables() {} -	virtual ~LLFindWearables() {} -	virtual bool operator()(LLInventoryCategory* cat, -							LLInventoryItem* item); -}; -  #endif // LL_LLINVENTORYMODEL_H diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp new file mode 100644 index 0000000000..72e5c0dd75 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -0,0 +1,603 @@ +/**  + * @file llinventorymodel.cpp + * @brief Implementation of the inventory model used to track agent inventory. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llinventorymodelbackgroundfetch.h" + +// Seraph clean this up +#include "llagent.h" +#include "llinventorypanel.h" +#include "llviewercontrol.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llappviewer.h" +#include "llviewerregion.h" +#include "llcallbacklist.h" + +const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; +const S32 MAX_FETCH_RETRIES = 10; + +// RN: for some reason, using std::queue in the header file confuses the compiler which thinks it's an xmlrpc_queue +static std::deque<LLUUID> sFetchQueue; +bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) +{ +	for (std::deque<LLUUID>::iterator it = sFetchQueue.begin(); +		 it != sFetchQueue.end(); ++it) +	{ +		const LLUUID& fetch_id = *it; +		if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) +			return false; +	} +	return true; +} + + +LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : +	mBackgroundFetchActive(FALSE), +	mAllFoldersFetched(FALSE), +	mInventoryFetchStarted(FALSE), +	mLibraryFetchStarted(FALSE), +	mNumFetchRetries(0), +	mMinTimeBetweenFetches(0.3f), +	mMaxTimeBetweenFetches(10.f), +	mTimelyFetchPending(FALSE), +	mBulkFetchCount(0) +{ +} + +LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() +{ +} + +bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() +{ +	return sFetchQueue.empty() && mBulkFetchCount<=0; +} + +bool LLInventoryModelBackgroundFetch::libraryFetchStarted() +{ +	return mLibraryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::libraryFetchCompleted() +{ +	return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::libraryFetchInProgress() +{ +	return libraryFetchStarted() && !libraryFetchCompleted(); +} +	 +bool LLInventoryModelBackgroundFetch::inventoryFetchStarted() +{ +	return mInventoryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() +{ +	return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() +{ +	return inventoryFetchStarted() && !inventoryFetchCompleted(); +} + +bool LLInventoryModelBackgroundFetch::isEverythingFetched() +{ +	return mAllFoldersFetched; +} + +BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() +{ +	return mBackgroundFetchActive; +} + +void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id) +{ +	if (!mAllFoldersFetched) +	{ +		mBackgroundFetchActive = TRUE; +		if (cat_id.isNull()) +		{ +			if (!mInventoryFetchStarted) +			{ +				mInventoryFetchStarted = TRUE; +				sFetchQueue.push_back(gInventory.getRootFolderID()); +				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +			} +			if (!mLibraryFetchStarted) +			{ +				mLibraryFetchStarted = TRUE; +				sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); +				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +			} +		} +		else +		{ +			// specific folder requests go to front of queue +			if (sFetchQueue.empty() || sFetchQueue.front() != cat_id) +			{ +				sFetchQueue.push_front(cat_id); +				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +			} +			if (cat_id == gInventory.getLibraryRootFolderID()) +			{ +				mLibraryFetchStarted = TRUE; +			} +			if (cat_id == gInventory.getRootFolderID()) +			{ +				mInventoryFetchStarted = TRUE; +			} +		} +	} +} + +void LLInventoryModelBackgroundFetch::findLostItems() +{ +	mBackgroundFetchActive = TRUE; +    sFetchQueue.push_back(LLUUID::null); +    gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +} + +void LLInventoryModelBackgroundFetch::stopBackgroundFetch() +{ +	if (mBackgroundFetchActive) +	{ +		mBackgroundFetchActive = FALSE; +		gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +		mBulkFetchCount=0; +		mMinTimeBetweenFetches=0.0f; +	} +} + +void LLInventoryModelBackgroundFetch::setAllFoldersFetched() +{ +	if (mInventoryFetchStarted && +		mLibraryFetchStarted) +	{ +		mAllFoldersFetched = TRUE; +	} +	stopBackgroundFetch(); +} + +void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) +{ +	LLInventoryModelBackgroundFetch::instance().backgroundFetch(); +} + +void LLInventoryModelBackgroundFetch::backgroundFetch() +{ +	if (mBackgroundFetchActive && gAgent.getRegion()) +	{ +		//If we'll be using the capability, we'll be sending batches and the background thing isn't as important. +		std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");    +		if (!url.empty())  +		{ +			bulkFetch(url); +			return; +		} +		 +		//DEPRECATED OLD CODE FOLLOWS. +		// no more categories to fetch, stop fetch process +		if (sFetchQueue.empty()) +		{ +			llinfos << "Inventory fetch completed" << llendl; + +			setAllFoldersFetched(); +			return; +		} + +		F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f); +		F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f); +		if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time) +		{ +			// double timeouts on failure +			mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f); +			mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f); +			llinfos << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; +			// fetch is no longer considered "timely" although we will wait for full time-out +			mTimelyFetchPending = FALSE; +		} + +		while(1) +		{ +			if (sFetchQueue.empty()) +			{ +				break; +			} + +			if(gDisconnected) +			{ +				// just bail if we are disconnected. +				break; +			} + +			LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); + +			// category has been deleted, remove from queue. +			if (!cat) +			{ +				sFetchQueue.pop_front(); +				continue; +			} +			 +			if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches &&  +				LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) +			{ +				// category exists but has no children yet, fetch the descendants +				// for now, just request every time and rely on retry timer to throttle +				if (cat->fetchDescendents()) +				{ +					mFetchTimer.reset(); +					mTimelyFetchPending = TRUE; +				} +				else +				{ +					//  The catagory also tracks if it has expired and here it says it hasn't +					//  yet.  Get out of here because nothing is going to happen until we +					//  update the timers. +					break; +				} +			} +			// do I have all my children? +			else if (gInventory.isCategoryComplete(sFetchQueue.front())) +			{ +				// finished with this category, remove from queue +				sFetchQueue.pop_front(); + +				// add all children to queue +				LLInventoryModel::cat_array_t* categories; +				LLInventoryModel::item_array_t* items; +				gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); +				for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); +					 it != categories->end(); +					 ++it) +				{ +					sFetchQueue.push_back((*it)->getUUID()); +				} + +				// we received a response in less than the fast time +				if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) +				{ +					// shrink timeouts based on success +					mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); +					mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); +					//llinfos << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; +				} + +				mTimelyFetchPending = FALSE; +				continue; +			} +			else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) +			{ +				// received first packet, but our num descendants does not match db's num descendants +				// so try again later +				LLUUID fetch_id = sFetchQueue.front(); +				sFetchQueue.pop_front(); + +				if (mNumFetchRetries++ < MAX_FETCH_RETRIES) +				{ +					// push on back of queue +					sFetchQueue.push_back(fetch_id); +				} +				mTimelyFetchPending = FALSE; +				mFetchTimer.reset(); +				break; +			} + +			// not enough time has elapsed to do a new fetch +			break; +		} +	} +} + +void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching)  +{   +	mBulkFetchCount += fetching;  +	if (mBulkFetchCount < 0) +	{ +		mBulkFetchCount = 0;  +	} +} + + +class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder +{ +	public: +		LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; +		//LLInventoryModelFetchDescendentsResponder() {}; +		void result(const LLSD& content); +		void error(U32 status, const std::string& reason); +	public: +		typedef std::vector<LLViewerInventoryCategory*> folder_ref_t; +	protected: +		LLSD mRequestSD; +}; + +//If we get back a normal response, handle it here +void  LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +{ +	if (content.has("folders"))	 +	{ + +		for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); +			folder_it != content["folders"].endArray(); +			++folder_it) +		{	 +			LLSD folder_sd = *folder_it; +			 + +			//LLUUID agent_id = folder_sd["agent_id"]; + +			//if(agent_id != gAgent.getID())	//This should never happen. +			//{ +			//	llwarns << "Got a UpdateInventoryItem for the wrong agent." +			//			<< llendl; +			//	break; +			//} + +			LLUUID parent_id = folder_sd["folder_id"]; +			LLUUID owner_id = folder_sd["owner_id"]; +			S32    version  = (S32)folder_sd["version"].asInteger(); +			S32    descendents = (S32)folder_sd["descendents"].asInteger(); +			LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id); + +            if (parent_id.isNull()) +            { +			    LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; +			    for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); +				    item_it != folder_sd["items"].endArray(); +				    ++item_it) +			    {	 +                    const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); +                    if (lost_uuid.notNull()) +                    { +				        LLSD item = *item_it; +				        titem->unpackMessage(item); +				 +                        LLInventoryModel::update_list_t update; +                        LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); +                        update.push_back(new_folder); +                        gInventory.accountForUpdate(update); + +                        titem->setParent(lost_uuid); +                        titem->updateParentOnServer(FALSE); +                        gInventory.updateItem(titem); +                        gInventory.notifyObservers("fetchDescendents"); +                         +                    } +                } +            } + +	        LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); +			if (!pcat) +			{ +				continue; +			} + +			for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); +				category_it != folder_sd["categories"].endArray(); +				++category_it) +			{	 +				LLSD category = *category_it; +				tcategory->fromLLSD(category);  +							 +				if (LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted() || +					LLInventoryModelBackgroundFetch::instance().libraryFetchStarted()) +				{ +					sFetchQueue.push_back(tcategory->getUUID()); +				} +				else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) +				{ +					gInventory.updateCategory(tcategory); +				} + +			} +			LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; +			for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); +				item_it != folder_sd["items"].endArray(); +				++item_it) +			{	 +				LLSD item = *item_it; +				titem->unpackMessage(item); +				 +				gInventory.updateItem(titem); +			} + +			// set version and descendentcount according to message. +			LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); +			if(cat) +			{ +				cat->setVersion(version); +				cat->setDescendentCount(descendents); +				cat->determineFolderType(); +			} + +		} +	} +		 +	if (content.has("bad_folders")) +	{ +		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); +			folder_it != content["bad_folders"].endArray(); +			++folder_it) +		{	 +			LLSD folder_sd = *folder_it; +			 +			//These folders failed on the dataserver.  We probably don't want to retry them. +			llinfos << "Folder " << folder_sd["folder_id"].asString()  +					<< "Error: " << folder_sd["error"].asString() << llendl; +		} +	} + +	LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1); +	 +	if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete()) +	{ +		llinfos << "Inventory fetch completed" << llendl; +		LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched(); +	} +	 +	gInventory.notifyObservers("fetchDescendents"); +} + +//If we get back an error (not found, etc...), handle it here +void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) +{ +	llinfos << "LLInventoryModelFetchDescendentsResponder::error " +		<< status << ": " << reason << llendl; +						 +	LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1); + +	if (status==499)		//timed out.  Let's be awesome! +	{ +		for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); +			folder_it != mRequestSD["folders"].endArray(); +			++folder_it) +		{	 +			LLSD folder_sd = *folder_it; +			LLUUID folder_id = folder_sd["folder_id"]; +			sFetchQueue.push_front(folder_id); +		} +	} +	else +	{ +		if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete()) +		{ +			LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched(); +		} +	} +	gInventory.notifyObservers("fetchDescendents"); +} + +//static   Bundle up a bunch of requests to send all at once. +void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) +{ +	//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. +	//If there are items in sFetchQueue, we want to check the time since the last bulkFetch was  +	//sent.  If it exceeds our retry time, go ahead and fire off another batch.   +	//Stopbackgroundfetch will be run from the Responder instead of here.   + +	S16 max_concurrent_fetches=8; +	F32 new_min_time = 0.5f;			//HACK!  Clean this up when old code goes away entirely. +	if (mMinTimeBetweenFetches < new_min_time)  +	{ +		mMinTimeBetweenFetches=new_min_time;  //HACK!  See above. +	} +	 +	if (gDisconnected || +		(mBulkFetchCount > max_concurrent_fetches) || +		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) +	{ +		return; // just bail if we are disconnected. +	}	 + +	U32 folder_count=0; +	U32 max_batch_size=5; + +	U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; + +	LLSD body; +	LLSD body_lib; +	while (!(sFetchQueue.empty()) && (folder_count < max_batch_size)) +	{ +        if (sFetchQueue.front().isNull()) //DEV-17797 +        { +			LLSD folder_sd; +			folder_sd["folder_id"]		= LLUUID::null.asString(); +			folder_sd["owner_id"]		= gAgent.getID(); +			folder_sd["sort_order"]		= (LLSD::Integer)sort_order; +			folder_sd["fetch_folders"]	= (LLSD::Boolean)FALSE; +			folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE; +			body["folders"].append(folder_sd); +            folder_count++; +        } +        else +        { +		    LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); +		 +		    if (cat) +		    { +			    if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) +			    { +				    LLSD folder_sd; +				    folder_sd["folder_id"]		= cat->getUUID(); +				    folder_sd["owner_id"]		= cat->getOwnerID(); +				    folder_sd["sort_order"]		= (LLSD::Integer)sort_order; +				    folder_sd["fetch_folders"]	= TRUE; //(LLSD::Boolean)sFullFetchStarted; +				    folder_sd["fetch_items"]	= (LLSD::Boolean)TRUE; +				     +				    if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) +					    body_lib["folders"].append(folder_sd); +				    else +					    body["folders"].append(folder_sd); +				    folder_count++; +			    } +			    if (mInventoryFetchStarted || mLibraryFetchStarted) +			    {	//Already have this folder but append child folders to list. +				    // add all children to queue +					LLInventoryModel::cat_array_t* categories; +					LLInventoryModel::item_array_t* items; +					gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); +					for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); +						 it != categories->end(); +						 ++it) +					{ +						sFetchQueue.push_back((*it)->getUUID()); +				    } +			    } +		    } +        } +		sFetchQueue.pop_front(); +	} +		 +	if (folder_count > 0) +	{ +		mBulkFetchCount++; +		if (body["folders"].size()) +		{ +			LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0); +		} +		if (body_lib["folders"].size()) +		{ +			std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); +			LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0); +		} +		mFetchTimer.reset(); +	} +	else if (isBulkFetchProcessingComplete()) +	{ +		setAllFoldersFetched(); +	} +} diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h new file mode 100644 index 0000000000..94606fae23 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -0,0 +1,119 @@ +/**  + * @file llinventorymodelbackgroundfetch.h + * @brief LLInventoryModelBackgroundFetch class header file + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYMODELBACKGROUNDFETCH_H +#define LL_LLINVENTORYMODELBACKGROUNDFETCH_H + +// Seraph clean this up +#include "llassettype.h" +#include "llfoldertype.h" +#include "lldarray.h" +#include "llframetimer.h" +#include "llhttpclient.h" +#include "lluuid.h" +#include "llpermissionsflags.h" +#include "llstring.h" +#include <map> +#include <set> +#include <string> +#include <vector> + +// Seraph clean this up +class LLInventoryObserver; +class LLInventoryObject; +class LLInventoryItem; +class LLInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLViewerInventoryItem; +class LLViewerInventoryCategory; +class LLMessageSystem; +class LLInventoryCollectFunctor; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryModelBackgroundFetch +// +// This class handles background fetch. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryModelBackgroundFetch : public LLSingleton<LLInventoryModelBackgroundFetch> +{ +public: +	LLInventoryModelBackgroundFetch(); +	~LLInventoryModelBackgroundFetch(); + +	// Start and stop background breadth-first fetching of inventory contents. +	// This gets triggered when performing a filter-search +	void start(const LLUUID& cat_id = LLUUID::null); +	BOOL backgroundFetchActive(); +	bool isEverythingFetched(); +	void incrBulkFetch(S16 fetching); +	void stopBackgroundFetch(); // stop fetch process +	bool isBulkFetchProcessingComplete(); + +	// Add categories to a list to be fetched in bulk. +	void bulkFetch(std::string url); + +	bool libraryFetchStarted(); +	bool libraryFetchCompleted(); +	bool libraryFetchInProgress(); +	 +	bool inventoryFetchStarted(); +	bool inventoryFetchCompleted(); +	bool inventoryFetchInProgress(); +    void findLostItems(); + +	void setAllFoldersFetched(); + +	static void backgroundFetchCB(void*); // background fetch idle function +	void backgroundFetch(); +	 +private: + 	BOOL mInventoryFetchStarted; +	BOOL mLibraryFetchStarted; +	BOOL mAllFoldersFetched; + +	// completing the fetch once per session should be sufficient +	BOOL mBackgroundFetchActive; +	S16 mBulkFetchCount; +	BOOL mTimelyFetchPending; +	S32 mNumFetchRetries; + +	LLFrameTimer mFetchTimer; +	F32 mMinTimeBetweenFetches; +	F32 mMaxTimeBetweenFetches; + +}; + +#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H + diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 9a2d76e7e2..83c2d62ee8 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -43,6 +43,8 @@  #include "llimfloater.h"  #include "llimview.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llsidepanelinventory.h"  #include "llsidetray.h"  #include "llscrollcontainer.h" @@ -643,7 +645,7 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)  	if(handled)  	{  		ECursorType cursor = getWindow()->getCursor(); -		if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) +		if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW)  		{  			// replace arrow cursor with arrow and hourglass cursor  			getWindow()->setCursor(UI_CURSOR_WORKING); diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index f25d2ef574..7336efb62a 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -36,6 +36,7 @@  #include "roles_constants.h"  #include "llinventory.h" +#include "llinventoryfunctions.h"  #include "lllandmark.h"  #include "llparcel.h"  #include "llregionhandle.h" diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index a60c69f169..4ffd43cb0f 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -36,6 +36,7 @@  #include "llcombobox.h"  #include "lliconctrl.h" +#include "llinventoryfunctions.h"  #include "lllineeditor.h"  #include "lltextbox.h"  #include "lltexteditor.h" diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 6ff784db0a..c7793bbc43 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -49,6 +49,7 @@  #include "lldndbutton.h"  #include "llfloaterworldmap.h"  #include "llfolderviewitem.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventorypanel.h"  #include "lllandmarkactions.h"  #include "llplacesinventorybridge.h" @@ -556,7 +557,7 @@ void LLLandmarksPanel::initLibraryInventoryPanel()  	const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);  	if (landmarks_cat.notNull())  	{ -		gInventory.startBackgroundFetch(landmarks_cat); +		LLInventoryModelBackgroundFetch::instance().start(landmarks_cat);  	}  	// Expanding "Library" tab for new users who have no landmarks in "My Inventory". @@ -620,7 +621,7 @@ void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesI  		  if (!gInventory.isCategoryComplete(cat_id))  		*/  		{ -			gInventory.startBackgroundFetch(cat_id); +			LLInventoryModelBackgroundFetch::instance().start(cat_id);  		}  		// Apply filter substring because it might have been changed diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index d40141c91d..dbc40959d7 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -40,6 +40,7 @@  #include "llfloaterinventory.h"  #include "llinventorybridge.h"  #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventorypanel.h"  #include "llfiltereditor.h"  #include "llfloaterreg.h" @@ -419,7 +420,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string )  		return;  	} -	gInventory.startBackgroundFetch(); +	LLInventoryModelBackgroundFetch::instance().start();  	mFilterSubString = search_string;  	if (mActivePanel->getFilterSubString().empty() && mFilterSubString.empty()) @@ -499,7 +500,7 @@ void LLPanelMainInventory::onFilterSelected()  	if (filter->isActive())  	{  		// If our filter is active we may be the first thing requiring a fetch so we better start it here. -		gInventory.startBackgroundFetch(); +		LLInventoryModelBackgroundFetch::instance().start();  	}  	setFilterTextFromFilter();  } @@ -566,11 +567,11 @@ void LLPanelMainInventory::updateItemcountText()  	std::string text = ""; -	if (LLInventoryModel::backgroundFetchActive()) +	if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive())  	{  		text = getString("ItemcountFetching", string_args);  	} -	else if (LLInventoryModel::isEverythingFetched()) +	else if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched())  	{  		text = getString("ItemcountCompleted", string_args);  	} @@ -600,7 +601,7 @@ void LLPanelMainInventory::toggleFindOptions()  		if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel  			parent_floater->addDependentFloater(mFinderHandle);  		// start background fetch of folders -		gInventory.startBackgroundFetch(); +		LLInventoryModelBackgroundFetch::instance().start();  	}  	else  	{ diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 55bf25f15b..421181dda1 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -53,6 +53,7 @@  #include "llfloaterinventory.h"  #include "llinventorybridge.h"  #include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "lluiconstants.h"  #include "llscrolllistctrl.h"  #include "lltextbox.h" @@ -245,7 +246,7 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)  	mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);  	mInventoryItemsPanel->getRootFolder()->scrollToShowSelection(); -	gInventory.startBackgroundFetch(); +	LLInventoryModelBackgroundFetch::instance().start();  }  void LLPanelOutfitEdit::onSearchEdit(const std::string& string) @@ -271,7 +272,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)  		mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();  	} -	gInventory.startBackgroundFetch(); +	LLInventoryModelBackgroundFetch::instance().start();  	if (mInventoryItemsPanel->getFilterSubString().empty() && mSearchString.empty())  	{ diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 6bda7d1546..dd320f8328 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -43,6 +43,7 @@  #include "llfloaterinventory.h"  #include "llfoldervieweventlistener.h"  #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventorypanel.h"  #include "lllandmark.h"  #include "lllineeditor.h" @@ -217,7 +218,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)  		getRootFolder()->scrollToShowSelection();  	} -	gInventory.startBackgroundFetch(); +	LLInventoryModelBackgroundFetch::instance().start();  	if (mActivePanel->getFilterSubString().empty() && string.empty())  	{ diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 34cef1bee7..54455afa4f 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -551,7 +551,9 @@ void LLPanelPlaces::onTeleportButtonClicked()  		{  			LLSD payload;  			payload["asset_id"] = mItem->getAssetUUID(); -			LLNotificationsUtil::add("TeleportFromLandmark", LLSD(), payload); +			LLSD args;  +			args["LOCATION"] = mItem->getName();  +			LLNotificationsUtil::add("TeleportFromLandmark", args, payload);  		}  		else if (mPlaceInfoType == AGENT_INFO_TYPE ||  				 mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index a9ec01f33a..ab2f9284f7 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -32,6 +32,7 @@  #include "llviewerprecompiledheaders.h"  //LLPanelPrimMediaControls +#include "llagent.h"  #include "llagentcamera.h"  #include "llparcel.h"  #include "llpanel.h" diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index aa7b7b8636..11cde47744 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -42,6 +42,8 @@  #include "llstring.h"  #include "lldir.h"  #include "llfloaterreg.h" +#include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llmultigesture.h"  #include "llnotificationsutil.h"  #include "llvfile.h" @@ -131,10 +133,10 @@ LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& ob  	// Start speculative download of sounds and animations  	const LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION); -	gInventory.startBackgroundFetch(animation_folder_id); +	LLInventoryModelBackgroundFetch::instance().start(animation_folder_id);  	const LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND); -	gInventory.startBackgroundFetch(sound_folder_id); +	LLInventoryModelBackgroundFetch::instance().start(sound_folder_id);  	// this will call refresh when we have everything.  	LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem(); diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 00e152b7f5..b951434010 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -358,11 +358,13 @@ void LLSidepanelAppearance::fetchInventory()  	LLUUID item_id;  	for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)  	{ -		// MULTI_WEARABLE: -		item_id = gAgentWearables.getWearableItemID((EWearableType)type,0); -		if(item_id.notNull()) +		for (U32 index = 0; index < gAgentWearables.getWearableCount((EWearableType)type); ++index)  		{ -			ids.push_back(item_id); +			item_id = gAgentWearables.getWearableItemID((EWearableType)type, index); +			if(item_id.notNull()) +			{ +				ids.push_back(item_id); +			}  		}  	} diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d75a1424d2..1a1dffe85c 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -62,6 +62,7 @@  #include "llimfloater.h"  #include "lllocationhistory.h"  #include "llimageworker.h" +  #include "llloginflags.h"  #include "llmd5.h"  #include "llmemorystream.h" @@ -116,6 +117,7 @@  #include "llimagebmp.h"  #include "llinventorybridge.h"  #include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llfriendcard.h"  #include "llkeyboard.h"  #include "llloginhandler.h"			// gLoginHandler, SLURL support @@ -1846,7 +1848,7 @@ bool idle_startup()  		}          //DEV-17797.  get null folder.  Any items found here moved to Lost and Found -        LLInventoryModel::findLostItems(); +        LLInventoryModelBackgroundFetch::instance().findLostItems();  		LLStartUp::setStartupState( STATE_PRECACHE );  		timeout.reset(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 2b846d33fc..a1b3c8dabd 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -48,6 +48,7 @@  #include "llfoldervieweventlistener.h"  #include "llinventory.h"  #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llinventoryobserver.h"  #include "llinventorypanel.h"  #include "llfloaterinventory.h" @@ -1053,7 +1054,7 @@ public:  	{  		// We need to find textures in all folders, so get the main  		// background download going. -		gInventory.startBackgroundFetch(); +		LLInventoryModelBackgroundFetch::instance().start();  		gInventory.removeObserver(this);  		delete this;  	} @@ -1074,9 +1075,9 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)  	{  		showPicker(FALSE);  		//grab textures first... -		gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); +		LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE));  		//...then start full inventory fetch. -		gInventory.startBackgroundFetch(); +		LLInventoryModelBackgroundFetch::instance().start();  		handled = TRUE;  	} diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 4f5eeb254b..394f550f2e 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -50,6 +50,7 @@  #include "llhudeffecttrail.h"  #include "llimview.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llmutelist.h"  #include "llpreviewnotecard.h"  #include "llrecentpeople.h" diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 75ec02f8ea..b42d25c1d8 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -44,7 +44,9 @@  #include "llfolderview.h"  #include "llviewercontrol.h"  #include "llconsole.h" +#include "llinventoryfunctions.h"  #include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h"  #include "llgesturemgr.h"  #include "llsidetray.h" @@ -538,7 +540,7 @@ bool LLViewerInventoryCategory::fetchDescendents()  		std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");  		if (!url.empty()) //Capability found.  Build up LLSD and use it.  		{ -			gInventory.startBackgroundFetch(mUUID);			 +			LLInventoryModelBackgroundFetch::instance().start(mUUID);			  		}  		else  		{	//Deprecated, but if we don't have a capability, use the old system. diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index fe924d68a5..3a6aed01ce 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -73,6 +73,7 @@  #include "llhudmanager.h"  #include "llimview.h"  #include "llinventorybridge.h" +#include "llinventoryfunctions.h"  #include "llpanellogin.h"  #include "llpanelblockedlist.h"  #include "llmenucommands.h" diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a3d78d13fa..305831aee3 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -63,6 +63,7 @@  #include "llfloaterpreference.h"  #include "llhudeffecttrail.h"  #include "llhudmanager.h" +#include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "llinventorypanel.h"  #include "llnearbychat.h" diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 9c2e5461b2..fe6990eae9 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -48,6 +48,7 @@  #include "llagentwearables.h"  #include "llhudeffecttrail.h"  #include "llhudmanager.h" +#include "llinventoryfunctions.h"  #include "llselectmgr.h"  #include "lltoolgrab.h"	// for needsRenderBeam  #include "lltoolmgr.h" // for needsRenderBeam  | 
