Просмотр исходного кода

TreeView and ProjectLibrary fixes

Marko Pintera 12 лет назад
Родитель
Сommit
619ef4a028

+ 2 - 0
CamelotClient/Include/BsGUIResourceTreeView.h

@@ -2,6 +2,7 @@
 
 #include "BsEditorPrerequisites.h"
 #include "BsGUITreeView.h"
+#include "BsProjectLibrary.h"
 #include <boost/signal.hpp>
 
 namespace BansheeEditor
@@ -75,6 +76,7 @@ namespace BansheeEditor
 		virtual void dragAndDropEnded(TreeElement* overTreeElement);
 		virtual void dragAndDropFinalize();
 
+		void updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry);
 		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const CM::WString& fullPath);
 		void deleteTreeElement(ResourceTreeElement* element);
 		void sortTreeElement(ResourceTreeElement* element);

+ 52 - 36
CamelotClient/Source/BsGUIResourceTreeView.cpp

@@ -35,16 +35,6 @@ namespace BansheeEditor
 		:GUITreeView(parent, backgroundStyle, elementBtnStyle, foldoutBtnStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle,
 		dragSepHighlightStyle, layoutOptions), mDraggedResources(nullptr), mCurrentWindow(nullptr), mDropTarget(nullptr), mDropTargetDragActive(false)
 	{
-		struct StackElem
-		{
-			StackElem(const ProjectLibrary::LibraryEntry* entry, ResourceTreeElement* treeElem)
-				:entry(entry), treeElem(treeElem)
-			{ }
-
-			const ProjectLibrary::LibraryEntry* entry;
-			ResourceTreeElement* treeElem;
-		};
-
 		ProjectLibrary::instance().onEntryAdded.connect(boost::bind(&GUIResourceTreeView::entryAdded, this, _1));
 		ProjectLibrary::instance().onEntryRemoved.connect(boost::bind(&GUIResourceTreeView::entryRemoved, this, _1));
 
@@ -54,28 +44,7 @@ namespace BansheeEditor
 		mRootElement.mElementName = Path::getFilename(mRootElement.mFullPath);
 		expandElement(&mRootElement);
 
-		Stack<StackElem>::type todo;
-		todo.push(StackElem(rootEntry, &mRootElement));
-
-		while(!todo.empty())
-		{
-			StackElem curElem = todo.top();
-			todo.pop();
-
-			const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
-
-			for(auto& child : dirEntry->mChildren)
-			{
-				ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, child->path);
-
-				if(child->type == ProjectLibrary::LibraryEntryType::Directory)
-					todo.push(StackElem(child, newChild));
-			}
-
-			sortTreeElement(curElem.treeElem);
-		}
-
-		
+		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
 
 		if(parent.getTarget()->getTarget()->isWindow())
 		{
@@ -130,6 +99,43 @@ namespace BansheeEditor
 		ProjectLibrary::instance().moveEntry(oldPath, findUniquePath(newPath));
 	}
 
+	void GUIResourceTreeView::updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry)
+	{
+		struct StackElem
+		{
+			StackElem(const ProjectLibrary::LibraryEntry* entry, ResourceTreeElement* treeElem)
+				:entry(entry), treeElem(treeElem)
+			{ }
+
+			const ProjectLibrary::LibraryEntry* entry;
+			ResourceTreeElement* treeElem;
+		};
+
+		if(libraryEntry->type == ProjectLibrary::LibraryEntryType::Directory)
+		{
+			Stack<StackElem>::type todo;
+			todo.push(StackElem(libraryEntry, treeElement));
+
+			while(!todo.empty())
+			{
+				StackElem curElem = todo.top();
+				todo.pop();
+
+				const ProjectLibrary::DirectoryEntry* dirEntry = static_cast<const ProjectLibrary::DirectoryEntry*>(curElem.entry);
+
+				for(auto& child : dirEntry->mChildren)
+				{
+					ResourceTreeElement* newChild = addTreeElement(curElem.treeElem, child->path);
+
+					if(child->type == ProjectLibrary::LibraryEntryType::Directory)
+						todo.push(StackElem(child, newChild));
+				}
+
+				sortTreeElement(curElem.treeElem);
+			}
+		}
+	}
+
 	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const CM::WString& fullPath)
 	{
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
@@ -249,9 +255,14 @@ namespace BansheeEditor
 		ResourceTreeElement* parentElement = findTreeElement(parentPath);
 		assert(parentElement != nullptr);
 
-		addTreeElement(parentElement, path);
+		ResourceTreeElement* newElement = addTreeElement(parentElement, path);
 		sortTreeElement(parentElement);
 
+		ProjectLibrary::LibraryEntry* libEntry = ProjectLibrary::instance().findEntry(path);
+		
+		assert(libEntry != nullptr);
+		updateFromProjectLibraryEntry(newElement, libEntry);
+
 		markContentAsDirty();
 	}
 
@@ -397,10 +408,11 @@ namespace BansheeEditor
 		{
 			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(selectedElement.element);
 			internalDraggedResources->resourcePaths[cnt] = resourceTreeElement->mFullPath; 
-			cnt++;
 
 			if(resourceManifest->filePathExists(internalDraggedResources->resourcePaths[cnt]))
 				draggedResources->resourceUUIDs.push_back(resourceManifest->filePathToUUID(internalDraggedResources->resourcePaths[cnt]));
+
+			cnt++;
 		}
 
 		mDraggedResources = internalDraggedResources;
@@ -422,9 +434,13 @@ namespace BansheeEditor
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			{
 				WString filename = Path::getFilename(mDraggedResources->resourcePaths[i]);
+				WString currentParent = Path::parentPath(mDraggedResources->resourcePaths[i]);
 
-				WString newPath = Path::combine(destDir, filename);
-				ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
+				if(!Path::equals(currentParent, destDir))
+				{
+					WString newPath = Path::combine(destDir, filename);
+					ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
+				}
 			}
 		}
 	}

+ 3 - 0
CamelotClient/Source/BsGUITreeView.cpp

@@ -548,6 +548,9 @@ namespace BansheeEditor
 				todo.pop();
 
 				curElem->mIsVisible = false;
+				if(curElem->mIsSelected)
+					unselectElement(curElem);
+
 				updateElementGUI(curElem);
 
 				if(curElem->mIsExpanded)

+ 27 - 6
CamelotClient/Source/BsProjectLibrary.cpp

@@ -156,7 +156,7 @@ namespace BansheeEditor
 							WString sourceFilePath = filePath;
 							Path::replaceExtension(sourceFilePath, L"");
 
-							if(FileSystem::isFile(sourceFilePath))
+							if(!FileSystem::isFile(sourceFilePath))
 							{
 								LOGWRN("Found a .meta file without a corresponding resource. Deleting.");
 
@@ -169,7 +169,7 @@ namespace BansheeEditor
 							UINT32 idx = 0;
 							for(auto& child : currentDir->mChildren)
 							{
-								if(child->type == LibraryEntryType::File && child->path == filePath)
+								if(child->type == LibraryEntryType::File && Path::equals(child->path, filePath))
 								{
 									existingEntries[idx] = true;
 									existingEntry = static_cast<ResourceEntry*>(child);
@@ -196,7 +196,7 @@ namespace BansheeEditor
 						UINT32 idx = 0;
 						for(auto& child : currentDir->mChildren)
 						{
-							if(child->type == LibraryEntryType::Directory && child->path == dirPath)
+							if(child->type == LibraryEntryType::Directory && Path::equals(child->path, dirPath))
 							{
 								existingEntries[idx] = true;
 								existingEntry = static_cast<DirectoryEntry*>(child);
@@ -295,7 +295,8 @@ namespace BansheeEditor
 		if(directory == mRootEntry)
 			mRootEntry = nullptr;
 
-		for(auto& child : directory->mChildren)
+		CM::Vector<LibraryEntry*>::type childrenToDestroy = directory->mChildren;
+		for(auto& child : childrenToDestroy)
 		{
 			if(child->type == LibraryEntryType::Directory)
 				deleteDirectoryInternal(static_cast<DirectoryEntry*>(child));
@@ -318,8 +319,7 @@ namespace BansheeEditor
 	void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
 	{
 		WString ext = Path::getExtension(resource->path);
-		WString metaPath = resource->path;
-		Path::replaceExtension(metaPath, ext + L".meta");
+		WString metaPath = resource->path + L".meta";
 
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		if(!Importer::instance().supportsFileType(ext))
@@ -492,6 +492,27 @@ namespace BansheeEditor
 				oldEntry->path = newPath;
 				oldEntry->elementName = Path::getFilename(newPath);
 
+				if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
+				{
+					Stack<LibraryEntry*>::type todo;
+					todo.push(oldEntry);
+
+					while(!todo.empty())
+					{
+						LibraryEntry* curEntry = todo.top();
+						todo.pop();
+
+						DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
+						for(auto& child : curDirEntry->mChildren)
+						{
+							child->path = Path::combine(child->parent->path, child->elementName);
+
+							if(child->type == LibraryEntryType::Directory)
+								todo.push(child);
+						}
+					}
+				}
+
 				if(!onEntryRemoved.empty())
 					onEntryRemoved(oldPath);
 

+ 40 - 8
CamelotUtility/Include/CmPath.h

@@ -61,7 +61,7 @@ namespace CamelotFramework
 		{
 			Vector<WString>::type splitPath;
 
-			WString standardizedPath = standardisePath(path);
+			WString standardizedPath = standardizePath(path);
 			return StringUtil::split(standardizedPath, L"/");
 		}
 
@@ -73,6 +73,41 @@ namespace CamelotFramework
 				return base + L'/' + name;
 		}
 
+		/**
+		 * @brief	Compares two canonical paths and returns true if they are equal.
+		 */
+		static bool equals(const WString& left, const WString& right)
+		{
+			Vector<WString>::type leftElements = split(left);
+			Vector<WString>::type rightElements = split(right);
+
+			UINT32 idx = 0;
+			for(auto& leftElem : leftElements)
+			{
+				if(leftElem.empty())
+					continue;
+				
+				while(idx < (UINT32)rightElements.size() && rightElements[idx].empty())
+					idx++;
+
+				if(idx >= (UINT32)rightElements.size())
+					return false; // Right path is deeper than left path
+
+				if(!comparePathElements(leftElem, rightElements[idx]))
+					return false;
+
+				idx++;
+			}
+
+			while(idx < (UINT32)rightElements.size() && rightElements[idx].empty())
+				idx++;
+
+			if(idx < (UINT32)rightElements.size())
+				return false; // Left path is deeper than right path
+
+			return true;
+		}
+
 		/**
 		 * @brief	Compares two path elements for equality. 
 		 * 			
@@ -106,19 +141,16 @@ namespace CamelotFramework
 		}
 
 		/**
-		 * @brief	Method for standardizing paths - use forward slashes only, end with slash.
+		 * @brief	Method for standardizing paths - use forward slashes only, end without a slash.
 		 */
-		static WString standardisePath(const WString& inPath)
+		static WString standardizePath(const WString& inPath)
 		{
 			WString path = inPath;
 
 			std::replace(path.begin(), path.end(), L'\\', L'/');
 
-			if(path.length() > 0)
-			{
-				if(path[path.length() - 1] != L'/')
-					path += L'/';
-			}
+			while(path.length() > 0 && path.back() == L'/')
+				path.pop_back();
 
 			return path;
 		}

+ 1 - 0
CamelotUtility/Source/CmFileSystem.cpp

@@ -2,6 +2,7 @@
 #include "CmDataStream.h"
 #include "CmPath.h"
 #include "CmException.h"
+#include "CmDebug.h"
 
 #include <boost/filesystem.hpp>
 

+ 3 - 13
ProjectLibrary.txt

@@ -1,8 +1,9 @@
 
 TODO
+ - Moving files within the TreeView will still cause them to be reimported
+  - UUIDs in meta files dont seem to match.
+  - I need a way to import a resource while keeping the existing UUID (maybe reimport() method?)
  - ResourceManifest filePathToUUID wont work as intended as file-path comparison is case sensitive plus it wont deal with slashes properly
- - Remove WPath. In general, but specifically from CmPath.h, CmFileSystem.h and Projectlibrary
- - ResourceTreeView - Element sorting doesn't work
  - ProjectLibrary Save/Load - saves/loads the hierarchy of ResourceEntries
     - ResourceManifest needs to store relative locations when I save it, so that user can move Project folder safely
  - Resource import queue (ability to display progress bar for resources that are importing)
@@ -11,21 +12,10 @@ TODO
 --------------------
 
 Test:
- - OSDropTarget
-    - Drag and drop one file from Explorer into TreeView
-    - Drag and drop multiple files from Explorer into TreeView
-    - Drag and drop entire folders from Explorer into TreeView
-    - Dragging folders or files from within Resources to another sub-folder in Resources
-
  - File monitoring
-    - Add a file and ensure it is imported
     - Delete a file and ensure it has been cleaned up
-    - Add a whole folder hierarchy with files and see if it is constructed properly
     - Delete a folder hierarcha and ensure it has been cleaned up
 
- - Start-up
-     - Load up ProjectLibrary with a complex hierarchy already existing, with multiple files to import
-
  - Save/Load (After it is implemented)
      - Ensure that leaving application and then reloading will still recognize previously saved assets and will not reimport them
        - Also ensure that UUIDs will be properly read from .meta files