diff options
| author | Merov Linden <merov@lindenlab.com> | 2012-03-19 18:14:55 -0700 | 
|---|---|---|
| committer | Merov Linden <merov@lindenlab.com> | 2012-03-19 18:14:55 -0700 | 
| commit | b615a553955447cccf8f5b6af60410d4bb3c89a2 (patch) | |
| tree | 5f5b7d415816305a354e38c9b33f35cf84791946 | |
| parent | 5f90875a9e92c7c92f92a32e64908a776fce64c6 (diff) | |
| parent | 86c572ad63f0cf222050e807899e80ea5802e1d7 (diff) | |
EXP-1841 : Pull the whole Cut and Paste feature in viewer-experience
32 files changed, 754 insertions, 397 deletions
| diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 6910b962a1..14173fdbb0 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -34,109 +34,113 @@  #include "llview.h"  #include "llwindow.h" -// Global singleton -LLClipboard gClipboard; - - -LLClipboard::LLClipboard() +LLClipboard::LLClipboard() : +	mGeneration(0)  { -	mSourceItem = NULL; +	reset();  } -  LLClipboard::~LLClipboard()  { +	reset();  } - -void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +void LLClipboard::reset()  { -	mSourceID = source_id; -	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToClipboard( mString ); +	// Increment the clipboard count +	mGeneration++; +	// Clear the clipboard +	mObjects.clear(); +	mCutMode = false; +	mString = LLWString();  } -void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) +// Copy the input uuid to the LL clipboard +bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	mSourceID = source_id; -	mString = src; -	LLView::getWindow()->copyTextToClipboard( mString ); +	reset(); +	return addToClipboard(src, type);  } -const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) +// Add the input uuid to the LL clipboard +// Convert the uuid to string and concatenate that string to the system clipboard if legit +bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	if( mSourceID.notNull() ) +	bool res = false; +	if (src.notNull())  	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromClipboard(temp_string); - -		if( temp_string != mString ) +		res = true; +		if (LLAssetType::lookupIsAssetIDKnowable(type))  		{ -			mSourceID.setNull(); -			mString = temp_string; +			LLWString source = utf8str_to_wstring(src.asString()); +			res = addToClipboard(source, 0, source.size()); +		} +		if (res) +		{ +			mObjects.push_back(src); +			mGeneration++;  		}  	} -	else -	{ -		LLView::getWindow()->pasteTextFromClipboard(mString); -	} +	return res; +} -	if( source_id ) +bool LLClipboard::pasteFromClipboard(std::vector<LLUUID>& inv_objects) const +{ +	bool res = false; +	S32 count = mObjects.size(); +	if (count > 0)  	{ -		*source_id = mSourceID; +		res = true; +		inv_objects.clear(); +		for (S32 i = 0; i < count; i++) +		{ +			inv_objects.push_back(mObjects[i]); +		}  	} - -	return mString; +	return res;  } +// Returns true if the LL Clipboard has pasteable items in it +bool LLClipboard::hasContents() const +{ +	return (mObjects.size() > 0); +} -BOOL LLClipboard::canPasteString() const +// Returns true if the input uuid is in the list of clipboard objects +bool LLClipboard::isOnClipboard(const LLUUID& object) const  { -	return LLView::getWindow()->isClipboardTextAvailable(); +	std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); +	return (iter != mObjects.end());  } +// Copy the input string to the LL and the system clipboard +bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) +{ +	return addToClipboard(src, pos, len, use_primary); +} -void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +// Concatenate the input string to the LL and the system clipboard +bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)  { -	mSourceID = source_id;  	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToPrimary( mString ); +	return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString));  } - -const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) +// Copy the System clipboard to the output string. +// Manage the LL Clipboard / System clipboard consistency +bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary)  { -	if( mSourceID.notNull() ) -	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromPrimary(temp_string); - -		if( temp_string != mString ) -		{ -			mSourceID.setNull(); -			mString = temp_string; -		} -	} -	else -	{ -		LLView::getWindow()->pasteTextFromPrimary(mString); -	} - -	if( source_id ) +	bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); +	if (res)  	{ -		*source_id = mSourceID; +		mString = dst;  	} - -	return mString; +	return res;  } - -BOOL LLClipboard::canPastePrimaryString() const +// Return true if there's something on the System clipboard +bool LLClipboard::isTextAvailable(bool use_primary) const  { -	return LLView::getWindow()->isPrimaryTextAvailable(); +	return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable());  } -void LLClipboard::setSourceObject(const LLUUID& source_id, LLAssetType::EType type)  -{ -	mSourceItem = new LLInventoryObject (source_id, LLUUID::null, type, ""); -} diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 9371b94284..fd2e7610df 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -27,46 +27,68 @@  #ifndef LL_LLCLIPBOARD_H  #define LL_LLCLIPBOARD_H +#include <boost/function.hpp>  #include "llstring.h"  #include "lluuid.h"  #include "stdenums.h" +#include "llsingleton.h" +#include "llassettype.h"  #include "llinventory.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLClipboard +// +// This class is used to cut/copy/paste text strings and inventory items around  +// the world. Use LLClipboard::instance().method() to use its methods. +// Note that the text and UUIDs are loosely coupled only. There are few cases +// where the viewer does offer a serialized version of the UUID on the clipboard. +// In those case, the text is overridden when copying/cutting the item.  +// In all other cases, the text and the UUIDs are very much independent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLClipboard +class LLClipboard : public LLSingleton<LLClipboard>  {  public:  	LLClipboard();  	~LLClipboard(); +	 +	// Clears the clipboard +	void reset(); +	// Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) +	int	getGeneration() const { return mGeneration; } -	/* We support two flavors of clipboard.  The default is the explicitly -	   copy-and-pasted clipboard.  The second is the so-called 'primary' clipboard -	   which is implicitly copied upon selection on platforms which expect this -	   (i.e. X11/Linux). */ - -	void		copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	void		copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPasteString() const; -	const LLWString&	getPasteWString(LLUUID* source_id = NULL); +	// Text strings management: +	// ------------------------ +	// We support two flavors of text clipboards. The default is the explicitly +	// copy-and-pasted clipboard. The second is the so-called 'primary' clipboard +	// which is implicitly copied upon selection on platforms which expect this +	// (i.e. X11/Linux, Mac). +	bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool pasteFromClipboard(LLWString& dst, bool use_primary = false); +	bool isTextAvailable(bool use_primary = false) const; +	 +	// Object list management: +	// ----------------------- +	// Clears and adds one single object to the clipboard +	bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Adds one object to the current list of objects on the clipboard +	bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Gets a copy of the objects on the clipboard +	bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const; +	 +	bool hasContents() const;										// True if the clipboard has pasteable objects +	bool isOnClipboard(const LLUUID& object) const;					// True if the input object uuid is on the clipboard -	void		copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPastePrimaryString() const; -	const LLWString&	getPastePrimaryWString(LLUUID* source_id = NULL);	 +	bool isCutMode() const { return mCutMode; } +	void setCutMode(bool mode) { mCutMode = mode; mGeneration++; } -	// Support clipboard for object known only by their uuid and asset type -	void		  setSourceObject(const LLUUID& source_id, LLAssetType::EType type); -	const LLInventoryObject* getSourceObject() { return mSourceItem; } -	  private: -	LLUUID      mSourceID; -	LLWString	mString; -	LLInventoryObject* mSourceItem; +	std::vector<LLUUID> mObjects;		// Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) +	LLWString mString;					// The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable. +	bool mCutMode;						// This is a convenience flag for the viewer. +	int mGeneration;					// Incremented when the clipboard changes so that interested parties can check for changes on the clipboard.	  }; - -// Global singleton -extern LLClipboard gClipboard; - -  #endif  // LL_LLCLIPBOARD_H diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 7e84814c51..d0fbf4b913 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1047,7 +1047,7 @@ void LLLineEditor::cut()  		// Prepare for possible rollback  		LLLineEditorRollback rollback( this ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  		deleteSelection();  		// Validate new string and rollback the if needed. @@ -1078,13 +1078,13 @@ void LLLineEditor::copy()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  	}  }  BOOL LLLineEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable();   }  void LLLineEditor::paste() @@ -1115,14 +1115,7 @@ void LLLineEditor::pasteHelper(bool is_primary)  	if (can_paste_it)  	{  		LLWString paste; -		if (is_primary) -		{ -			paste = gClipboard.getPastePrimaryWString(); -		} -		else  -		{ -			paste = gClipboard.getPasteWString(); -		} +		LLClipboard::instance().pasteFromClipboard(paste, is_primary);  		if (!paste.empty())  		{ @@ -1209,13 +1202,13 @@ void LLLineEditor::copyPrimary()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length, true);  	}  }  BOOL LLLineEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);   }  void LLLineEditor::updatePrimary() diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 466fac33ea..b3e1b63db5 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2504,7 +2504,7 @@ void	LLScrollListCtrl::copy()  	{  		buffer += (*itor)->getContentsCSV() + "\n";  	} -	gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length());  }  // virtual diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3409b6817d..9720dded6c 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1332,7 +1332,7 @@ void LLTextEditor::cut()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID ); +	LLClipboard::instance().copyToClipboard( getWText(), left_pos, length);  	deleteSelection( FALSE );  	onKeyStroke(); @@ -1352,12 +1352,12 @@ void LLTextEditor::copy()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length);  }  BOOL LLTextEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable();  }  // paste from clipboard @@ -1393,16 +1393,8 @@ void LLTextEditor::pasteHelper(bool is_primary)  		return;  	} -	LLUUID source_id;  	LLWString paste; -	if (is_primary) -	{ -		paste = gClipboard.getPastePrimaryWString(&source_id); -	} -	else  -	{ -		paste = gClipboard.getPasteWString(&source_id); -	} +	LLClipboard::instance().pasteFromClipboard(paste, is_primary);  	if (paste.empty())  	{ @@ -1475,12 +1467,12 @@ void LLTextEditor::copyPrimary()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true);  }  BOOL LLTextEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);  }  void LLTextEditor::updatePrimary() diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 66361c8fbf..0593475c54 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -288,7 +288,6 @@ set(viewer_SOURCE_FILES      llinspectremoteobject.cpp      llinspecttoast.cpp      llinventorybridge.cpp -    llinventoryclipboard.cpp      llinventoryfilter.cpp      llinventoryfunctions.cpp      llinventoryicon.cpp @@ -843,7 +842,6 @@ set(viewer_HEADER_FILES      llinspectremoteobject.h      llinspecttoast.h      llinventorybridge.h -    llinventoryclipboard.h      llinventoryfilter.h      llinventoryfunctions.h      llinventoryicon.h diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index f4b6dc2c81..575b613ccf 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -39,7 +39,7 @@  #include "llagent.h"  #include "llclipboard.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h"  #include "llinventorybridge.h"  #include "llinventoryfunctions.h"  #include "llfloatersidepanelcontainer.h" @@ -1118,7 +1118,7 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)  }  void copy_slurl_to_clipboard_cb(std::string& slurl)  { -	gClipboard.copyFromString(utf8str_to_wstring(slurl)); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size());  	LLSD args;  	args["SLURL"] = slurl; @@ -1187,7 +1187,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)  	}  	else if (action == "copy")  	{ -		LLInventoryClipboard::instance().store(mSelectedItemID); +		LLClipboard::instance().copyToClipboard(mSelectedItemID, LLAssetType::AT_LANDMARK);  	}  	else if (action == "paste")  	{ @@ -1211,13 +1211,13 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)  BOOL LLFavoritesBarCtrl::isClipboardPasteable() const  { -	if (!LLInventoryClipboard::instance().hasContents()) +	if (!LLClipboard::instance().hasContents())  	{  		return FALSE;  	}  	LLDynamicArray<LLUUID> objects; -	LLInventoryClipboard::instance().retrieve(objects); +	LLClipboard::instance().pasteFromClipboard(objects);  	S32 count = objects.count();  	for(S32 i = 0; i < count; i++)  	{ @@ -1246,7 +1246,7 @@ void LLFavoritesBarCtrl::pastFromClipboard() const  	{  		LLInventoryItem* item = NULL;  		LLDynamicArray<LLUUID> objects; -		LLInventoryClipboard::instance().retrieve(objects); +		LLClipboard::instance().pasteFromClipboard(objects);  		S32 count = objects.count();  		LLUUID parent_id(mFavoriteFolderId);  		for(S32 i = 0; i < count; i++) diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 9ed9d10c75..56051ff684 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -32,7 +32,7 @@  #include "llinventorybridge.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h"  #include "llagent.h"  #include "llappearancemgr.h" @@ -397,11 +397,11 @@ bool LLFloaterGesture::isActionEnabled(const LLSD& command)  	std::string command_name = command.asString();  	if("paste" == command_name)  	{ -		if(!LLInventoryClipboard::instance().hasContents()) +		if(!LLClipboard::instance().hasContents())  			return false;  		LLDynamicArray<LLUUID> ids; -		LLInventoryClipboard::instance().retrieve(ids); +		LLClipboard::instance().pasteFromClipboard(ids);  		for(LLDynamicArray<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)  		{  			LLInventoryItem* item = gInventory.getItem(*it); @@ -496,27 +496,26 @@ void LLFloaterGesture::onActivateBtnClick()  void LLFloaterGesture::onCopyPasteAction(const LLSD& command)  {  	std::string command_name  = command.asString(); -	// since we select this comman inventory item had  already arrived . +	// Since we select this command, the inventory items must have already arrived  	if("copy_gesture" == command_name)  	{  		uuid_vec_t ids;  		getSelectedIds(ids); -		// make sure that clopboard is empty -		LLInventoryClipboard::instance().reset(); +		// Make sure the clipboard is empty +		LLClipboard::instance().reset();  		for(uuid_vec_t::iterator it = ids.begin(); it != ids.end(); it++)  		{  			LLInventoryItem* item = gInventory.getItem(*it);  			if(item  && item->getInventoryType() == LLInventoryType::IT_GESTURE)  			{ -				LLInventoryClipboard::instance().add(item->getUUID()); +				LLClipboard::instance().addToClipboard(item->getUUID(),LLAssetType::AT_GESTURE);  			}  		}  	}  	else if ("paste" == command_name)  	{ -		LLInventoryClipboard& clipbord = LLInventoryClipboard::instance();  		LLDynamicArray<LLUUID> ids; -		clipbord.retrieve(ids); +		LLClipboard::instance().pasteFromClipboard(ids);  		if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID))  			return;  		LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID); @@ -536,11 +535,11 @@ void LLFloaterGesture::onCopyPasteAction(const LLSD& command)  						gesture_dir->getUUID(), getString("copy_name", string_args), cb);  			}  		} -		clipbord.reset(); +		LLClipboard::instance().reset();  	}  	else if ("copy_uuid" == command_name)  	{ -		gClipboard.copyFromString(utf8str_to_wstring(mGestureList->getCurrentID().asString()), mGestureList->getCurrentID()); +		LLClipboard::instance().copyToClipboard(mGestureList->getCurrentID(),LLAssetType::AT_GESTURE);  	}  } diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 6c4b781122..068a6407f7 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -30,7 +30,7 @@  #include "llcallbacklist.h"  #include "llinventorybridge.h" -#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. +#include "llclipboard.h" // *TODO: remove this once hack below gone.  #include "llinventoryfilter.h"  #include "llinventoryfunctions.h"  #include "llinventorymodelbackgroundfetch.h" @@ -456,8 +456,8 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen  		}  		else  		{ -			folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? -									(folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter +			folderp->setVisible((show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? +								 (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))));  		}  		if (folderp->getVisible()) @@ -1045,6 +1045,36 @@ bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector<LLFol  	return false;  } +// static +void LLFolderView::removeCutItems() +{ +	// There's no item in "cut" mode on the clipboard -> exit +	if (!LLClipboard::instance().isCutMode()) +		return; + +	// Get the list of clipboard item uuids and iterate through them +	LLDynamicArray<LLUUID> objects; +	LLClipboard::instance().pasteFromClipboard(objects); +	for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin(); +		 iter != objects.end(); +		 ++iter) +	{ +		const LLUUID& item_id = (*iter); +		LLInventoryObject *obj = gInventory.getObject(item_id); +		if (obj) +		{ +			if (LLAssetType::AT_CATEGORY == obj->getType()) +			{ +				remove_category(&gInventory, item_id); +			} +			else +			{ +				remove_item(&gInventory, item_id); +			} +		} +	} +} +  void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -1324,7 +1354,7 @@ BOOL LLFolderView::canCopy() const  void LLFolderView::copy()  {  	// *NOTE: total hack to clear the inventory clipboard -	LLInventoryClipboard::instance().reset(); +	LLClipboard::instance().reset();  	S32 count = mSelectedItems.size();  	if(getVisible() && getEnabled() && (count > 0))  	{ @@ -1365,7 +1395,7 @@ BOOL LLFolderView::canCut() const  void LLFolderView::cut()  {  	// clear the inventory clipboard -	LLInventoryClipboard::instance().reset(); +	LLClipboard::instance().reset();  	S32 count = mSelectedItems.size();  	if(getVisible() && getEnabled() && (count > 0))  	{ @@ -1379,6 +1409,7 @@ void LLFolderView::cut()  				listener->cutToClipboard();  			}  		} +		LLFolderView::removeCutItems();  	}  	mSearchString.clear();  } @@ -2139,10 +2170,10 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata)  		removeSelectedItems();  		return true;  	} - -	if ("copy" == action) -	{	 -		LLInventoryClipboard::instance().reset(); +	if (("copy" == action) || ("cut" == action)) +	{ +		// Clear the clipboard before we start adding things on it +		LLClipboard::instance().reset();  	}  	static const std::string change_folder_string = "change_folder_type_"; diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 5c5a3a894f..da8bb15f8e 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -80,8 +80,8 @@ protected:  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLFolderView  // -// Th LLFolderView represents the root level folder view object. It -// manages the screen region of the folder view. +// The LLFolderView represents the root level folder view object.  +// It manages the screen region of the folder view.  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler @@ -110,7 +110,7 @@ public:  	virtual LLFolderView*	getRoot() { return this; } -	// FolderViews default to sort by name.  This will change that, +	// FolderViews default to sort by name. This will change that,  	// and resort the items if necessary.  	void setSortOrder(U32 order);  	void setFilterPermMask(PermissionMask filter_perm_mask); @@ -139,20 +139,20 @@ public:  	virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse);  	virtual BOOL addFolder( LLFolderViewFolder* folder); -	// Finds width and height of this object and it's children.  Also -	// makes sure that this view and it's children are the right size. +	// Find width and height of this object and its children. Also +	// makes sure that this view and its children are the right size.  	virtual S32 arrange( S32* width, S32* height, S32 filter_generation );  	void arrangeAll() { mArrangeGeneration++; }  	S32 getArrangeGeneration() { return mArrangeGeneration; } -	// applies filters to control visibility of inventory items +	// Apply filters to control visibility of inventory items  	virtual void filter( LLInventoryFilter& filter); -	// get the last selected item +	// Get the last selected item  	virtual LLFolderViewItem* getCurSelectedItem( void ); -	// Record the selected item and pass it down the hierachy. +	// Record the selected item and pass it down the hierarchy.  	virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem,  		BOOL take_keyboard_focus); @@ -162,13 +162,13 @@ public:  	// Called once a frame to update the selection if mSelectThisID has been set  	void updateSelection(); -	// This method is used to toggle the selection of an item. Walks -	// children, and keeps track of selected objects. +	// This method is used to toggle the selection of an item.  +	// Walks children and keeps track of selected objects.  	virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected);  	virtual std::set<LLUUID> getSelectionList() const; -	// make sure if ancestor is selected, descendents are not +	// Make sure if ancestor is selected, descendents are not  	void sanitizeSelection();  	void clearSelection();  	void addToSelectionList(LLFolderViewItem* item); @@ -179,21 +179,22 @@ public:  	void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; }  	LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; } -	// deletion functionality +	// Deletion functionality   	void removeSelectedItems(); + 	static void removeCutItems(); -	// open the selected item. +	// Open the selected item  	void openSelectedItems( void );  	void propertiesSelectedItems( void ); -	// change the folder type +	// Change the folder type  	void changeType(LLInventoryModel *model, LLFolderType::EType new_folder_type);  	void autoOpenItem(LLFolderViewFolder* item);  	void closeAutoOpenedFolders();  	BOOL autoOpenTest(LLFolderViewFolder* item); -	// copy & paste +	// Copy & paste  	virtual void	copy();  	virtual BOOL	canCopy() const; @@ -206,7 +207,7 @@ public:  	virtual void	doDelete();  	virtual BOOL	canDoDelete() const; -	// public rename functionality - can only start the process +	// Public rename functionality - can only start the process  	void startRenamingSelectedItem( void );  	// These functions were used when there was only one folderview, @@ -347,7 +348,7 @@ protected:  	/**  	 * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. -	 * NOTE: For now it uses only to cut LLFolderViewItem::mLabel text to be used for Landmarks in Places Panel. +	 * NOTE: For now it's used only to cut LLFolderViewItem::mLabel text for Landmarks in Places Panel.  	 */  	bool							mUseEllipses; // See EXT-719 diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index aee31ca033..06682dcbf1 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -75,7 +75,7 @@ public:  	virtual void move( LLFolderViewEventListener* parent_listener ) = 0;  	virtual BOOL isItemCopyable() const = 0;  	virtual BOOL copyToClipboard() const = 0; -	virtual void cutToClipboard() = 0; +	virtual BOOL cutToClipboard() const = 0;  	virtual BOOL isClipboardPasteable() const = 0;  	virtual void pasteFromClipboard() = 0;  	virtual void pasteLinkFromClipboard() = 0; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index afad27b4e0..712d3e4583 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -40,6 +40,7 @@  #include "llviewerwindow.h"		// Argh, only for setCursor()  // linden library includes +#include "llclipboard.h"  #include "llfocusmgr.h"		// gFocusMgr  #include "lltrans.h" @@ -1002,7 +1003,7 @@ void LLFolderViewItem::draw()  	LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor;  	if (highlight_link) color = sLinkColor;  	if (in_library) color = sLibraryColor; - +	  	F32 right_x  = 0;  	F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;  	F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); @@ -1158,7 +1159,36 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)  		mNeedsSort = false;  	} +	// evaluate mHasVisibleChildren  	mHasVisibleChildren = hasFilteredDescendants(filter_generation); +	if (mHasVisibleChildren) +	{ +		// We have to verify that there's at least one child that's not filtered out +		bool found = false; +		// Try the items first +		for (items_t::iterator iit = mItems.begin(); iit != mItems.end(); ++iit) +		{ +			LLFolderViewItem* itemp = (*iit); +			found = (itemp->getFiltered(filter_generation)); +			if (found) +				break; +		} +		if (!found) +		{ +			// If no item found, try the folders +			for (folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) +			{ +				LLFolderViewFolder* folderp = (*fit); +				found = ( folderp->getListener() +								&&	(folderp->getFiltered(filter_generation) +									 ||	(folderp->getFilteredFolder(filter_generation)  +										 && folderp->hasFilteredDescendants(filter_generation)))); +				if (found) +					break; +			} +		} +		mHasVisibleChildren = found; +	}  	// calculate height as a single item (without any children), and reshapes rectangle to match  	LLFolderViewItem::arrange( width, height, filter_generation ); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index da85c81cf2..8d3ac3e723 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -47,7 +47,7 @@  #include "llgiveinventory.h"   #include "llimfloater.h"  #include "llimview.h" -#include "llinventoryclipboard.h" +#include "llclipboard.h"  #include "llinventorydefines.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h" @@ -143,6 +143,42 @@ bool isMarketplaceSendAction(const std::string& action)  	return ("send_to_marketplace" == action);  } +// Used by LLFolderBridge as callback for directory fetching recursion +class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver +{ +public: +	LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) {} +	~LLRightClickInventoryFetchDescendentsObserver() {} +	virtual void execute(bool clear_observer = false); +	virtual void done() +	{ +		execute(true); +	} +}; + +// Used by LLFolderBridge as callback for directory content items fetching +class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +{ +public: +	LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : LLInventoryFetchItemsObserver(ids) { }; +	~LLRightClickInventoryFetchObserver() {} +	void execute(bool clear_observer = false) +	{ +		if (clear_observer) +		{ +			dec_busy_count(); +			gInventory.removeObserver(this); +			delete this; +		} +		// we've downloaded all the items, so repaint the dialog +		LLFolderBridge::staticFolderOptionsMenu(); +	} +	virtual void done() +	{ +		execute(true); +	} +}; +  // +=================================================+  // |        LLInvFVBridge                            |  // +=================================================+ @@ -215,13 +251,27 @@ BOOL LLInvFVBridge::isLink() const  /**   * @brief Adds this item into clipboard storage   */ -void LLInvFVBridge::cutToClipboard() +BOOL LLInvFVBridge::cutToClipboard() const  { -	if(isItemMovable()) +	const LLInventoryObject* obj = gInventory.getObject(mUUID); +	if (obj && isItemMovable() && isItemRemovable())  	{ -		LLInventoryClipboard::instance().cut(mUUID); +		LLClipboard::instance().setCutMode(true); +		return LLClipboard::instance().addToClipboard(mUUID);  	} +	return FALSE;  } + +BOOL LLInvFVBridge::copyToClipboard() const +{ +	const LLInventoryObject* obj = gInventory.getObject(mUUID); +	if (obj && isItemCopyable()) +	{ +		return LLClipboard::instance().addToClipboard(mUUID); +	} +	return FALSE; +} +  // *TODO: make sure this does the right thing  void LLInvFVBridge::showProperties()  { @@ -409,7 +459,8 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*  BOOL LLInvFVBridge::isClipboardPasteable() const  { -	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) +	// Return FALSE on degenerated cases: empty clipboard, no inventory, no agent +	if (!LLClipboard::instance().hasContents() || !isAgentInventory())  	{  		return FALSE;  	} @@ -419,37 +470,42 @@ BOOL LLInvFVBridge::isClipboardPasteable() const  		return FALSE;  	} -	const LLUUID &agent_id = gAgent.getID(); +	// In cut mode, whatever is on the clipboard is always pastable +	if (LLClipboard::instance().isCutMode()) +	{ +		return TRUE; +	} +	// In normal mode, we need to check each element of the clipboard to know if we can paste or not  	LLDynamicArray<LLUUID> objects; -	LLInventoryClipboard::instance().retrieve(objects); +	LLClipboard::instance().pasteFromClipboard(objects);  	S32 count = objects.count();  	for(S32 i = 0; i < count; i++)  	{  		const LLUUID &item_id = objects.get(i); -		// Can't paste folders +		// Folders are pastable if all items in there are copyable  		const LLInventoryCategory *cat = model->getCategory(item_id); -		if (cat) -		{ -			return FALSE; -		} - -		const LLInventoryItem *item = model->getItem(item_id); -		if (item) +		if (cat)   		{ -			if (!item->getPermissions().allowCopyBy(agent_id)) -			{ +			LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, item_id); +			if (!cat_br.isItemCopyable())  				return FALSE; -			} +			// Skip to the next item in the clipboard +			continue;  		} + +		// Each item must be copyable to be pastable +		LLItemBridge item_br(mInventoryPanel.get(), mRoot, item_id); +		if (!item_br.isItemCopyable()) +			return FALSE;  	}  	return TRUE;  }  BOOL LLInvFVBridge::isClipboardPasteableAsLink() const  { -	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) +	if (!LLClipboard::instance().hasContents() || !isAgentInventory())  	{  		return FALSE;  	} @@ -460,7 +516,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const  	}  	LLDynamicArray<LLUUID> objects; -	LLInventoryClipboard::instance().retrieve(objects); +	LLClipboard::instance().pasteFromClipboard(objects);  	S32 count = objects.count();  	for(S32 i = 0; i < count; i++)  	{ @@ -611,6 +667,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,  				disabled_items.push_back(std::string("Copy"));  			} +			items.push_back(std::string("Cut")); +			if (!isItemMovable() || !isItemRemovable()) +			{ +				disabled_items.push_back(std::string("Cut")); +			} +  			if (canListOnMarketplace())  			{  				items.push_back(std::string("Marketplace Separator")); @@ -1290,6 +1352,12 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)  		gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));  		return;  	} +	else if ("cut" == action) +	{ +		cutToClipboard(); +		LLFolderView::removeCutItems(); +		return; +	}  	else if ("copy" == action)  	{  		copyToClipboard(); @@ -1297,7 +1365,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)  	}  	else if ("paste" == action)  	{ -		// Single item only  		LLInventoryItem* itemp = model->getItem(mUUID);  		if (!itemp) return; @@ -1672,16 +1739,6 @@ BOOL LLItemBridge::isItemCopyable() const  	return FALSE;  } -BOOL LLItemBridge::copyToClipboard() const -{ -	if(isItemCopyable()) -	{ -		LLInventoryClipboard::instance().add(mUUID); -		return TRUE; -	} -	return FALSE; -} -  LLViewerInventoryItem* LLItemBridge::getItem() const  {  	LLViewerInventoryItem* item = NULL; @@ -1713,18 +1770,22 @@ LLHandle<LLFolderBridge> LLFolderBridge::sSelf;  BOOL LLFolderBridge::isItemMovable() const  {  	LLInventoryObject* obj = getInventoryObject(); -	if(obj) +	if (obj)  	{ -		return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())); +		// If it's a protected type folder, we can't move it +		if (LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())) +			return FALSE; +		return TRUE;  	}  	return FALSE;  }  void LLFolderBridge::selectItem()  { +	// Have no fear: the first thing start() does is to test if everything for that folder has been fetched... +	LLInventoryModelBackgroundFetch::instance().start(getUUID(), true);  } -  // Iterate through a folder's children to determine if  // all the children are removable.  class LLIsItemRemovable : public LLFolderViewFunctor @@ -1780,18 +1841,34 @@ BOOL LLFolderBridge::isUpToDate() const  BOOL LLFolderBridge::isItemCopyable() const  { -	// Can copy folders to paste-as-link, but not for straight paste. -	return gSavedSettings.getBOOL("InventoryLinking"); -} - -BOOL LLFolderBridge::copyToClipboard() const -{ -	if(isItemCopyable()) +	// Folders are copyable if items in them are, recursively, copyable. +	 +	// Get the content of the folder +	LLInventoryModel::cat_array_t* cat_array; +	LLInventoryModel::item_array_t* item_array; +	gInventory.getDirectDescendentsOf(mUUID,cat_array,item_array); + +	// Check the items +	LLInventoryModel::item_array_t item_array_copy = *item_array; +	for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) +	{ +		LLInventoryItem* item = *iter; +		LLItemBridge item_br(mInventoryPanel.get(), mRoot, item->getUUID()); +		if (!item_br.isItemCopyable()) +			return FALSE; +	} +	 +	// Check the folders +	LLInventoryModel::cat_array_t cat_array_copy = *cat_array; +	for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)  	{ -		LLInventoryClipboard::instance().add(mUUID); -		return TRUE; +		LLViewerInventoryCategory* category = *iter; +		LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, category->getUUID()); +		if (!cat_br.isItemCopyable()) +			return FALSE;  	} -	return FALSE; +	 +	return TRUE;  }  BOOL LLFolderBridge::isClipboardPasteable() const @@ -1809,7 +1886,7 @@ BOOL LLFolderBridge::isClipboardPasteable() const  		}  		LLDynamicArray<LLUUID> objects; -		LLInventoryClipboard::instance().retrieve(objects); +		LLClipboard::instance().pasteFromClipboard(objects);  		const LLViewerInventoryCategory *current_cat = getCategory();  		// Search for the direct descendent of current Friends subfolder among all pasted items, @@ -1847,7 +1924,7 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const  		const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat );  		const LLUUID ¤t_cat_id = current_cat->getUUID();  		LLDynamicArray<LLUUID> objects; -		LLInventoryClipboard::instance().retrieve(objects); +		LLClipboard::instance().pasteFromClipboard(objects);  		S32 count = objects.count();  		for(S32 i = 0; i < count; i++)  		{ @@ -2437,121 +2514,114 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id,  	return accept;  } -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer)  { -public: -	LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : -		LLInventoryFetchItemsObserver(ids), -		mCopyItems(false) -	{ }; -	LLRightClickInventoryFetchObserver(const uuid_vec_t& ids, -									   const LLUUID& cat_id,  -									   bool copy_items) : -		LLInventoryFetchItemsObserver(ids), -		mCatID(cat_id), -		mCopyItems(copy_items) -	{ }; -	virtual void done() -	{ -		// we've downloaded all the items, so repaint the dialog -		LLFolderBridge::staticFolderOptionsMenu(); - -		gInventory.removeObserver(this); -		delete this; -	} - -protected: -	LLUUID mCatID; -	bool mCopyItems; - -}; - -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: -	LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids, -												  bool copy_items) :  -		LLInventoryFetchDescendentsObserver(ids), -		mCopyItems(copy_items)  -	{} -	~LLRightClickInventoryFetchDescendentsObserver() {} -	virtual void done(); -protected: -	bool mCopyItems; -}; - -void LLRightClickInventoryFetchDescendentsObserver::done() -{ -	// Avoid passing a NULL-ref as mCompleteFolders.front() down to -	// gInventory.collectDescendents() +	// Bail out immediately if no descendents  	if( mComplete.empty() )  	{  		llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; -		dec_busy_count(); -		gInventory.removeObserver(this); -		delete this; +		if (clear_observer) +		{ +			dec_busy_count(); +			gInventory.removeObserver(this); +			delete this; +		}  		return;  	} - -	// What we do here is get the complete information on the items in -	// the library, and set up an observer that will wait for that to -	// happen. -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(mComplete.front(), -								  cat_array, -								  item_array, -								  LLInventoryModel::EXCLUDE_TRASH); -	S32 count = item_array.count(); -#if 0 // HACK/TODO: Why? -	// This early causes a giant menu to get produced, and doesn't seem to be needed. -	if(!count) -	{ -		llwarns << "Nothing fetched in category " << mCompleteFolders.front() -				<< llendl; +	 +	// Copy the list of complete fetched folders while "this" is still valid +	uuid_vec_t completed_folder = mComplete; +	 +	// Clean up, and remove this as an observer now since recursive calls +	// could notify observers and throw us into an infinite loop. +	if (clear_observer) +	{  		dec_busy_count();  		gInventory.removeObserver(this);  		delete this; -		return;  	} -#endif - -	uuid_vec_t ids; -	for(S32 i = 0; i < count; ++i) +	 +	for (uuid_vec_t::iterator current_folder = completed_folder.begin(); current_folder != completed_folder.end(); ++current_folder)  	{ -		ids.push_back(item_array.get(i)->getUUID()); -	} +		// Get the information on the fetched folder items and subfolders and fetch those  +		LLInventoryModel::cat_array_t* cat_array; +		LLInventoryModel::item_array_t* item_array; +		gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); -	LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(ids, mComplete.front(), mCopyItems); +		S32 item_count = item_array->count(); +		S32 cat_count = cat_array->count(); +	 +		// Move to next if current folder empty +		if ((item_count == 0) && (cat_count == 0)) +		{ +			continue; +		} -	// clean up, and remove this as an observer since the call to the -	// outfit could notify observers and throw us into an infinite -	// loop. -	dec_busy_count(); -	gInventory.removeObserver(this); -	delete this; +		uuid_vec_t ids; +		LLRightClickInventoryFetchObserver* outfit = NULL; +		LLRightClickInventoryFetchDescendentsObserver* categories = NULL; -	// increment busy count and either tell the inventory to check & -	// call done, or add this object to the inventory for observation. -	inc_busy_count(); +		// Fetch the items +		if (item_count) +		{ +			for (S32 i = 0; i < item_count; ++i) +			{ +				ids.push_back(item_array->get(i)->getUUID()); +			} +			outfit = new LLRightClickInventoryFetchObserver(ids); +		} +		// Fetch the subfolders +		if (cat_count) +		{ +			for (S32 i = 0; i < cat_count; ++i) +			{ +				ids.push_back(cat_array->get(i)->getUUID()); +			} +			categories = new LLRightClickInventoryFetchDescendentsObserver(ids); +		} -	// do the fetch -	outfit->startFetch(); -	outfit->done();				//Not interested in waiting and this will be right 99% of the time. -//Uncomment the following code for laggy Inventory UI. -/*	if(outfit->isFinished()) -	{ -	// everything is already here - call done. -	outfit->done(); +		// Perform the item fetch +		if (outfit) +		{ +			outfit->startFetch(); +			outfit->execute();				// Not interested in waiting and this will be right 99% of the time. +			delete outfit; +			// Uncomment the following code for laggy Inventory UI. +			/* +			 if (outfit->isFinished()) +			 { +				// everything is already here - call done. +				outfit->execute(); +				delete outfit; +			 } +			 else +			 { +				// it's all on its way - add an observer, and the inventory +				// will call done for us when everything is here. +				inc_busy_count(); +				gInventory.addObserver(outfit); +			} +			*/ +		} +		// Perform the subfolders fetch : this is where we truly recurse down the folder hierarchy +		if (categories) +		{ +			categories->startFetch(); +			if (categories->isFinished()) +			{ +				// everything is already here - call done. +				categories->execute(); +				delete categories; +			} +			else +			{ +				// it's all on its way - add an observer, and the inventory +				// will call done for us when everything is here. +				inc_busy_count(); +				gInventory.addObserver(categories); +			} +		}  	} -	else -	{ -	// it's all on it's way - add an observer, and the inventory -	// will call done for us when everything is here. -	gInventory.addObserver(outfit); -	}*/  } @@ -2670,6 +2740,12 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)  		modifyOutfit(TRUE);  		return;  	} +	else if ("cut" == action) +	{ +		cutToClipboard(); +		LLFolderView::removeCutItems(); +		return; +	}  	else if ("copy" == action)  	{  		copyToClipboard(); @@ -2881,7 +2957,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re  void LLFolderBridge::pasteFromClipboard()  {  	LLInventoryModel* model = getInventoryModel(); -	if(model && isClipboardPasteable()) +	if (model && isClipboardPasteable())  	{  		const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);  		const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); @@ -2891,7 +2967,7 @@ void LLFolderBridge::pasteFromClipboard()  		const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);  		LLDynamicArray<LLUUID> objects; -		LLInventoryClipboard::instance().retrieve(objects); +		LLClipboard::instance().pasteFromClipboard(objects);  		if (move_is_into_outbox)  		{ @@ -2941,7 +3017,8 @@ void LLFolderBridge::pasteFromClipboard()  			const LLUUID& item_id = (*iter);  			LLInventoryItem *item = model->getItem(item_id); -			if (item) +			LLInventoryObject *obj = model->getObject(item_id); +			if (obj)  			{  				if (move_is_into_current_outfit || move_is_into_outfit)  				{ @@ -2950,29 +3027,56 @@ void LLFolderBridge::pasteFromClipboard()  						dropToOutfit(item, move_is_into_current_outfit);  					}  				} -				else if(LLInventoryClipboard::instance().isCutMode()) +				else if (LLClipboard::instance().isCutMode())  				{ -					// move_inventory_item() is not enough, -					//we have to update inventory locally too -					LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); -					llassert(viitem); -					if (viitem) +					// Do a move to "paste" a "cut" +					// move_inventory_item() is not enough, as we have to update inventory locally too +					if (LLAssetType::AT_CATEGORY == obj->getType()) +					{ +						LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); +						llassert(vicat); +						if (vicat) +						{ +							changeCategoryParent(model, vicat, parent_id, FALSE); +						} +					} +					else  					{ -						changeItemParent(model, viitem, parent_id, FALSE); +						LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); +						llassert(viitem); +						if (viitem) +						{ +							changeItemParent(model, viitem, parent_id, FALSE); +						}  					}  				}  				else  				{ -					copy_inventory_item( -						gAgent.getID(), -						item->getPermissions().getOwner(), -						item->getUUID(), -						parent_id, -						std::string(), -						LLPointer<LLInventoryCallback>(NULL)); +					// Do a "copy" to "paste" a regular copy clipboard +					if (LLAssetType::AT_CATEGORY == obj->getType()) +					{ +						LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); +						llassert(vicat); +						if (vicat) +						{ +							copy_inventory_category(model, vicat, parent_id); +						} +					} +					else +					{ +						copy_inventory_item( +											gAgent.getID(), +											item->getPermissions().getOwner(), +											item->getUUID(), +											parent_id, +											std::string(), +											LLPointer<LLInventoryCallback>(NULL)); +					}  				}  			}  		} +		// Change mode to paste for next paste +		LLClipboard::instance().setCutMode(false);  	}  } @@ -2997,7 +3101,7 @@ void LLFolderBridge::pasteLinkFromClipboard()  		const LLUUID parent_id(mUUID);  		LLDynamicArray<LLUUID> objects; -		LLInventoryClipboard::instance().retrieve(objects); +		LLClipboard::instance().pasteFromClipboard(objects);  		for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin();  			 iter != objects.end();  			 ++iter) @@ -3035,6 +3139,8 @@ void LLFolderBridge::pasteLinkFromClipboard()  					LLPointer<LLInventoryCallback>(NULL));  			}  		} +		// Change mode to paste for next paste +		LLClipboard::instance().setCutMode(false);  	}  } @@ -3292,16 +3398,19 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  		folders.push_back(category->getUUID());  		sSelf = getHandle(); -		LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); +		LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders);  		fetch->startFetch(); -		inc_busy_count();  		if (fetch->isFinished())  		{ +			// Do not call execute() or done() here as if the folder is here, there's likely no point drilling down  +			// This saves lots of time as buildContextMenu() is called a lot +			delete fetch;  			buildContextMenuFolderOptions(flags);  		}  		else  		{  			// it's all on its way - add an observer, and the inventory will call done for us when everything is here. +			inc_busy_count();  			gInventory.addObserver(fetch);  		}  	} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3b4f845f54..dc9e88d54d 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -106,8 +106,8 @@ public:  	virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch);  	virtual void move(LLFolderViewEventListener* new_parent_bridge) {}  	virtual BOOL isItemCopyable() const { return FALSE; } -	virtual BOOL copyToClipboard() const { return FALSE; } -	virtual void cutToClipboard(); +	virtual BOOL copyToClipboard() const; +	virtual BOOL cutToClipboard() const;  	virtual BOOL isClipboardPasteable() const;  	virtual BOOL isClipboardPasteableAsLink() const;  	virtual void pasteFromClipboard() {} @@ -212,7 +212,6 @@ public:  	virtual BOOL renameItem(const std::string& new_name);  	virtual BOOL removeItem();  	virtual BOOL isItemCopyable() const; -	virtual BOOL copyToClipboard() const;  	virtual BOOL hasChildren() const { return FALSE; }  	virtual BOOL isUpToDate() const { return TRUE; } @@ -275,7 +274,6 @@ public:  	virtual BOOL isItemCopyable() const;  	virtual BOOL isClipboardPasteable() const;  	virtual BOOL isClipboardPasteableAsLink() const; -	virtual BOOL copyToClipboard() const;  	static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 947f74315c..e859535d18 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -39,8 +39,11 @@  #include "llviewerfoldertype.h"  // linden library includes +#include "llclipboard.h"  #include "lltrans.h" +LLFastTimer::DeclareTimer FT_FILTER_CLIPBOARD("Filter Clipboard"); +  LLInventoryFilter::FilterOps::FilterOps() :  	mFilterObjectTypes(0xffffffffffffffffULL),  	mFilterCategoryTypes(0xffffffffffffffffULL), @@ -88,11 +91,15 @@ LLInventoryFilter::~LLInventoryFilter()  BOOL LLInventoryFilter::check(const LLFolderViewItem* item)   { -	// If it's a folder and we're showing all folders, return TRUE automatically. +	// Clipboard cut items are *always* filtered so we need this value upfront +	const LLFolderViewEventListener* listener = item->getListener(); +	const BOOL passed_clipboard = (listener ? checkAgainstClipboard(listener->getUUID()) : TRUE); + +	// If it's a folder and we're showing all folders, return automatically.  	const BOOL is_folder = (dynamic_cast<const LLFolderViewFolder*>(item) != NULL);  	if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS))  	{ -		return TRUE; +		return passed_clipboard;  	}  	mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; @@ -103,6 +110,7 @@ BOOL LLInventoryFilter::check(const LLFolderViewItem* item)  	const BOOL passed = (passed_filtertype &&  						 passed_permissions &&  						 passed_filterlink && +						 passed_clipboard &&  						 (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos));  	return passed; @@ -114,8 +122,10 @@ bool LLInventoryFilter::check(const LLInventoryItem* item)  	const bool passed_filtertype = checkAgainstFilterType(item);  	const bool passed_permissions = checkAgainstPermissions(item); +	const BOOL passed_clipboard = checkAgainstClipboard(item->getUUID());  	const bool passed = (passed_filtertype &&  						 passed_permissions && +						 passed_clipboard &&  						 (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos));  	return passed; @@ -145,10 +155,13 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const  bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const  { +	// Always check against the clipboard +	const BOOL passed_clipboard = checkAgainstClipboard(folder_id); +	  	// we're showing all folders, overriding filter  	if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)  	{ -		return true; +		return passed_clipboard;  	}  	if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) @@ -163,7 +176,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const  			return false;  	} -	return true; +	return passed_clipboard;  }  BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const @@ -255,7 +268,7 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con  			}  		}  	} -	 +  	return TRUE;  } @@ -309,6 +322,31 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLInventoryItem* item) cons  	return true;  } +// Items and folders that are on the clipboard or, recursively, in a folder which   +// is on the clipboard must be filtered out if the clipboard is in the "cut" mode. +bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const +{ +	if (LLClipboard::instance().isCutMode()) +	{ +		LLFastTimer ft(FT_FILTER_CLIPBOARD); +		LLUUID current_id = object_id; +		LLInventoryObject *current_object = gInventory.getObject(object_id); +		while (current_id.notNull() && current_object) +		{ +			if (LLClipboard::instance().isOnClipboard(current_id)) +			{ +				return false; +			} +			current_id = current_object->getParentUUID(); +			if (current_id.notNull()) +			{ +				current_object = gInventory.getObject(current_id); +			} +		} +	} +	return true; +} +  BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const  {  	const LLFolderViewEventListener* listener = item->getListener(); @@ -379,7 +417,7 @@ BOOL LLInventoryFilter::isNotDefault() const  	not_default |= (mFilterOps.mMinDate != mDefaultFilterOps.mMinDate);  	not_default |= (mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate);  	not_default |= (mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo); - +	  	return not_default;  } @@ -965,7 +1003,7 @@ void LLInventoryFilter::fromLLSD(LLSD& data)  {  	if(data.has("filter_types"))  	{ -		setFilterObjectTypes((U32)data["filter_types"].asInteger()); +		setFilterObjectTypes((U64)data["filter_types"].asInteger());  	}  	if(data.has("min_date") && data.has("max_date")) diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 6be2acfaa3..1804637a04 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -124,6 +124,7 @@ public:  	BOOL 				checkAgainstPermissions(const LLFolderViewItem* item) const;  	bool 				checkAgainstPermissions(const LLInventoryItem* item) const;  	BOOL 				checkAgainstFilterLinks(const LLFolderViewItem* item) const; +	bool				checkAgainstClipboard(const LLUUID& object_id) const;  	std::string::size_type getStringMatchOffset() const; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index dd92188e9d..236c997ef6 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -54,7 +54,6 @@  #include "lliconctrl.h"  #include "llimview.h"  #include "llinventorybridge.h" -#include "llinventoryclipboard.h"  #include "llinventorymodel.h"  #include "llinventorypanel.h"  #include "lllineeditor.h" @@ -161,6 +160,31 @@ void change_category_parent(LLInventoryModel* model,  	model->notifyObservers();  } +// Move the item to the trash. Works for folders and objects. +// Caution: This method assumes that the item is removable! +void remove_item(LLInventoryModel* model, const LLUUID& id) +{ +	LLViewerInventoryItem* item = model->getItem(id); +	if (!item) +		return; +	 +	if (item->getType() == LLAssetType::AT_CATEGORY) +	{ +		// Call the general helper function to delete a folder +		remove_category(model, id); +	} +	else +	{ +		// Get the trash UUID +		LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); +		if (trash_id.notNull()) +		{ +			// Finally, move the item to the trash +			change_item_parent(model, item, trash_id, true); +		} +	} +} +  void remove_category(LLInventoryModel* model, const LLUUID& cat_id)  {  	if (!model || !get_is_category_removable(model, cat_id)) @@ -214,6 +238,49 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s  	model->notifyObservers();  } +void copy_inventory_category(LLInventoryModel* model, +							 LLViewerInventoryCategory* cat, +							 const LLUUID& parent_id, +							 const LLUUID& root_copy_id) +{ +	// Create the initial folder +	LLUUID new_cat_uuid = gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName()); +	model->notifyObservers(); +	 +	// We need to exclude the initial root of the copy to avoid recursively copying the copy, etc... +	LLUUID root_id = (root_copy_id.isNull() ? new_cat_uuid : root_copy_id); + +	// Get the content of the folder +	LLInventoryModel::cat_array_t* cat_array; +	LLInventoryModel::item_array_t* item_array; +	gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + +	// Copy all the items +	LLInventoryModel::item_array_t item_array_copy = *item_array; +	for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) +	{ +		LLInventoryItem* item = *iter; +		copy_inventory_item( +							gAgent.getID(), +							item->getPermissions().getOwner(), +							item->getUUID(), +							new_cat_uuid, +							std::string(), +							LLPointer<LLInventoryCallback>(NULL)); +	} +	 +	// Copy all the folders +	LLInventoryModel::cat_array_t cat_array_copy = *cat_array; +	for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) +	{ +		LLViewerInventoryCategory* category = *iter; +		if (category->getUUID() != root_id) +		{ +			copy_inventory_category(model, category, new_cat_uuid, root_id); +		} +	} +} +  class LLInventoryCollectAllItems : public LLInventoryCollectFunctor  {  public: diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index ce2b89b22e..b3d9f4b966 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -62,6 +62,8 @@ void change_item_parent(LLInventoryModel* model,  									 const LLUUID& new_parent_id,  									 BOOL restamp); +void remove_item(LLInventoryModel* model, const LLUUID& id); +  void change_category_parent(LLInventoryModel* model,  	LLViewerInventoryCategory* cat,  	const LLUUID& new_parent_id, @@ -71,6 +73,8 @@ void remove_category(LLInventoryModel* model, const LLUUID& cat_id);  void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); +void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null); +  // Generates a string containing the path to the item specified by item_id.  void append_path(const LLUUID& id, std::string& path); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a71b699fdd..0eba8bd0f1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -30,6 +30,7 @@  #include "llagent.h"  #include "llagentwearables.h"  #include "llappearancemgr.h" +#include "llclipboard.h"  #include "llinventorypanel.h"  #include "llinventorybridge.h"  #include "llinventoryfunctions.h" @@ -1110,50 +1111,82 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)  		return;  	}  	LLPointer<LLViewerInventoryCategory> cat = getCategory(id); -	if(cat.notNull()) -	{ -		// do the cache accounting -		llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -				<< llendl; -		S32 descendents = cat->getDescendentCount(); -		if(descendents > 0) -		{ -			LLCategoryUpdate up(id, -descendents); -			accountForUpdate(up); +	if (cat.notNull()) +	{ +		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) +		{ +			// Something on the clipboard is in "cut mode" and needs to be preserved +			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() +			<< " iterate and purge non hidden items" << llendl; +			cat_array_t* categories; +			item_array_t* items; +			// Get the list of direct descendants in tha categoy passed as argument +			getDirectDescendentsOf(id, categories, items); +			std::vector<LLUUID> list_uuids; +			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) +			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists +			for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) +			{ +				list_uuids.push_back((*it)->getUUID()); +			} +			// Iterate through the list and only purge the UUIDs that are not on the clipboard +			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) +			{ +				if (!LLClipboard::instance().isOnClipboard(*it)) +				{ +					purgeObject(*it); +				} +			}  		} +		else +		{ +			// Fast purge +			// do the cache accounting +			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() +				<< llendl; +			S32 descendents = cat->getDescendentCount(); +			if(descendents > 0) +			{ +				LLCategoryUpdate up(id, -descendents); +				accountForUpdate(up); +			} -		// we know that descendent count is 0, aide since the -		// accounting may actually not do an update, we should force -		// it here. -		cat->setDescendentCount(0); +			// we know that descendent count is 0, however since the +			// accounting may actually not do an update, we should force +			// it here. +			cat->setDescendentCount(0); + +			// send it upstream +			LLMessageSystem* msg = gMessageSystem; +			msg->newMessage("PurgeInventoryDescendents"); +			msg->nextBlock("AgentData"); +			msg->addUUID("AgentID", gAgent.getID()); +			msg->addUUID("SessionID", gAgent.getSessionID()); +			msg->nextBlock("InventoryData"); +			msg->addUUID("FolderID", id); +			gAgent.sendReliableMessage(); -		// send it upstream -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessage("PurgeInventoryDescendents"); -		msg->nextBlock("AgentData"); -		msg->addUUID("AgentID", gAgent.getID()); -		msg->addUUID("SessionID", gAgent.getSessionID()); -		msg->nextBlock("InventoryData"); -		msg->addUUID("FolderID", id); -		gAgent.sendReliableMessage(); - -		// unceremoniously remove anything we have locally stored. -		cat_array_t categories; -		item_array_t items; -		collectDescendents(id, -						   categories, -						   items, -						   INCLUDE_TRASH); -		S32 count = items.count(); -		S32 i; -		for(i = 0; i < count; ++i) -		{ -			deleteObject(items.get(i)->getUUID()); -		} -		count = categories.count(); -		for(i = 0; i < count; ++i) -		{ -			deleteObject(categories.get(i)->getUUID()); +			// unceremoniously remove anything we have locally stored. +			cat_array_t categories; +			item_array_t items; +			collectDescendents(id, +							   categories, +							   items, +							   INCLUDE_TRASH); +			S32 count = items.count(); +			for(S32 i = 0; i < count; ++i) +			{ +				deleteObject(items.get(i)->getUUID()); +			} +			count = categories.count(); +			for(S32 i = 0; i < count; ++i) +			{ +				deleteObject(categories.get(i)->getUUID()); +			}  		}  	}  } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index c47b74815f..71dd963f28 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -33,6 +33,7 @@  #include "llagentwearables.h"  #include "llappearancemgr.h"  #include "llavataractions.h" +#include "llclipboard.h"  #include "llfloaterinventory.h"  #include "llfloaterreg.h"  #include "llfloatersidepanelcontainer.h" @@ -248,6 +249,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)  		getFilter()->setFilterEmptySystemFolders();  	} +	// keep track of the clipboard state so that we avoid filtering too much +	mClipboardState = LLClipboard::instance().getGeneration(); +	  	// Initialize base class params.  	LLPanel::initFromParams(params);  } @@ -278,6 +282,14 @@ void LLInventoryPanel::draw()  {  	// Select the desired item (in case it wasn't loaded when the selection was requested)  	mFolderRoot->updateSelection(); +	 +	// Nudge the filter if the clipboard state changed +	if (mClipboardState != LLClipboard::instance().getGeneration()) +	{ +		mClipboardState = LLClipboard::instance().getGeneration(); +		getFilter()->setModified(LLClipboard::instance().isCutMode() ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); +	} +	  	LLPanel::draw();  } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 7d805f6862..6db59afb9b 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -222,6 +222,7 @@ public:  private:  	std::string					mSortOrderSetting; +	int							mClipboardState;  	//--------------------------------------------------------------------  	// Hidden folders diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index c7454e85a9..68a3b6d1cd 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -1149,7 +1149,7 @@ Rules:  	- cut/rename/delete in any other accordions  	- paste - only in Favorites, Landmarks accordions   3. For Folders we can: perform any action in Landmarks accordion, except Received folder - 4. We can not paste folders from Clipboard (processed by LLFolderView::canPaste()) + 4. We can paste folders from Clipboard (processed by LLFolderView::canPaste())   5. Check LLFolderView/Inventory Bridges rules   */  bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFolderViewItem* item) const @@ -1206,8 +1206,7 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold  		if ("cut" == command_name)  		{ -			// "Cut" disabled for folders. See EXT-8697. -			can_be_modified = root_folder->canCut() && listenerp->getInventoryType() != LLInventoryType::IT_CATEGORY; +			can_be_modified = root_folder->canCut();  		}  		else if ("rename" == command_name)  		{ diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index c3c62920d3..c11597f532 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -375,7 +375,7 @@ void LLPanelMainInventory::onClearSearch()  	if (mActivePanel)  	{  		mActivePanel->setFilterSubString(LLStringUtil::null); -		mActivePanel->setFilterTypes(0xffffffff); +		mActivePanel->setFilterTypes(0xffffffffffffffffULL);  		mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS);  	} @@ -726,7 +726,7 @@ void LLFloaterInventoryFinder::updateElementsFromFilter()  void LLFloaterInventoryFinder::draw()  {  	LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); -	U32 filter = 0xffffffff; +	U64 filter = 0xffffffffffffffffULL;  	BOOL filtered_by_all_types = TRUE;  	if (!getChild<LLUICtrl>("check_animation")->getValue()) diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index f3ecba7185..1ca24f3031 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -124,7 +124,7 @@ public:  	virtual void move(LLFolderViewEventListener* parent_listener);  	virtual BOOL isItemCopyable() const;  	virtual BOOL copyToClipboard() const; -	virtual void cutToClipboard(); +	virtual BOOL cutToClipboard() const;  	virtual BOOL isClipboardPasteable() const;  	virtual void pasteFromClipboard();  	virtual void pasteLinkFromClipboard(); @@ -524,8 +524,9 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const  	return FALSE;  } -void LLTaskInvFVBridge::cutToClipboard() +BOOL LLTaskInvFVBridge::cutToClipboard() const  { +	return FALSE;  }  BOOL LLTaskInvFVBridge::isClipboardPasteable() const diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 1f1cccad85..c63d89fc98 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -358,7 +358,7 @@ void LLTeleportHistoryPanel::ContextMenu::onInfo()  //static  void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl)  { -	gClipboard.copyFromString(utf8str_to_wstring(slurl)); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size());  }  void LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard() diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index eb4c7572d4..280cc11179 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -467,7 +467,7 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item)  		LLAgentUI::buildSLURL(slurl, false);  		LLUIString location_str(slurl.getSLURLString()); -		gClipboard.copyFromString(location_str); +		LLClipboard::instance().copyToClipboard(location_str,0,location_str.length());  	}  } diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index e2801c09bd..3b9934d4be 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -302,6 +302,6 @@ void LLPanelWearing::copyToClipboard()  		}  	} -	gClipboard.copyFromString(utf8str_to_wstring(text)); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(text),0,text.size());  }  // EOF diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index eccb2cf2f1..81ad96f39e 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -75,6 +75,7 @@ LLToolBarView::LLToolBarView(const LLToolBarView::Params& p)  	mDragStarted(false),  	mShowToolbars(true),  	mDragToolbarButton(NULL), +	mDragItem(NULL),  	mToolbarsLoaded(false)  {  	for (S32 i = 0; i < TOOLBAR_COUNT; i++) @@ -579,7 +580,6 @@ BOOL LLToolBarView::handleDragTool( S32 x, S32 y, const LLUUID& uuid, LLAssetTyp  			uuid_vec_t cargo_ids;  			types.push_back(DAD_WIDGET);  			cargo_ids.push_back(uuid); -			gClipboard.setSourceObject(uuid,LLAssetType::AT_WIDGET);  			LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_VIEWER;  			LLUUID srcID;  			LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, src, srcID); @@ -662,6 +662,18 @@ void LLToolBarView::resetDragTool(LLToolBarButton* toolbarButton)  	gToolBarView->mDragToolbarButton = toolbarButton;  } +// Provide a handle on a free standing inventory item containing references to the tool. +// This might be used by Drag and Drop to move around references to tool items. +LLInventoryObject* LLToolBarView::getDragItem() +{ +	if (mDragToolbarButton) +	{ +		LLUUID item_uuid = mDragToolbarButton->getCommandId().uuid(); +		mDragItem = new LLInventoryObject (item_uuid, LLUUID::null, LLAssetType::AT_WIDGET, ""); +	} +	return mDragItem; +} +  void LLToolBarView::setToolBarsVisible(bool visible)  {  	mShowToolbars = visible; diff --git a/indra/newview/lltoolbarview.h b/indra/newview/lltoolbarview.h index be66bcae36..9c4194ebed 100644 --- a/indra/newview/lltoolbarview.h +++ b/indra/newview/lltoolbarview.h @@ -31,6 +31,7 @@  #include "lluictrl.h"  #include "lltoolbar.h"  #include "llcommandmanager.h" +#include "llinventory.h"  class LLUICtrlFactory; @@ -106,6 +107,7 @@ public:  	static BOOL handleDragTool(S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type);  	static BOOL handleDropTool(void* cargo_data, S32 x, S32 y, LLToolBar* toolbar);  	static void resetDragTool(LLToolBarButton* toolbarButton); +	LLInventoryObject* getDragItem();  	bool isModified() const; @@ -129,6 +131,7 @@ private:  	bool				mDragStarted;  	LLToolBarButton*	mDragToolbarButton; +	LLInventoryObject*	mDragItem;  	bool				mShowToolbars;  }; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index c7ab934f9e..4f4eef0f3d 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -48,6 +48,7 @@  #include "llpreviewnotecard.h"  #include "llrootview.h"  #include "llselectmgr.h" +#include "lltoolbarview.h"  #include "lltoolmgr.h"  #include "lltooltip.h"  #include "lltrans.h" @@ -2528,7 +2529,7 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(  	}  	else if(mSource == SOURCE_VIEWER)  	{ -		item = (LLViewerInventoryItem*)gClipboard.getSourceObject(); +		item = (LLViewerInventoryItem*)gToolBarView->getDragItem();  	}  	if(item) return item;  	if(cat) return cat; diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 56b5bbf942..cad5769042 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -89,5 +89,5 @@ void LLURLLineEditor::copyEscapedURLToClipboard()  	else // human-readable location  		text_to_copy = utf8str_to_wstring(unescaped_text); -	gClipboard.copyFromString( text_to_copy ); +	LLClipboard::instance().copyToClipboard(text_to_copy, 0, text_to_copy.size());  } diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index ef4a1bc061..b13bf5b508 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -453,6 +453,14 @@       layout="topleft"        name="Copy Separator" />      <menu_item_call +     label="Cut" +     layout="topleft" +     name="Cut"> +        <menu_item_call.on_click +         function="Inventory.DoToSelected" +         parameter="cut" /> +    </menu_item_call> +    <menu_item_call       label="Copy"       layout="topleft"       name="Copy"> | 
