[Monodevelop-patches-list] r2433 - in trunk/MonoDevelop/Core/src/MonoDevelop.Base: . Commands Commands/ProjectBrowserCommands Gui/Pads/ClassPad Gui/Pads/ProjectPad Gui/Pads/SolutionPad Internal/Project/Project Internal/Project/Project/Collections Services/DispatchService Services/File Services/Project Services/Tasks

Lluis Sanchez <lluis@ximian.com> lluis at mono-cvs.ximian.com
Wed Apr 6 20:02:46 EDT 2005


Author: lluis
Date: 2005-04-06 20:02:46 -0400 (Wed, 06 Apr 2005)
New Revision: 2433

Added:
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFile.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/NodeState.cs
Modified:
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/ChangeLog
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/MenuItemBuilders.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/FolderNodeCommands.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/GeneralNodeCommands.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ClassNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/CombineNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/EventNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeCommandHandler.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/NamespaceNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ProjectNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/CombineNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/FolderNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeBuilderContext.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeNavigator.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TreeViewPad.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TypeNodeBuilder.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Collections/ProjectFileCollection.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Project.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Makefile.am
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/MonoDevelopCore.addin.xml
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/DispatchService/DispatchService.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/DefaultFileService.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/IFileService.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/IProjectService.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/ProjectService.cs
   trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Tasks/Task.cs
Log:
2005-04-07  Lluis Sanchez Gual  <lluis at novell.com>

	* Commands/ProjectBrowserCommands/FolderNodeCommands.cs: Implemented
	IncludeFileToProject command.
	* Commands/ProjectBrowserCommands/GeneralNodeCommands.cs:
	New copy/cut/paste commands for tree nodes.
	* Services/File/DefaultFileService.cs:
	IFileService.cs: Use a progress monitor when opening files. OpenFile now
	return an IAsyncOperation object that can be used to track the status
	of the operation. Added methods for copying and moving files.
	* Services/DispatchService/DispatchService.cs: Dispatch all pending
	messages at once in the GUI thread. It gives better performance.
	* Services/Tasks/Task.cs: Track changes in IFileService.
	
	* Services/Project/IProjectService.cs:
	* Services/Project/ProjectService.cs: Implemented method for copying
	files between projects.
	
	* Gui/Pads/SolutionPad/TreeViewPad.cs: Implemented support for
	drag&drop and copy/paste. Some other internal improvements.
	* Gui/Pads/SolutionPad/ITreeNavigator.cs,
	* Gui/Pads/SolutionPad/TypeNodeBuilder.cs: Some API adjustments.
	* Gui/Pads/SolutionPad/NodeState.cs: New class that can store the
	status of a tree.
	
	* Gui/Pads/ProjectPad/ProjectFolder.cs:
	* Gui/Pads/ProjectPad/ProjectNodeBuilder.cs:
	* Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs:
	* Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs:
	* Gui/Pads/ProjectPad/FolderNodeBuilder.cs:
	* MonoDevelopCore.addin.xml:
	Implemented support for drag&drop of files and folders. Moved all code
	that handles the ShowAllFiles option to its own node builder extension.
	
	* Gui/Pads/ProjectPad/SystemFile.cs:
	* Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs:
	* Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs:
	New classes that implement the ShowAllFiles option.
	
	* Gui/Pads/ProjectPad/CombineNodeBuilder.cs:
	* Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs:
	* Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs:
	* Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs:
	* Gui/Pads/ClassPad/ClassNodeBuilder.cs:
	* Gui/Pads/ClassPad/ProjectNodeBuilder.cs:
	* Gui/Pads/ClassPad/MemberNodeBuilder.cs:
	* Gui/Pads/ClassPad/CombineNodeBuilder.cs:
	* Gui/Pads/ClassPad/NamespaceNodeBuilder.cs:
	* Gui/Pads/ClassPad/MemberNodeCommandHandler.cs:
	* Gui/Pads/ClassPad/EventNodeBuilder.cs: Track api changes.
	
	* Gui/Pads/ProjectPad/ResourceFolder.cs: Implemented Equals().
	
	* Internal/Project/Project/Project.cs: Set the project as dirty when its
	files change.
	
	* Internal/Project/Project/Collections/ProjectFileCollection.cs: new
	method for getting all files in a path.
	
	* Commands/MenuItemBuilders.cs: Removed debug code.



Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/ChangeLog
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/ChangeLog	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/ChangeLog	2005-04-07 00:02:46 UTC (rev 2433)
@@ -1,3 +1,64 @@
+2005-04-07  Lluis Sanchez Gual  <lluis at novell.com>
+
+	* Commands/ProjectBrowserCommands/FolderNodeCommands.cs: Implemented
+	IncludeFileToProject command.
+	* Commands/ProjectBrowserCommands/GeneralNodeCommands.cs:
+	New copy/cut/paste commands for tree nodes.
+	* Services/File/DefaultFileService.cs:
+	IFileService.cs: Use a progress monitor when opening files. OpenFile now
+	return an IAsyncOperation object that can be used to track the status
+	of the operation. Added methods for copying and moving files.
+	* Services/DispatchService/DispatchService.cs: Dispatch all pending
+	messages at once in the GUI thread. It gives better performance.
+	* Services/Tasks/Task.cs: Track changes in IFileService.
+	
+	* Services/Project/IProjectService.cs:
+	* Services/Project/ProjectService.cs: Implemented method for copying
+	files between projects.
+	
+	* Gui/Pads/SolutionPad/TreeViewPad.cs: Implemented support for
+	drag&drop and copy/paste. Some other internal improvements.
+	* Gui/Pads/SolutionPad/ITreeNavigator.cs,
+	* Gui/Pads/SolutionPad/TypeNodeBuilder.cs: Some API adjustments.
+	* Gui/Pads/SolutionPad/NodeState.cs: New class that can store the
+	status of a tree.
+	
+	* Gui/Pads/ProjectPad/ProjectFolder.cs:
+	* Gui/Pads/ProjectPad/ProjectNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/FolderNodeBuilder.cs:
+	* MonoDevelopCore.addin.xml:
+	Implemented support for drag&drop of files and folders. Moved all code
+	that handles the ShowAllFiles option to its own node builder extension.
+	
+	* Gui/Pads/ProjectPad/SystemFile.cs:
+	* Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs:
+	* Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs:
+	New classes that implement the ShowAllFiles option.
+	
+	* Gui/Pads/ProjectPad/CombineNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs:
+	* Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs:
+	* Gui/Pads/ClassPad/ClassNodeBuilder.cs:
+	* Gui/Pads/ClassPad/ProjectNodeBuilder.cs:
+	* Gui/Pads/ClassPad/MemberNodeBuilder.cs:
+	* Gui/Pads/ClassPad/CombineNodeBuilder.cs:
+	* Gui/Pads/ClassPad/NamespaceNodeBuilder.cs:
+	* Gui/Pads/ClassPad/MemberNodeCommandHandler.cs:
+	* Gui/Pads/ClassPad/EventNodeBuilder.cs: Track api changes.
+	
+	* Gui/Pads/ProjectPad/ResourceFolder.cs: Implemented Equals().
+	
+	* Internal/Project/Project/Project.cs: Set the project as dirty when its
+	files change.
+	
+	* Internal/Project/Project/Collections/ProjectFileCollection.cs: new
+	method for getting all files in a path.
+	
+	* Commands/MenuItemBuilders.cs: Removed debug code.
+
 2005-04-06  Chris Toshok  <toshok at ximian.com>
 
 	* Services/IDebuggerService.cs: remove the CurrentFrame property,

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/MenuItemBuilders.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/MenuItemBuilders.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/MenuItemBuilders.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -278,7 +278,6 @@
 		
 		public Gtk.MenuItem[] BuildSubmenu(ConditionCollection conditionCollection, object owner)
 		{
-			Runtime.LoggingService.Info (Environment.StackTrace);
 			browser = (SolutionPad) owner;
 			ITreeNavigator nav = browser.GetSelectedNode ();
 			if (nav == null) return new Gtk.MenuItem[0];

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/FolderNodeCommands.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/FolderNodeCommands.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/FolderNodeCommands.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -208,4 +208,24 @@
 			browser.StartLabelEdit();
 		}
 	}
+	
+	public class IncludeFileToProject : AbstractMenuCommand
+	{
+		public override void Run ()
+		{
+			SolutionPad browser = (SolutionPad) Owner;
+			ITreeNavigator nav = browser.GetSelectedNode ();
+			if (nav == null) return;
+			
+			Project project = nav.GetParentDataItem (typeof(Project), true) as Project;
+			
+			if (nav.DataItem is SystemFile) {
+				SystemFile file = (SystemFile) nav.DataItem;
+				if (project.IsCompileable (file.Path))
+					project.AddFile (file.Path, BuildAction.Compile);
+				else
+					project.AddFile (file.Path, BuildAction.Nothing);
+			}
+		}
+	}
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/GeneralNodeCommands.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/GeneralNodeCommands.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Commands/ProjectBrowserCommands/GeneralNodeCommands.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -53,5 +53,32 @@
 			browser.ActivateCurrentItem ();
 		}
 	}
+	
+	public class CopyNodeCommand: AbstractMenuCommand
+	{
+		public override void Run()
+		{
+			TreeViewPad browser = (TreeViewPad)Owner;
+			browser.CopyCurrentItem ();
+		}
+	}
+	
+	public class CutNodeCommand: AbstractMenuCommand
+	{
+		public override void Run()
+		{
+			TreeViewPad browser = (TreeViewPad)Owner;
+			browser.CutCurrentItem ();
+		}
+	}
+	
+	public class PasteNodeCommand: AbstractMenuCommand
+	{
+		public override void Run()
+		{
+			TreeViewPad browser = (TreeViewPad)Owner;
+			browser.PasteToCurrentItem ();
+		}
+	}
 }
 

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ClassNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ClassNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ClassNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -44,8 +44,8 @@
 		public override Type CommandHandlerType {
 			get { return typeof(ClassNodeCommandHandler); }
 		}
-		
-		public override string GetNodeName (object dataObject)
+
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((ClassData)dataObject).Class.Name;
 		}
@@ -87,9 +87,9 @@
 					classData.Class.Events.Count > 0;
 		}
 		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			if (otherDataObject is ClassData)
+			if (thisNode.DataItem is ClassData)
 				return DefaultSort;
 			else
 				return 1;
@@ -101,11 +101,14 @@
 		public override void ActivateItem ()
 		{
 			string file = GetFileName ();
-			Runtime.FileService.OpenFile (file, new FileOpeningFinished (OnFileOpened));
+			IAsyncOperation op = Runtime.FileService.OpenFile (file);
+			op.Completed += new OperationHandler (OnFileOpened);
 		}
 		
-		private void OnFileOpened()
+		private void OnFileOpened (IAsyncOperation op)
 		{
+			if (!op.Success) return;
+
 			ClassData cls = CurrentNode.DataItem as ClassData;
 			int line = cls.Class.Region.BeginLine;
 			string file = GetFileName ();

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/CombineNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/CombineNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/CombineNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -51,7 +51,7 @@
 			get { return typeof(Combine); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((Combine)dataObject).Name;
 		}
@@ -89,9 +89,9 @@
 			return ((Combine) dataObject).Entries.Count > 0;
 		}
 		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			if (otherDataObject is Combine)
+			if (otherNode.DataItem is Combine)
 				return DefaultSort;
 			else
 				return -1;

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/EventNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/EventNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/EventNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -48,10 +48,9 @@
 			icon = Context.GetIcon (Runtime.Gui.Icons.GetIcon (data));
 		}
 
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			ITreeOptions options = Context.GetOptions (thisDataObject);
-			if (options ["GroupByType"]) {
+			if (thisNode.Options ["GroupByType"]) {
 			
 			}
 			return DefaultSort;

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -37,7 +37,7 @@
 {
 	public abstract class MemberNodeBuilder: TypeNodeBuilder
 	{
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((IMember)dataObject).Name;
 		}
@@ -46,20 +46,19 @@
 			get { return typeof(MemberNodeCommandHandler); }
 		}
 		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			if (!(otherDataObject is IMember)) return 1;
+			if (!(otherNode.DataItem is IMember)) return 1;
 
-			ITreeOptions options = Context.GetOptions (thisDataObject);
-			if (options ["GroupByType"]) {
-				int v1 = GetTypeSortValue (thisDataObject);
-				int v2 = GetTypeSortValue (otherDataObject);
+			if (thisNode.Options ["GroupByType"]) {
+				int v1 = GetTypeSortValue (thisNode.DataItem);
+				int v2 = GetTypeSortValue (otherNode.DataItem);
 				if (v1 < v2) return -1;
 				else if (v1 > v2) return 1;
 			}
-			if (options ["GroupByAccess"]) {
-				int v1 = GetAccessSortValue (((IMember)thisDataObject).Modifiers);
-				int v2 = GetAccessSortValue (((IMember)otherDataObject).Modifiers);
+			if (thisNode.Options ["GroupByAccess"]) {
+				int v1 = GetAccessSortValue (((IMember)thisNode.DataItem).Modifiers);
+				int v2 = GetAccessSortValue (((IMember)otherNode.DataItem).Modifiers);
 				if (v1 < v2) return -1;
 				else if (v1 > v2) return 1;
 			}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeCommandHandler.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeCommandHandler.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/MemberNodeCommandHandler.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -39,11 +39,14 @@
 		public override void ActivateItem ()
 		{
 			string file = GetFileName ();
-			Runtime.FileService.OpenFile (file, new FileOpeningFinished (OnFileOpened));
+			IAsyncOperation op = Runtime.FileService.OpenFile (file);
+			op.Completed += new OperationHandler (OnFileOpened);
 		}
 		
-		private void OnFileOpened()
+		private void OnFileOpened (IAsyncOperation op)
 		{
+			if (!op.Success) return;
+			
 			IMember member = CurrentNode.DataItem as IMember;
 			int line = member.Region.BeginLine;
 			string file = GetFileName ();

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/NamespaceNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/NamespaceNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/NamespaceNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -54,9 +54,9 @@
 			Runtime.ParserService.ClassInformationChanged -= changeClassInformationHandler;
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
-			return Context.GetOptions (dataObject) ["NestedNamespaces"] ? ((NamespaceData)dataObject).Name : ((NamespaceData)dataObject).FullName;
+			return thisNode.Options ["NestedNamespaces"] ? ((NamespaceData)dataObject).Name : ((NamespaceData)dataObject).FullName;
 		}
 		
 		public override void BuildNode (ITreeBuilder treeBuilder, object dataObject, ref string label, ref Gdk.Pixbuf icon, ref Gdk.Pixbuf closedIcon)

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ProjectNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ProjectNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ClassPad/ProjectNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -62,7 +62,7 @@
 			project.NameChanged -= projectNameChanged;
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((Project)dataObject).Name;
 		}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/CombineNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/CombineNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/CombineNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -55,7 +55,7 @@
 			get { return typeof(CombineNodeCommandHandler); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((Combine)dataObject).Name;
 		}
@@ -100,9 +100,9 @@
 			return ((Combine) dataObject).Entries.Count > 0;
 		}
 		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			if (otherDataObject is Combine)
+			if (otherNode.DataItem is Combine)
 				return DefaultSort;
 			else
 				return -1;

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/FolderNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/FolderNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/FolderNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -44,7 +44,7 @@
 		}
 		
 		public abstract string GetFolderPath (object dataObject);
-
+		
 		public override void BuildChildNodes (ITreeBuilder builder, object dataObject)
 		{
 			string path = GetFolderPath (dataObject);
@@ -59,43 +59,8 @@
 			
 			foreach (string folder in folders)
 				builder.AddChild (new ProjectFolder (folder, project));
-			
-			if (builder.Options ["ShowAllFiles"])
-			{
-				foreach (string file in Directory.GetFiles (path)) {
-					if (files.GetFile (file) == null)
-						builder.AddChild (new ProjectFile (file));
-				}
-					
-				foreach (string folder in Directory.GetDirectories (path))
-					if (!folders.Contains (folder))
-						builder.AddChild (new ProjectFolder (folder, null));
-			}
 		}
-		
-		protected void AddFile (ITreeBuilder builder, Project project, ProjectFile file)
-		{
-			if (file.BuildAction == BuildAction.EmbedAsResource)
-				return;
 				
-			string[] path = file.RelativePath.Split (Path.DirectorySeparatorChar);
-			StringBuilder sb = new StringBuilder (project.BaseDirectory);
-			for (int n=0; n<path.Length - 1; n++) {
-				string dir = path [n];
-				if (dir == ".") continue;
-				if (sb.Length > 0) sb.Append (Path.DirectorySeparatorChar);
-				sb.Append (dir);
-				if (!builder.MoveToChild (dir, typeof(ProjectFolder)))
-					builder.AddChild (new ProjectFolder (sb.ToString (), project), true);
-			}
-			if (file.Subtype == Subtype.Directory)
-				builder.AddChild (new ProjectFolder (file.FilePath, project));
-			else if (builder.Options ["ShowAllFiles"])
-				builder.UpdateChildren ();
-			else
-				builder.AddChild (file);
-		}
-
 		void GetFolderContent (Project project, string folder, out ProjectFileCollection files, out ArrayList folders)
 		{
 			files = new ProjectFileCollection ();
@@ -145,10 +110,69 @@
 
 			if (files.Count > 0 || folders.Count > 0) return true;
 			
-			if (builder.Options ["ShowAllFiles"])
-				return Directory.GetFiles (path).Length > 0 || Directory.GetDirectories (path).Length > 0;
+			return false;
+		}
+	}
+	
+	public abstract class FolderCommandHandler: NodeCommandHandler
+	{
+		public abstract string GetFolderPath (object dataObject);
 
+		public override bool CanDropNode (object dataObject, DragOperation operation)
+		{
+			string targetPath = GetFolderPath (CurrentNode.DataItem);
+			
+			if (dataObject is ProjectFile)
+				return Path.GetDirectoryName (((ProjectFile)dataObject).Name) != targetPath;
+			if (dataObject is ProjectFolder)
+				return ((ProjectFolder)dataObject).Path != targetPath;
 			return false;
 		}
-	}
+		
+		public override void OnNodeDrop (object dataObject, DragOperation operation)
+		{
+			string targetPath = GetFolderPath (CurrentNode.DataItem);
+			string what, source, where, how;
+			Project targetProject = (Project) CurrentNode.GetParentDataItem (typeof(Project), true);
+			Project sourceProject;
+			
+			bool ask;
+			if (operation == DragOperation.Move)
+				how = GettextCatalog.GetString ("move");
+			else
+				how = GettextCatalog.GetString ("copy");
+			
+			if (dataObject is ProjectFolder) {
+				source = ((ProjectFolder) dataObject).Path;
+				sourceProject = ((ProjectFolder) dataObject).Project;
+				what = string.Format (GettextCatalog.GetString ("the folder '{0}'"), Path.GetFileName(source));
+				ask = true;
+			}
+			else if (dataObject is ProjectFile) {
+				source = ((ProjectFile)dataObject).Name;
+				sourceProject = ((ProjectFile) dataObject).Project;
+				what = string.Format (GettextCatalog.GetString ("the file '{0}'"), Path.GetFileName(source));
+				ask = false;
+			} else {
+				return;
+			}
+			
+			if (targetPath == targetProject.BaseDirectory)
+				where = string.Format (GettextCatalog.GetString ("root folder of project '{0}'"), targetProject.Name);
+			else
+				where = string.Format (GettextCatalog.GetString ("folder '{0}'"), Path.GetFileName (targetPath));
+			
+			if (ask) {
+				if (!Runtime.MessageService.AskQuestion (String.Format (GettextCatalog.GetString ("Do you really want to {0} {1} to {2}?"), how, what, where)))
+					return;
+			}
+			
+			using (IProgressMonitor monitor = Runtime.TaskService.GetStatusProgressMonitor (GettextCatalog.GetString("Copying files ..."), Stock.CopyIcon, true))
+			{
+				bool move = operation == DragOperation.Move;
+				Runtime.ProjectService.TransferFiles (monitor, sourceProject, source, targetProject, targetPath, move, false);
+			}
+			Runtime.ProjectService.SaveCombine();
+		}
+	}	
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFileNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -45,7 +45,7 @@
 			get { return typeof(ProjectFileNodeCommandHandler); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return Path.GetFileName (((ProjectFile)dataObject).Name);
 		}
@@ -64,15 +64,15 @@
 			ProjectFile file = (ProjectFile) dataObject;
 			label = Path.GetFileName (file.FilePath);
 			icon = Context.GetIcon (Runtime.Gui.Icons.GetImageForFile (file.FilePath));
-			if (file.Project == null) {
-				Gdk.Pixbuf gicon = Context.GetComposedIcon (icon, "fade");
-				if (gicon == null) {
-					gicon = Runtime.Gui.Icons.MakeTransparent (icon, 0.5);
-					Context.CacheComposedIcon (icon, "fade", gicon);
-				}
-				icon = gicon;
-			}
 		}
+		
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
+		{
+			if (otherNode.DataItem is ProjectFolder)
+				return 1;
+			else
+				return DefaultSort;
+		}
 	}
 	
 	public class ProjectFileNodeCommandHandler: NodeCommandHandler
@@ -111,7 +111,15 @@
 			bool yes = Runtime.MessageService.AskQuestion (String.Format (GettextCatalog.GetString ("Are you sure you want to remove file {0} from project {1}?"), Path.GetFileName (file.Name), project.Name));
 			if (!yes) return;
 
-			Runtime.ProjectService.RemoveFileFromProject (file.Name);
+			ProjectFile[] inFolder = project.ProjectFiles.GetFilesInPath (Path.GetDirectoryName (file.Name));
+			if (inFolder.Length == 1 && inFolder [0] == file) {
+				// This is the last project file in the folder. Make sure we keep
+				// a reference to the folder, so it is not deleted from the tree.
+				ProjectFile folderFile = new ProjectFile (Path.GetDirectoryName (file.Name));
+				folderFile.Subtype = Subtype.Directory;
+				project.ProjectFiles.Add (folderFile);
+			}
+			project.ProjectFiles.Remove (file);
 			Runtime.ProjectService.SaveCombine();
 		}
 		

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -45,7 +45,6 @@
 			this.project = project;
 			this.absolutePath = absolutePath;
 			Runtime.FileService.FileRenamed += new FileEventHandler (OnFileRenamed);
-			Runtime.FileService.FileRemoved += new FileEventHandler (OnFileRemoved);
 		}
 		
 		public string Path {
@@ -60,18 +59,29 @@
 			get { return project; }
 		}
 		
+		public override bool Equals (object other)
+		{
+			ProjectFolder f = other as ProjectFolder;
+			return f != null && absolutePath == f.absolutePath && project == f.project;
+		}
+		
+		public override int GetHashCode ()
+		{
+			if (project != null)
+				return (absolutePath + project.Name).GetHashCode ();
+			else
+				return absolutePath.GetHashCode ();
+		}
+		
 		public void Dispose ()
 		{
 			Runtime.FileService.FileRenamed -= new FileEventHandler (OnFileRenamed);
-			Runtime.FileService.FileRemoved -= new FileEventHandler (OnFileRemoved);
 		}
 		
-		void OnFileRemoved (object sender, FileEventArgs e)
+		public void Remove ()
 		{
-			if (!e.IsDirectory || e.TargetFile != absolutePath) return;
-			
 			if (FolderRemoved != null) {
-				FolderRemoved(this, e);
+				FolderRemoved (this, new FileEventArgs (absolutePath, true));
 			}
 		}
 

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectFolderNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -51,7 +51,7 @@
 			get { return typeof(ProjectFolderCommandHandler); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((ProjectFolder)dataObject).Name;
 		}
@@ -78,6 +78,7 @@
 		
 		public override void OnNodeAdded (object dataObject)
 		{
+			base.OnNodeAdded (dataObject);
 			ProjectFolder folder = (ProjectFolder) dataObject;
 			folder.FolderRenamed += fileRenamedHandler;
 			folder.FolderRemoved += fileRemovedHandler;
@@ -85,6 +86,7 @@
 		
 		public override void OnNodeRemoved (object dataObject)
 		{
+			base.OnNodeRemoved (dataObject);
 			ProjectFolder folder = (ProjectFolder) dataObject;
 			folder.FolderRenamed -= fileRenamedHandler;
 			folder.FolderRemoved -= fileRemovedHandler;
@@ -93,54 +95,40 @@
 		
 		void OnFolderRenamed (object sender, FileEventArgs e)
 		{
-			ITreeBuilder tb = Context.GetTreeBuilder (sender);
+			ProjectFolder f = (ProjectFolder) sender;
+			ITreeBuilder tb = Context.GetTreeBuilder (new ProjectFolder (e.SourceFile, f.Project));
 			if (tb != null) tb.Update ();
 		}
 		
 		void OnFolderRemoved (object sender, FileEventArgs e)
 		{
 			ITreeBuilder tb = Context.GetTreeBuilder (sender);
-			if (tb != null) tb.Remove ();
+			if (tb != null) {
+				if (!tb.HasChildren())
+					tb.Remove ();
+				else
+					tb.UpdateAll ();
+			}
 		}
 	
 		public override void BuildNode (ITreeBuilder treeBuilder, object dataObject, ref string label, ref Gdk.Pixbuf icon, ref Gdk.Pixbuf closedIcon)
 		{
+			base.BuildNode (treeBuilder, dataObject, ref label, ref icon, ref closedIcon);
+
 			ProjectFolder folder = (ProjectFolder) dataObject;
 			label = folder.Name;
 			icon = folderOpenIcon;
 			closedIcon = folderClosedIcon;
-			
-			if (folder.Project == null)
-			{
-				Gdk.Pixbuf gicon = Context.GetComposedIcon (icon, "fade");
-				if (gicon == null) {
-					gicon = Runtime.Gui.Icons.MakeTransparent (icon, 0.5);
-					Context.CacheComposedIcon (icon, "fade", gicon);
-				}
-				icon = gicon;
-				
-				gicon = Context.GetComposedIcon (closedIcon, "fade");
-				if (gicon == null) {
-					gicon = Runtime.Gui.Icons.MakeTransparent (closedIcon, 0.5);
-					Context.CacheComposedIcon (closedIcon, "fade", gicon);
-				}
-				closedIcon = gicon;
-			}
 		}
-		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
-		{
-			if (otherDataObject is ProjectFolder)
-				return DefaultSort;
-			else if (otherDataObject is ProjectFile)
-				return -1;
-			else
-				return 1;
-		}
 	}
 	
-	public class ProjectFolderCommandHandler: NodeCommandHandler
+	public class ProjectFolderCommandHandler: FolderCommandHandler
 	{
+		public override string GetFolderPath (object dataObject)
+		{
+			return ((ProjectFolder)dataObject).Path;
+		}
+		
 		public override void RenameItem (string newName)
 		{
 			ProjectFolder folder = (ProjectFolder) CurrentNode.DataItem as ProjectFolder;
@@ -169,7 +157,23 @@
 			bool yes = Runtime.MessageService.AskQuestion (String.Format (GettextCatalog.GetString ("Do you want to remove folder {0}?"), folder.Name));
 			if (!yes) return;
 			
-			Runtime.ProjectService.RemoveFileFromProject (folder.Path);
+			Project project = folder.Project;
+			ProjectFile[] files = folder.Project.ProjectFiles.GetFilesInPath (folder.Path);
+			ProjectFile[] inParentFolder = project.ProjectFiles.GetFilesInPath (Path.GetDirectoryName (folder.Path));
+			
+			if (inParentFolder.Length == files.Length) {
+				// This is the last folder in the parent folder. Make sure we keep
+				// a reference to the folder, so it is not deleted from the tree.
+				ProjectFile folderFile = new ProjectFile (Path.GetDirectoryName (folder.Path));
+				folderFile.Subtype = Subtype.Directory;
+				project.ProjectFiles.Add (folderFile);
+			}
+			
+			foreach (ProjectFile file in files)
+				folder.Project.ProjectFiles.Remove (file);
+
+//			folder.Remove ();
+			Runtime.ProjectService.SaveCombine();
 		}
 		
 		public override DragOperation CanDragNode ()
@@ -179,11 +183,12 @@
 		
 		public override bool CanDropNode (object dataObject, DragOperation operation)
 		{
-			return (dataObject is ProjectFile) || (dataObject is ProjectFolder);
+			return base.CanDropNode (dataObject, operation);
 		}
 		
 		public override void OnNodeDrop (object dataObject, DragOperation operation)
 		{
+			base.OnNodeDrop (dataObject, operation);
 		}
 	}
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -41,6 +41,7 @@
 		ProjectFileEventHandler fileRemovedHandler;
 		ProjectFileRenamedEventHandler fileRenamedHandler;
 		CombineEntryRenamedEventHandler projectNameChanged;
+		Hashtable projectsByPath = new Hashtable ();
 		
 		public override Type NodeDataType {
 			get { return typeof(Project); }
@@ -71,17 +72,21 @@
 
 		public override void OnNodeAdded (object dataObject)
 		{
+			base.OnNodeAdded (dataObject);
 			Project project = (Project) dataObject;
 			project.NameChanged += projectNameChanged;
+			projectsByPath.Remove (project.BaseDirectory);
 		}
 		
 		public override void OnNodeRemoved (object dataObject)
 		{
+			base.OnNodeRemoved (dataObject);
 			Project project = (Project) dataObject;
 			project.NameChanged -= projectNameChanged;
+			projectsByPath [project.BaseDirectory] = project;
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((Project)dataObject).Name;
 		}
@@ -97,6 +102,8 @@
 		
 		public override void BuildNode (ITreeBuilder treeBuilder, object dataObject, ref string label, ref Gdk.Pixbuf icon, ref Gdk.Pixbuf closedIcon)
 		{
+			base.BuildNode (treeBuilder, dataObject, ref label, ref icon, ref closedIcon);
+
 			Project p = dataObject as Project;
 			label = p.Name;
 			string iconName = Runtime.Gui.Icons.GetImageForProjectType (p.ProjectType);
@@ -119,25 +126,95 @@
 		
 		void OnAddFile (object sender, ProjectFileEventArgs e)
 		{
-			ITreeBuilder tb = Context.GetTreeBuilder (e.Project);
-			if (tb != null) {
-				if (e.ProjectFile.BuildAction != BuildAction.EmbedAsResource)
-					AddFile (tb, e.Project, e.ProjectFile);
-				else {
-					tb.MoveToChild ("Resources", typeof(ResourceFolder));
-					tb.AddChild (e.ProjectFile);
+			AddFile (e.ProjectFile, e.Project);
+		}
+		
+		void OnRemoveFile (object sender, ProjectFileEventArgs e)
+		{
+			RemoveFile (e.ProjectFile, e.Project);
+		}
+		
+		void AddFile (ProjectFile file, Project project)
+		{
+			ITreeBuilder tb = Context.GetTreeBuilder ();
+			if (file.BuildAction != BuildAction.EmbedAsResource)
+			{
+				string filePath = Path.GetDirectoryName (file.Name);
+				
+				object data;
+				if (file.Subtype == Subtype.Directory)
+					data = new ProjectFolder (file.Name, project);
+				else
+					data = file;
+					
+				// Already there?
+				if (tb.MoveToObject (data))
+					return;
+				
+				if (filePath != project.BaseDirectory) {
+					if (tb.MoveToObject (new ProjectFolder (filePath, project)))
+						tb.AddChild (data);
+					else {
+						// Make sure there is a path to that folder
+						tb = FindParentFolderNode (filePath, project);
+						if (tb != null)
+							tb.UpdateChildren ();
+					}
+				} else {
+					if (tb.MoveToObject (project))
+						tb.AddChild (data);
 				}
 			}
+			else {
+				if (tb.MoveToObject (new ResourceFolder (project)))
+					tb.AddChild (file);
+			}
 		}
 		
-		void OnRemoveFile (object sender, ProjectFileEventArgs e)
+		ITreeBuilder FindParentFolderNode (string path, Project project)
 		{
-			ITreeBuilder tb = Context.GetTreeBuilder (e.ProjectFile);
-			if (tb != null) {
-				if (tb.Options ["ShowAllFiles"] && File.Exists (e.ProjectFile.Name))
-					tb.UpdateAll ();
+			int i = path.LastIndexOf (Path.DirectorySeparatorChar);
+			if (i == -1) return null;
+			
+			string basePath = path.Substring (0, i);
+			
+			if (basePath == project.BaseDirectory)
+				return Context.GetTreeBuilder (project);
+				
+			ITreeBuilder tb = Context.GetTreeBuilder (new ProjectFolder (basePath, project));
+			if (tb != null) return tb;
+			
+			return FindParentFolderNode (basePath, project);
+		}
+		
+		void RemoveFile (ProjectFile file, Project project)
+		{
+			ITreeBuilder tb = Context.GetTreeBuilder ();
+			
+			if (file.Subtype == Subtype.Directory) {
+				if (!tb.MoveToObject (new ProjectFolder (file.Name, project)))
+					return;
+				tb.MoveToParent ();
+				tb.UpdateAll ();
+				return;
+			} else {
+				if (tb.MoveToObject (file)) {
+					tb.Remove (true);
+					if (file.BuildAction == BuildAction.EmbedAsResource)
+						return;
+				} else {
+					string parentPath = Path.GetDirectoryName (file.Name);
+					if (!tb.MoveToObject (new ProjectFolder (parentPath, project)))
+						return;
+				}
+			}
+			
+			while (tb.DataItem is ProjectFolder) {
+				ProjectFolder f = (ProjectFolder) tb.DataItem;
+				if (!Directory.Exists (f.Path) || project.ProjectFiles.GetFilesInPath (f.Path).Length == 0)
+					tb.Remove (true);
 				else
-					tb.Remove ();
+					break;
 			}
 		}
 		
@@ -154,8 +231,13 @@
 		}
 	}
 	
-	public class ProjectNodeCommandHandler: NodeCommandHandler
+	public class ProjectNodeCommandHandler: FolderCommandHandler
 	{
+		public override string GetFolderPath (object dataObject)
+		{
+			return ((Project)dataObject).BaseDirectory;
+		}
+		
 		public override void RenameItem (string newName)
 		{
 			if (newName.IndexOfAny (new char [] { '\'', '(', ')', '"', '{', '}', '|' } ) != -1) {
@@ -191,11 +273,12 @@
 		
 		public override bool CanDropNode (object dataObject, DragOperation operation)
 		{
-			return (dataObject is ProjectFile) || (dataObject is ProjectFolder);
+			return base.CanDropNode (dataObject, operation);
 		}
 		
 		public override void OnNodeDrop (object dataObject, DragOperation operation)
 		{
+			base.OnNodeDrop (dataObject, operation);
 		}
 	}
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceFolderNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -47,7 +47,7 @@
 			get { return typeof(ProjectReferenceFolderNodeCommandHandler); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return "References";
 		}
@@ -90,15 +90,18 @@
 			return ((ProjectReferenceCollection) dataObject).Count > 0;
 		}
 		
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
 			return -1;
 		}
 
 		void OnRemoveReference (object sender, ProjectReferenceEventArgs e)
 		{
-			ITreeBuilder tb = Context.GetTreeBuilder (e.ProjectReference);
-			if (tb != null) tb.Remove ();
+			ITreeBuilder tb = Context.GetTreeBuilder (e.Project);
+			if (tb != null) {
+				if (tb.FindChild (e.ProjectReference, true))
+					tb.Remove ();
+			}
 		}
 		
 		void OnAddReference (object sender, ProjectReferenceEventArgs e)

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -45,7 +45,7 @@
 			get { return typeof(ProjectReferenceNodeCommandHandler); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			return ((ProjectReference)dataObject).Reference;
 		}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -43,5 +43,16 @@
 		public Project Project {
 			get { return project; }
 		}
+		
+		public override bool Equals (object other)
+		{
+			ResourceFolder f = other as ResourceFolder;
+			return f != null && project == f.project;
+		}
+		
+		public override int GetHashCode ()
+		{
+			return project.GetHashCode () + 1;
+		}
 	}
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -41,7 +41,7 @@
 			get { return typeof(ResourceFolder); }
 		}
 		
-		public override string GetNodeName (object dataObject)
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
 		{
 			// Don't localize this string.
 			return "Resources";
@@ -67,9 +67,9 @@
 			return false;
 		}
 
-		public override int CompareObjects (object thisDataObject, object otherDataObject)
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
-			if (otherDataObject is ProjectReferenceCollection)
+			if (otherNode.DataItem is ProjectReferenceCollection)
 				return 1;
 			else
 				return -1;

Added: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -0,0 +1,354 @@
+//
+// ShowAllFilesBuilderExtension.cs
+//
+// Author:
+//   Lluis Sanchez Gual
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+
+using MonoDevelop.Internal.Project;
+using MonoDevelop.Services;
+
+namespace MonoDevelop.Gui.Pads.ProjectPad
+{
+	public class ShowAllFilesBuilderExtension: NodeBuilderExtension
+	{
+		ProjectFileEventHandler fileAddedHandler;
+		ProjectFileEventHandler fileRemovedHandler;
+		
+		FileEventHandler createdHandler;
+		FileEventHandler deletedHandler;
+		FileEventHandler renamedHandler;
+		
+		ArrayList projects = new ArrayList ();
+		
+		public override bool CanBuildNode (Type dataType)
+		{
+			return typeof(ProjectFolder).IsAssignableFrom (dataType) ||
+					typeof(Project).IsAssignableFrom (dataType);
+		}
+		
+		public override Type CommandHandlerType {
+			get { return typeof(ShowAllFilesCommandHandler); }
+		}
+		
+		protected override void Initialize ()
+		{
+			fileAddedHandler = (ProjectFileEventHandler) Runtime.DispatchService.GuiDispatch (new ProjectFileEventHandler (OnAddFile));
+			fileRemovedHandler = (ProjectFileEventHandler) Runtime.DispatchService.GuiDispatch (new ProjectFileEventHandler (OnRemoveFile));
+			
+			createdHandler = (FileEventHandler) Runtime.DispatchService.GuiDispatch (new FileEventHandler (OnSystemFileAdded));
+			deletedHandler = (FileEventHandler) Runtime.DispatchService.GuiDispatch (new FileEventHandler (OnSystemFileDeleted));
+			renamedHandler = (FileEventHandler) Runtime.DispatchService.GuiDispatch (new FileEventHandler (OnSystemFileRenamed));
+			
+			Runtime.ProjectService.FileAddedToProject += fileAddedHandler;
+			Runtime.ProjectService.FileRemovedFromProject += fileRemovedHandler;
+			
+			Runtime.FileService.FileRenamed += renamedHandler;
+			Runtime.FileService.FileRemoved += deletedHandler;
+			Runtime.FileService.FileCreated += createdHandler;
+		}
+		
+		public override void Dispose ()
+		{
+			Runtime.ProjectService.FileAddedToProject -= fileAddedHandler;
+			Runtime.ProjectService.FileRemovedFromProject -= fileRemovedHandler;
+			Runtime.FileService.FileRenamed -= renamedHandler;
+			Runtime.FileService.FileRemoved -= deletedHandler;
+			Runtime.FileService.FileCreated -= createdHandler;
+		}
+
+		public override void OnNodeAdded (object dataObject)
+		{
+			base.OnNodeAdded (dataObject);
+			if (dataObject is Project)
+				projects.Add (dataObject);
+		}
+		
+		public override void OnNodeRemoved (object dataObject)
+		{
+			base.OnNodeRemoved (dataObject);
+			if (dataObject is Project)
+				projects.Remove (dataObject);
+		}
+		
+		internal static string GetFolderPath (object dataObject)
+		{
+			if (dataObject is Project) return ((Project)dataObject).BaseDirectory;
+			else return ((ProjectFolder)dataObject).Path;
+		}
+		
+		public override void BuildNode (ITreeBuilder builder, object dataObject, ref string label, ref Gdk.Pixbuf icon, ref Gdk.Pixbuf closedIcon)
+		{
+			string thisPath = GetFolderPath (dataObject);
+			
+			if ((dataObject is ProjectFolder) && builder.Options ["ShowAllFiles"] && Directory.Exists (thisPath))
+			{
+				ProjectFolder pf = (ProjectFolder) dataObject;
+				if (!HasProjectFiles (pf.Project, thisPath)) {
+					Gdk.Pixbuf gicon = Context.GetComposedIcon (icon, "fade");
+					if (gicon == null) {
+						gicon = Runtime.Gui.Icons.MakeTransparent (icon, 0.5);
+						Context.CacheComposedIcon (icon, "fade", gicon);
+					}
+					icon = gicon;
+					gicon = Context.GetComposedIcon (closedIcon, "fade");
+					if (gicon == null) {
+						gicon = Runtime.Gui.Icons.MakeTransparent (closedIcon, 0.5);
+						Context.CacheComposedIcon (closedIcon, "fade", gicon);
+					}
+					closedIcon = gicon;
+				}
+			}
+		}
+
+		public override void BuildChildNodes (ITreeBuilder builder, object dataObject)
+		{
+			string path = GetFolderPath (dataObject);
+			if (builder.Options ["ShowAllFiles"] && Directory.Exists (path))
+			{
+				Project project = (Project) builder.GetParentDataItem (typeof(Project), true);
+				
+				foreach (string file in Directory.GetFiles (path)) {
+					if (project.ProjectFiles.GetFile (file) == null)
+						builder.AddChild (new SystemFile (file, project));
+				}
+				
+				foreach (string folder in Directory.GetDirectories (path))
+					if (!builder.HasChild (Path.GetFileName (folder), typeof(ProjectFolder)))
+						builder.AddChild (new ProjectFolder (folder, project));
+			}
+		}
+		
+		public override bool HasChildNodes (ITreeBuilder builder, object dataObject)
+		{
+			if (builder.Options ["ShowAllFiles"]) {
+				string path = GetFolderPath (dataObject);
+				return Directory.Exists (path) && (Directory.GetFiles (path).Length > 0 || Directory.GetDirectories (path).Length > 0);
+			}
+			else
+				return false;
+		}
+		
+		void OnAddFile (object sender, ProjectFileEventArgs e)
+		{
+			if (e.ProjectFile.BuildAction != BuildAction.EmbedAsResource) {
+				ITreeBuilder tb = Context.GetTreeBuilder (new SystemFile (e.ProjectFile.Name, e.Project));
+				if (tb != null) tb.Remove (true);
+				Context.Tree.AddNodeInsertCallback (e.ProjectFile, new TreeNodeCallback (UpdateProjectFileParent));
+			}
+		}
+		
+		void UpdateProjectFileParent (ITreeNavigator nav)
+		{
+			ITreeBuilder tb = Context.GetTreeBuilder (nav);
+			tb.MoveToParent ();
+			while (tb.DataItem is ProjectFolder) {
+				tb.Update ();
+				tb.MoveToParent ();
+			}
+		}
+		
+		void OnRemoveFile (object sender, ProjectFileEventArgs e)
+		{
+			if (e.ProjectFile.BuildAction != BuildAction.EmbedAsResource && e.ProjectFile.Subtype != Subtype.Directory) {
+				AddFile (e.ProjectFile.Name, e.Project);
+			}
+		}
+		
+		void AddFile (string file, Project project)
+		{
+			ITreeBuilder tb = Context.GetTreeBuilder ();
+			string filePath = Path.GetDirectoryName (file);
+			
+			object data = new SystemFile (file, project);
+				
+			// Already there?
+			if (tb.MoveToObject (data))
+				return;
+			
+			if (filePath != project.BaseDirectory) {
+				if (tb.MoveToObject (new ProjectFolder (filePath, project))) {
+					if (tb.Filled && tb.Options ["ShowAllFiles"])
+						tb.AddChild (data);
+				} else {
+					// Make sure there is a path to that folder
+					EnsureReachable (project, file);
+				}
+			} else {
+				if (tb.MoveToObject (project) && tb.Options ["ShowAllFiles"])
+					tb.AddChild (data);
+			}
+		}
+		
+		bool RemoveFile (string file, Project project)
+		{
+			ITreeBuilder tb = Context.GetTreeBuilder (new SystemFile (file, project));
+			if (tb != null) {
+				tb.Remove (true);
+				while (tb.DataItem is ProjectFolder) {
+					tb.Update ();
+					tb.MoveToParent ();
+				}
+				return true;
+			}
+			return false;
+		}
+		
+		ITreeBuilder FindParentFolderNode (string path, Project project, out string lastChildPath)
+		{
+			lastChildPath = path;
+			string basePath = Path.GetDirectoryName (path);
+			
+			if (basePath == project.BaseDirectory)
+				return Context.GetTreeBuilder (project);
+				
+			ITreeBuilder tb = Context.GetTreeBuilder (new ProjectFolder (basePath, project));
+			if (tb != null) return tb;
+			
+			return FindParentFolderNode (basePath, project, out lastChildPath);
+		}
+		
+		void OnSystemFileAdded (object sender, FileEventArgs e)
+		{
+			Project project = GetProjectForFile (e.FileName);
+			if (project == null) return;
+			
+			if (e.IsDirectory) {
+				EnsureReachable (project, e.FileName + "/");
+			} else {
+				if (project.ProjectFiles.GetFile (e.FileName) == null)
+					AddFile (e.FileName, project);
+			}
+		}
+		
+		void OnSystemFileDeleted (object sender, FileEventArgs e)
+		{
+			Project project = GetProjectForFile (e.FileName);
+			if (project == null) return;
+			
+			ITreeBuilder tb = Context.GetTreeBuilder ();
+			
+			if (e.IsDirectory) {
+				if (tb.MoveToObject (new ProjectFolder (e.FileName, project))) {
+					if (tb.Options ["ShowAllFiles"] && !HasProjectFiles (project, e.FileName)) {
+						tb.Remove ();
+						return;
+					}
+				}
+			}
+			else {
+				if (tb.MoveToObject (new SystemFile (e.FileName, project))) {
+					tb.Remove ();
+					return;
+				}
+			}
+			
+			// Find the parent folder, and update it's children count
+			
+			string parentPath = Path.GetDirectoryName (e.FileName);
+			if (tb.MoveToObject (new ProjectFolder (parentPath, project))) {
+				if (tb.Options ["ShowAllFiles"] && Directory.Exists (parentPath))
+					tb.UpdateChildren ();
+			}
+		}
+		
+		void OnSystemFileRenamed (object sender, FileEventArgs e)
+		{
+			Project project = GetProjectForFile (e.SourceFile);
+			if (project == null) return;
+			
+			if (e.IsDirectory) {
+/*				string childPath;
+				ITreeBuilder tb = FindParentFolderNode (e.SourceFile, project, out childPath);
+				if (tb != null && tb.Options ["ShowAllFiles"]) {
+					tb.UpdateAll ();
+				}
+*/
+			} else {
+				ITreeBuilder tb = Context.GetTreeBuilder (new SystemFile (e.SourceFile, project));
+				if (tb != null) {
+					tb.Remove (true);
+					tb.AddChild (new SystemFile (e.TargetFile, project));
+				}
+			}
+		}
+		
+		void EnsureReachable (Project project, string path)
+		{
+			string childPath;
+			ITreeBuilder tb = FindParentFolderNode (path, project, out childPath);
+			if (tb != null && childPath != path && tb.Options ["ShowAllFiles"]) {
+				tb.AddChild (new ProjectFolder (childPath, project));
+			}
+		}
+		
+		bool HasProjectFiles (Project project, string path)
+		{
+			string basePath = path + Path.DirectorySeparatorChar;
+			foreach (ProjectFile f in project.ProjectFiles)
+				if (f.Name.StartsWith (basePath))
+					return true;
+			return false;
+		}
+		
+		Project GetProjectForFile (string path)
+		{
+			string baseDir = path + Path.DirectorySeparatorChar;
+			foreach (Project p in projects) {
+				if (baseDir.StartsWith (p.BaseDirectory + Path.DirectorySeparatorChar))
+					return p;
+			}
+			return null;
+		}
+	}
+	
+	public class ShowAllFilesCommandHandler: NodeCommandHandler
+	{
+		public override bool CanDropNode (object dataObject, DragOperation operation)
+		{
+			if (dataObject is SystemFile) {
+				string targetPath = ShowAllFilesBuilderExtension.GetFolderPath (CurrentNode.DataItem);
+				return Path.GetDirectoryName (((SystemFile)dataObject).Path) != targetPath;
+			}
+			return false;
+		}
+		
+		public override void OnNodeDrop (object dataObject, DragOperation operation)
+		{
+			string targetPath = ShowAllFilesBuilderExtension.GetFolderPath (CurrentNode.DataItem);
+			Project targetProject = (Project) CurrentNode.GetParentDataItem (typeof(Project), true);
+			string source = ((SystemFile)dataObject).Path;
+			
+			using (IProgressMonitor monitor = Runtime.TaskService.GetStatusProgressMonitor (GettextCatalog.GetString("Copying files ..."), Stock.CopyIcon, true))
+			{
+				bool move = operation == DragOperation.Move;
+				Runtime.ProjectService.TransferFiles (monitor, null, source, targetProject, targetPath, move, false);
+			}
+		}
+	}
+}

Added: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFile.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFile.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFile.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -0,0 +1,73 @@
+//
+// SystemFile.cs
+//
+// Author:
+//   Lluis Sanchez Gual
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+using MonoDevelop.Internal.Project;
+
+namespace MonoDevelop.Gui.Pads.ProjectPad
+{
+	public class SystemFile
+	{
+		string absolutePath;
+		Project project;
+		
+		public SystemFile (string absolutePath, Project project)
+		{
+			this.project = project;
+			this.absolutePath = absolutePath;
+		}
+		
+		public string Path {
+			get { return absolutePath; }
+		}
+		
+		public string Name {
+			get { return System.IO.Path.GetFileName (absolutePath); }
+		}
+		
+		public Project Project {
+			get { return project; }
+		}
+		
+		public override bool Equals (object other)
+		{
+			SystemFile f = other as SystemFile;
+			return f != null && absolutePath == f.absolutePath && project == f.project;
+		}
+		
+		public override int GetHashCode ()
+		{
+			if (project != null)
+				return (absolutePath + project.Name).GetHashCode ();
+			else
+				return absolutePath.GetHashCode ();
+		}
+	}
+}

Added: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -0,0 +1,130 @@
+//
+// SystemFileNodeBuilder.cs
+//
+// Author:
+//   Lluis Sanchez Gual
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+
+using MonoDevelop.Internal.Project;
+using MonoDevelop.Services;
+
+namespace MonoDevelop.Gui.Pads.ProjectPad
+{
+	public class SystemFileNodeBuilder: TypeNodeBuilder
+	{
+		public override Type NodeDataType {
+			get { return typeof(SystemFile); }
+		}
+		
+		public override Type CommandHandlerType {
+			get { return typeof(SystemFileNodeCommandHandler); }
+		}
+		
+		public override string GetNodeName (ITreeNavigator thisNode, object dataObject)
+		{
+			return Path.GetFileName (((SystemFile)dataObject).Name);
+		}
+		
+		public override string ContextMenuAddinPath {
+			get { return "/SharpDevelop/Views/ProjectBrowser/ContextMenu/SystemFileNode"; }
+		}
+		
+		public override void GetNodeAttributes (ITreeNavigator treeNavigator, object dataObject, ref NodeAttributes attributes)
+		{
+			attributes |= NodeAttributes.AllowRename;
+		}
+		
+		public override void BuildNode (ITreeBuilder treeBuilder, object dataObject, ref string label, ref Gdk.Pixbuf icon, ref Gdk.Pixbuf closedIcon)
+		{
+			SystemFile file = (SystemFile) dataObject;
+			label = file.Name;
+			icon = Context.GetIcon (Runtime.Gui.Icons.GetImageForFile (file.Path));
+			Gdk.Pixbuf gicon = Context.GetComposedIcon (icon, "fade");
+			if (gicon == null) {
+				gicon = Runtime.Gui.Icons.MakeTransparent (icon, 0.5);
+				Context.CacheComposedIcon (icon, "fade", gicon);
+			}
+			icon = gicon;
+		}
+		
+		public override int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
+		{
+			if (otherNode.DataItem is ProjectFolder)
+				return 1;
+			else
+				return DefaultSort;
+		}
+	}
+	
+	public class SystemFileNodeCommandHandler: NodeCommandHandler
+	{
+		public override void RenameItem (string newName)
+		{
+			SystemFile file = CurrentNode.DataItem as SystemFile;
+			string oldname = file.Path;
+
+			string newname = Path.Combine (Path.GetDirectoryName (oldname), newName);
+			if (oldname != newname) {
+				try {
+					if (Runtime.FileUtilityService.IsValidFileName (newname)) {
+						Runtime.FileService.RenameFile (oldname, newname);
+					}
+				} catch (System.IO.IOException) {   // assume duplicate file
+					Runtime.MessageService.ShowError (GettextCatalog.GetString ("File or directory name is already in use, choose a different one."));
+				} catch (System.ArgumentException) { // new file name with wildcard (*, ?) characters in it
+					Runtime.MessageService.ShowError (GettextCatalog.GetString ("The file name you have chosen contains illegal characters. Please choose a different file name."));
+				}
+			}
+		}
+		
+		public override void ActivateItem ()
+		{
+			SystemFile file = CurrentNode.DataItem as SystemFile;
+			Runtime.FileService.OpenFile (file.Path);
+		}
+		
+		public override void RemoveItem ()
+		{
+			SystemFile file = CurrentNode.DataItem as SystemFile;
+			
+			bool yes = Runtime.MessageService.AskQuestion (String.Format (GettextCatalog.GetString ("Are you sure you want to permanently delete the file {0}?"), file.Path));
+			if (!yes) return;
+
+			try {
+				Runtime.FileService.RemoveFile (file.Path);
+			} catch (Exception ex) {
+				Runtime.MessageService.ShowError (string.Format (GettextCatalog.GetString ("The file {0} could not be deleted"), file.Path));
+			}
+		}
+		
+		public override DragOperation CanDragNode ()
+		{
+			return DragOperation.Copy | DragOperation.Move;
+		}
+	}
+}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeBuilderContext.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeBuilderContext.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeBuilderContext.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -34,11 +34,13 @@
 	{
 		ITreeBuilder GetTreeBuilder ();
 		ITreeBuilder GetTreeBuilder (object dataObject);
+		ITreeBuilder GetTreeBuilder (ITreeNavigator navigator);
 		ITreeNavigator GetTreeNavigator (object dataObject);
-		ITreeOptions GetOptions (object dataObject);
 		
 		Gdk.Pixbuf GetIcon (string iconId);
 		Gdk.Pixbuf GetComposedIcon (Gdk.Pixbuf baseIcon, string compositionId);
 		void CacheComposedIcon (Gdk.Pixbuf baseIcon, string compositionId, Gdk.Pixbuf composedIcon);
+		
+		TreeViewPad Tree { get; }
 	}
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeNavigator.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeNavigator.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/ITreeNavigator.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -42,10 +42,12 @@
 		void ExpandToNode ();
 		ITreeOptions Options { get; }
 		
+		NodeState SaveState ();
+		void RestoreState (NodeState state);
+
 		NodePosition CurrentPosition { get; }
 		bool MoveToPosition (NodePosition position);
 		
-		bool MoveToObject (object dataObject);
 		bool MoveToParent ();
 		bool MoveToParent (Type type);
 		bool MoveToRoot ();
@@ -55,6 +57,15 @@
 		bool HasChildren ();
 		bool MoveNext ();
 		
+		// The following methods only look through nodes already created
+		// (the tree is lazily created)
+		bool MoveToObject (object dataObject);
+		bool FindChild (object dataObject);
+		bool FindChild (object dataObject, bool recursive);
+		
+		// True if the node has been filled with child data.
+		bool Filled { get; }
+		
 		ITreeNavigator Clone ();
 	}
 	

Added: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/NodeState.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/NodeState.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/NodeState.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -0,0 +1,164 @@
+//
+// NodeState.cs
+//
+// Author:
+//   Lluis Sanchez Gual
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Xml;
+
+namespace MonoDevelop.Gui.Pads
+{
+	public class NodeState
+	{
+		string NodeName;
+		bool Expanded;
+		TreeViewPad.TreeOptions Options;
+		ArrayList ChildrenState;
+		
+		public XmlElement ToXml (XmlDocument doc)
+		{
+			return ToXml (doc, null);
+		}
+		
+		public static NodeState FromXml (XmlElement elem)
+		{
+			return FromXml (elem, null);
+		}
+		
+		XmlElement ToXml (XmlDocument doc, TreeViewPad.TreeOptions parentOptions)
+		{
+			XmlElement el = doc.CreateElement ("Node");
+			if (NodeName != null)
+				el.SetAttribute ("name", NodeName);
+			el.SetAttribute ("expanded", Expanded.ToString ());
+			
+			TreeViewPad.TreeOptions ops = Options;
+			if (ops != null) {
+				foreach (DictionaryEntry de in ops) {
+					object parentVal = parentOptions != null ? parentOptions [de.Key] : null;
+					if (parentVal != null && !parentVal.Equals (de.Value) || (parentVal == null && de.Value != null) || parentOptions == null) {
+						XmlElement eop = doc.CreateElement ("Option");
+						eop.SetAttribute ("id", de.Key.ToString());
+						eop.SetAttribute ("value", de.Value.ToString ());
+						el.AppendChild (eop);
+					}
+				}
+			}
+			
+			if (ChildrenState == null) return el;
+			foreach (NodeState ces in ChildrenState) {
+				XmlElement child = ces.ToXml (doc, ops != null ? ops : parentOptions);
+				el.AppendChild (child);
+			}
+			
+			return el;
+		}
+
+		static NodeState FromXml (XmlElement elem, TreeViewPad.TreeOptions parentOptions)
+		{
+			NodeState ns = new NodeState ();
+			ns.NodeName = elem.GetAttribute ("name");
+			string expanded = elem.GetAttribute ("expanded");
+			ns.Expanded = (expanded == "" || bool.Parse (expanded));
+			
+			XmlNodeList nodelist = elem.ChildNodes;
+			foreach (XmlNode nod in nodelist) {
+				XmlElement el = nod as XmlElement;
+				if (el == null) continue;
+				if (el.LocalName == "Option") {
+					if (ns.Options == null) {
+						if (parentOptions != null) ns.Options = parentOptions.CloneOptions (Gtk.TreeIter.Zero);
+						else ns.Options = new TreeViewPad.TreeOptions ();
+					}
+					ns.Options [el.GetAttribute ("id")] = bool.Parse (el.GetAttribute ("value"));
+				}
+				else if (el.LocalName == "Node") {
+					if (ns.ChildrenState == null) ns.ChildrenState = new ArrayList ();
+					ns.ChildrenState.Add (FromXml (el, ns.Options != null ? ns.Options : parentOptions));
+				}
+			}
+			return ns;
+		}
+		
+		internal static NodeState SaveState (TreeViewPad pad, ITreeNavigator nav)
+		{
+			NodeState state = SaveStateRec (pad, nav);
+			if (state == null) return new NodeState ();
+			else return state;
+		}
+		
+		static NodeState SaveStateRec (TreeViewPad pad, ITreeNavigator nav)
+		{
+			Gtk.TreeIter it = nav.CurrentPosition._iter;
+			
+			ArrayList childrenState = null;
+
+			if (nav.Filled && nav.MoveToFirstChild ()) {
+				do {
+					NodeState cs = SaveStateRec (pad, nav);
+					if (cs != null) {
+						cs.NodeName = nav.NodeName;
+						if (childrenState == null) childrenState = new ArrayList ();
+						childrenState.Add (cs);
+					}
+				} while (nav.MoveNext ());
+				nav.MoveToParent ();
+			}
+			
+			TreeViewPad.TreeOptions ops = pad.GetIterOptions (it);
+			if (ops != null || nav.Expanded || childrenState != null) {
+				NodeState es = new NodeState ();
+				es.Expanded = nav.Expanded;
+				es.Options = ops;
+				es.ChildrenState = childrenState;
+				return es;
+			} else
+				return null;
+		}
+		
+		internal static void RestoreState (TreeViewPad pad, ITreeNavigator nav, NodeState es)
+		{
+			if (es == null) return;
+
+			Gtk.TreeIter it = nav.CurrentPosition._iter;
+			if (es.Options != null) {
+				pad.SetIterOptions (it, es.Options);
+			}
+			pad.ResetState (it);
+			nav.Expanded = es.Expanded;
+			
+			if (es.ChildrenState == null) return;
+			
+			foreach (NodeState ces in es.ChildrenState) {
+				if (nav.MoveToChild (ces.NodeName, null)) {
+					RestoreState (pad, nav, ces);
+					nav.MoveToParent ();
+				}
+			}
+		}
+	}
+}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TreeViewPad.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TreeViewPad.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TreeViewPad.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -81,7 +81,13 @@
 		TreeOptions globalOptions;
 		Hashtable nodeOptions = new Hashtable ();
 		
+		TreeNodeNavigator workNode;
+		TreeNodeNavigator compareNode1;
+		TreeNodeNavigator compareNode2;
+		
 		object dragObject;
+		object copyObject;
+		DragOperation currentTransferOperation;
 
 		Gtk.Frame contentPanel = new Gtk.Frame();
 
@@ -171,10 +177,8 @@
 			store = new Gtk.TreeStore (typeof (string), typeof (Gdk.Pixbuf), typeof (Gdk.Pixbuf), typeof (object), typeof (object), typeof(int), typeof(bool));
 			tree.Model = store;
 
-/*
-			tree.EnableModelDragSource (Gdk.ModifierType.Button1Mask, target_table, Gdk.DragAction.Copy | Gdk.DragAction.Move);
 			tree.EnableModelDragDest (target_table, Gdk.DragAction.Copy | Gdk.DragAction.Move);
-*/
+			Gtk.Drag.SourceSet (tree, Gdk.ModifierType.Button1Mask, target_table, Gdk.DragAction.Copy | Gdk.DragAction.Move);
 
 			store.SetDefaultSortFunc (new Gtk.TreeIterCompareFunc (CompareNodes), IntPtr.Zero, null);
 			store.SetSortColumnId (/* GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID */ -1, Gtk.SortType.Ascending);
@@ -214,74 +218,64 @@
 			foreach (NodeBuilder nb in builders)
 				nb.SetContext (builderContext);
 			
-/*			tree.DragBegin += new Gtk.DragBeginHandler (OnDragBegin);
-			tree.DragDataGet += new Gtk.DragDataGetHandler (OnDragDataGet);
+			workNode = new TreeNodeNavigator (this);
+			compareNode1 = new TreeNodeNavigator (this);
+			compareNode2 = new TreeNodeNavigator (this);
+			
+			tree.DragBegin += new Gtk.DragBeginHandler (OnDragBegin);
 			tree.DragDataReceived += new Gtk.DragDataReceivedHandler (OnDragDataReceived);
 			tree.DragDrop += new Gtk.DragDropHandler (OnDragDrop);
 			tree.DragEnd += new Gtk.DragEndHandler (OnDragEnd);
-			tree.DragLeave += new Gtk.DragLeaveHandler (OnDragLeave);
 			tree.DragMotion += new Gtk.DragMotionHandler (OnDragMotion);
-*/
 		}
 
-/*
+
 		void OnDragBegin (object o, Gtk.DragBeginArgs arg)
 		{
 			ITreeNavigator nav = GetSelectedNode ();
+			if (nav == null) return;
 			dragObject = nav.DataItem;
-			Runtime.LoggingService.Info ("OnDragBegin");
+			Gdk.Pixbuf px = (Gdk.Pixbuf) store.GetValue (nav.CurrentPosition._iter, OpenIconColumn);
+			Gtk.Drag.SetIconPixbuf (arg.Context, px, -10, -10);
 		}
 		
-		void OnDragDataGet (object o, Gtk.DragDataGetArgs args)
-		{
-			Runtime.LoggingService.Info ("OnDragDataGet");
-			args.SelectionData.Set (args.Context.Targets[0], 0, new byte[0]);
-		}
-		
 		void OnDragDataReceived (object o, Gtk.DragDataReceivedArgs args)
 		{
-			Runtime.LoggingService.Info ("OnDragDataReceived " + args.X + " " + args.Y + " " + args.SelectionData.Length);
-			
 			if (dragObject != null) {
-				bool res = CheckAndDrop (args.X, args.Y, true);
+				bool res = CheckAndDrop (args.X, args.Y, true, args.Context, dragObject);
 				Gtk.Drag.Finish (args.Context, res, true, args.Time);
 			} else {
-				if (args.SelectionData.Data.Length > 0) {
-					string fullData = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
-					Runtime.LoggingService.Info ("file:" + fullData);
-				}
-				Gtk.Drag.Finish (args.Context, false, true, args.Time);
+				bool res = CheckAndDrop (args.X, args.Y, true, args.Context, args.SelectionData);
+//				string fullData = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
+				Gtk.Drag.Finish (args.Context, res, true, args.Time);
 			}
 		}
 		
 		void OnDragDrop (object o, Gtk.DragDropArgs args)
 		{
-			Runtime.LoggingService.Info ("OnDragDrop " + args.X + " " + args.Y);
+			if (dragObject != null) {
+				bool res = CheckAndDrop (args.X, args.Y, true, args.Context, dragObject);
+				Gtk.Drag.Finish (args.Context, res, true, args.Time);
+			}
 		}
 		
 		void OnDragEnd (object o, Gtk.DragEndArgs args)
 		{
 			dragObject = null;
-			Runtime.LoggingService.Info ("OnDragEnd");
 		}
 		
-		void OnDragLeave (object sender, Gtk.DragLeaveArgs args)
-		{
-			Runtime.LoggingService.Info ("OnDragLeave");
-		}
-		
 		[GLib.ConnectBefore]
 		void OnDragMotion (object o, Gtk.DragMotionArgs args)
 		{
 			if (dragObject != null) {
-				if (!CheckAndDrop (args.X, args.Y, false)) {
+				if (!CheckAndDrop (args.X, args.Y, false, args.Context, dragObject)) {
 					Gdk.Drag.Status (args.Context, (Gdk.DragAction)0, args.Time);
 					args.RetVal = true;
 				}
 			}
 		}
 		
-		bool CheckAndDrop (int x, int y, bool drop)
+		bool CheckAndDrop (int x, int y, bool drop, Gdk.DragContext ctx, object obj)
 		{
 			Gtk.TreePath path;
 			Gtk.TreeViewDropPosition pos;
@@ -291,24 +285,23 @@
 			if (!store.GetIter (out iter, path)) return false;
 			
 			TreeNodeNavigator nav = new TreeNodeNavigator (this, iter);
-			Runtime.LoggingService.Info ("Trying drop to " + nav.NodeName);
 			NodeBuilder[] chain = nav.BuilderChain;
 			bool foundHandler = false;
 			
+			DragOperation oper = ctx.Action == Gdk.DragAction.Copy ? DragOperation.Copy : DragOperation.Move;
+			
 			foreach (NodeBuilder nb in chain) {
 				nb.CommandHandler.SetCurrentNode (nav);
-				if (nb.CommandHandler.CanDropNode (dragObject, DragOperation.Copy)) {
+				if (nb.CommandHandler.CanDropNode (obj, oper)) {
 					foundHandler = true;
-					if (drop) {
-						Runtime.LoggingService.Info ("Droping to " + nb);
-						nb.CommandHandler.OnNodeDrop (dragObject, DragOperation.Copy);
-					}
+					if (drop)
+						nb.CommandHandler.OnNodeDrop (obj, oper);
 				}
 			}
 			return foundHandler;
 		}
-*/
 
+
 		public virtual void Dispose ()
 		{
 			Clear ();
@@ -331,13 +324,19 @@
 		
 		protected void Clear ()
 		{
+			copyObject = dragObject = null;
+			
 			object[] obs = new object [nodeHash.Count];
 			nodeHash.Keys.CopyTo (obs, 0);
 			
-			foreach (object dataObject in obs)
-				UnregisterNode (dataObject, null);
+			foreach (object dataObject in obs) {
+				NodeBuilder[] chain = GetBuilderChain (dataObject.GetType());
+				foreach (NodeBuilder nb in chain)
+					nb.OnNodeRemoved (dataObject);
+			}
 
 			nodeHash = new Hashtable ();
+			nodeOptions = new Hashtable ();
 			store.Clear ();
 		}
 		
@@ -360,7 +359,10 @@
 		{
 			object it = nodeHash [dataObject];
 			if (it == null) return null;
-			return new TreeNodeNavigator (this, (Gtk.TreeIter)it);
+			if (it is Gtk.TreeIter[])
+				return new TreeNodeNavigator (this, ((Gtk.TreeIter[])it)[0]);
+			else
+				return new TreeNodeNavigator (this, (Gtk.TreeIter)it);
 		}
 		
 		public ITreeNavigator GetRootNode ()
@@ -389,10 +391,9 @@
 		
 		public void ActivateCurrentItem ()
 		{
-			ITreeNavigator node = GetSelectedNode ();
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
 			if (node != null) {
-				object data = node.DataItem;
-				NodeBuilder[] chain = GetBuilderChain (data.GetType ());
+				NodeBuilder[] chain = node.NodeBuilderChain;
 				NodePosition pos = node.CurrentPosition;
 				foreach (NodeBuilder b in chain) {
 					b.CommandHandler.SetCurrentNode (node);
@@ -404,10 +405,9 @@
 
 		public void RemoveCurrentItem ()
 		{
-			ITreeNavigator node = GetSelectedNode ();
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
 			if (node != null) {
-				object data = node.DataItem;
-				NodeBuilder[] chain = GetBuilderChain (data.GetType ());
+				NodeBuilder[] chain = node.NodeBuilderChain;
 				NodePosition pos = node.CurrentPosition;
 				foreach (NodeBuilder b in chain) {
 					b.CommandHandler.SetCurrentNode (node);
@@ -417,6 +417,120 @@
 			}
 		}
 
+		public void CopyCurrentItem ()
+		{
+			CancelTransfer ();
+			TransferCurrentItem (DragOperation.Copy);
+		}
+
+		public void CutCurrentItem ()
+		{
+			CancelTransfer ();
+			TransferCurrentItem (DragOperation.Move);
+			
+			if (copyObject != null) {
+				TreeBuilder tb = new TreeBuilder (this);
+				if (tb.MoveToObject (copyObject))
+					tb.Update ();
+			}
+		}
+		
+		public bool CanCopyCurrentItem ()
+		{
+			return CanTransferCurrentItem (DragOperation.Copy);
+		}
+
+		public bool CanCutCurrentItem ()
+		{
+			return CanTransferCurrentItem (DragOperation.Move);
+		}
+		
+		void TransferCurrentItem (DragOperation oper)
+		{
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
+			if (node != null) {
+				NodeBuilder[] chain = node.NodeBuilderChain;
+				NodePosition pos = node.CurrentPosition;
+				foreach (NodeBuilder b in chain) {
+					b.CommandHandler.SetCurrentNode (node);
+					if ((b.CommandHandler.CanDragNode () & oper) != 0) {
+						node.MoveToPosition (pos);
+						copyObject = node.DataItem;
+						currentTransferOperation = oper;
+						break;
+					}
+					node.MoveToPosition (pos);
+				}
+			}
+		}
+		
+		bool CanTransferCurrentItem (DragOperation oper)
+		{
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
+			if (node != null) {
+				NodeBuilder[] chain = node.NodeBuilderChain;
+				NodePosition pos = node.CurrentPosition;
+				foreach (NodeBuilder b in chain) {
+					b.CommandHandler.SetCurrentNode (node);
+					if ((b.CommandHandler.CanDragNode () & oper) != 0)
+						return true;
+					node.MoveToPosition (pos);
+				}
+			}
+			return false;
+		}
+		
+		public void PasteToCurrentItem ()
+		{
+			if (copyObject == null) return;
+			
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
+			if (node != null) {
+				NodeBuilder[] chain = node.NodeBuilderChain;
+				NodePosition pos = node.CurrentPosition;
+				foreach (NodeBuilder b in chain) {
+					b.CommandHandler.SetCurrentNode (node);
+					if (b.CommandHandler.CanDropNode (copyObject, currentTransferOperation)) {
+						node.MoveToPosition (pos);
+						b.CommandHandler.OnNodeDrop (copyObject, currentTransferOperation);
+					}
+					node.MoveToPosition (pos);
+				}
+			}
+			CancelTransfer ();
+		}
+
+		public bool CanPasteToCurrentItem ()
+		{
+			if (copyObject == null) return false;
+			
+			TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
+			if (node != null) {
+				NodeBuilder[] chain = node.NodeBuilderChain;
+				NodePosition pos = node.CurrentPosition;
+				foreach (NodeBuilder b in chain) {
+					b.CommandHandler.SetCurrentNode (node);
+					if (b.CommandHandler.CanDropNode (copyObject, currentTransferOperation))
+						return true;
+					node.MoveToPosition (pos);
+				}
+			}
+			return false;
+		}
+
+		void CancelTransfer ()
+		{
+			if (copyObject != null) {
+				object oldCopyObject = copyObject;
+				copyObject = null;
+				if (currentTransferOperation == DragOperation.Move) {
+					TreeBuilder tb = new TreeBuilder (this);
+					if (tb.MoveToObject (oldCopyObject))
+						tb.Update ();
+				}
+			}
+		}
+
 		/// <summary>
 		/// If you want to edit a node label. Select the node you want to edit and then
 		/// call this method, instead of using the LabelEdit Property and the BeginEdit
@@ -429,11 +543,9 @@
 			if (!tree.Selection.GetSelected (out foo, out iter))
 				return;
 			
-			object data = store.GetValue (iter, TreeViewPad.DataItemColumn);
+			workNode.MoveToIter (iter);
+			store.SetValue (iter, TreeViewPad.TextColumn, workNode.NodeName);
 			
-			TypeNodeBuilder nb = GetTypeNodeBuilder (data.GetType ());
-			store.SetValue (iter, TreeViewPad.TextColumn, nb.GetNodeName (data));
-			
 			text_render.Editable = true;
 			tree.SetCursor (store.GetPath (iter), complete_column, true);
 		}
@@ -462,86 +574,22 @@
 		
 		public void SaveTreeState (XmlElement el)
 		{
-			Gtk.TreeIter iter;
-			if (!store.GetIterFirst (out iter)) return;
-			XmlElement child = SaveTree (el.OwnerDocument, globalOptions, new TreeNodeNavigator (this, iter));
-			if (child != null) el.AppendChild (child);
-		}
-		
-		XmlElement SaveTree (XmlDocument doc, ITreeOptions parentOptions, TreeNodeNavigator nav)
-		{
-			XmlElement el = null;
-			ITreeOptions ops = nodeOptions [nav.DataItem] as ITreeOptions;
-			
-			if (nav.Expanded || ops != null) {
-				el = doc.CreateElement ("Node");
-				if (ops != null) {
-					foreach (TreePadOption op in options) {
-						if (parentOptions [op.Id] != ops [op.Id]) {
-							XmlElement eop = doc.CreateElement ("Option");
-							eop.SetAttribute ("id", op.Id);
-							eop.SetAttribute ("value", ops [op.Id].ToString ());
-							el.AppendChild (eop);
-						}
-					}
-				}
-			}
-			
-			if (!nav.Filled || !nav.MoveToFirstChild ())
-				return el;
+			ITreeNavigator root = GetRootNode ();
+			if (root == null) return;
 
-			do {
-				XmlElement child = SaveTree (doc, ops != null ? ops : parentOptions, nav);
-				if (child != null) {
-					if (el == null) el = doc.CreateElement ("Node");
-					el.AppendChild (child);
-				}
-			} while (nav.MoveNext ());
-			
-			nav.MoveToParent ();
-			
-			if (el != null) {
-				el.SetAttribute ("name", nav.NodeName);
-				el.SetAttribute ("expanded", nav.Expanded.ToString ());
-			}
-			return el;
+			NodeState state = root.SaveState ();
+			XmlElement child = state.ToXml (el.OwnerDocument);
+			el.AppendChild (child);
 		}
 		
 		public void RestoreTreeState (XmlElement parent)
 		{
 			ITreeNavigator nav = GetRootNode ();
-			if (nav != null)
-				RestoreTree (parent, nav);
+			XmlElement rootNode = parent ["Node"];
+			NodeState state = NodeState.FromXml (rootNode);
+			nav.RestoreState (state);
 		}
 		
-		void RestoreTree (XmlElement parent, ITreeNavigator nav)
-		{
-			XmlNodeList nodelist = parent.ChildNodes;
-			foreach (XmlNode nod in nodelist) {
-				XmlElement el = nod as XmlElement;
-				if (el == null) continue;
-				if (el.LocalName == "Option") {
-					nav.Options [el.GetAttribute ("id")] = bool.Parse (el.GetAttribute ("value"));
-				}
-			}
-
-			string expanded = parent.GetAttribute ("expanded");
-			if (expanded == "" || bool.Parse (expanded))
-				nav.Expanded = true;
-				
-			foreach (XmlNode nod in nodelist) {
-				XmlElement el = nod as XmlElement;
-				if (el == null) continue;
-				if (el.LocalName == "Node") {
-					string name = el.GetAttribute ("name");
-					if (nav.MoveToChild (name, null)) {
-						RestoreTree (el, nav);
-						nav.MoveToParent ();
-					}
-				}
-			}
-		}
-		
 		NodeBuilder[] GetBuilderChain (Type type)
 		{
 			NodeBuilder[] chain = builderChains [type] as NodeBuilder[];
@@ -567,9 +615,9 @@
 			return chain;
 		}
 		
-		TypeNodeBuilder GetTypeNodeBuilder (Type type)
+		TypeNodeBuilder GetTypeNodeBuilder (Gtk.TreeIter iter)
 		{
-			NodeBuilder[] chain = GetBuilderChain (type);
+			NodeBuilder[] chain = (NodeBuilder[]) store.GetValue (iter, TreeViewPad.BuilderChainColumn);
 			if (chain != null && chain.Length > 0)
 				return chain[0] as TypeNodeBuilder;
 			return null;
@@ -577,45 +625,92 @@
 		
 		int CompareNodes (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b)
 		{
-			object o1 = store.GetValue (a, DataItemColumn);
-			object o2 = store.GetValue (b, DataItemColumn);
-			
 			NodeBuilder[] chain1 = (NodeBuilder[]) store.GetValue (a, BuilderChainColumn);
 			if (chain1 == null) return 0;
 			
+			compareNode1.MoveToIter (a);
+			compareNode2.MoveToIter (b);
+
 			TypeNodeBuilder tb1 = (TypeNodeBuilder) chain1[0];
-			int sort = tb1.CompareObjects (o1, o2);
+			int sort = tb1.CompareObjects (compareNode1, compareNode2);
 			if (sort != TypeNodeBuilder.DefaultSort) return sort;
 			
 			NodeBuilder[] chain2 = (NodeBuilder[]) store.GetValue (b, BuilderChainColumn);
 			if (chain2 == null) return 0;
 			
-			if (chain1 == chain2)
-				return string.Compare (tb1.GetNodeName (o1), tb1.GetNodeName (o2), true);
-				
 			TypeNodeBuilder tb2 = (TypeNodeBuilder) chain2[0];
-			sort = tb2.CompareObjects (o2, o1);
-			if (sort != TypeNodeBuilder.DefaultSort) return sort * -1;
-
-			return string.Compare (tb1.GetNodeName (o1), tb2.GetNodeName (o2), true);
+			
+			if (chain1 != chain2) {
+				sort = tb2.CompareObjects (compareNode2, compareNode1);
+				if (sort != TypeNodeBuilder.DefaultSort) return sort * -1;
+			}
+			
+			object o1 = store.GetValue (a, DataItemColumn);
+			object o2 = store.GetValue (b, DataItemColumn);
+			return string.Compare (tb1.GetNodeName (compareNode1, o1), tb2.GetNodeName (compareNode2, o2), true);
 		}
 		
+		internal bool GetFirstNode (object dataObject, out Gtk.TreeIter iter)
+		{
+			object it = nodeHash [dataObject];
+			if (it == null) {
+				iter = Gtk.TreeIter.Zero;
+				return false;
+			}
+			else if (it is Gtk.TreeIter)
+				iter = (Gtk.TreeIter) it;
+			else
+				iter = ((Gtk.TreeIter[])it)[0];
+			return true;
+		}
+		
 		internal void RegisterNode (Gtk.TreeIter it, object dataObject, NodeBuilder[] chain)
 		{
-			nodeHash [dataObject] = it;
-
-			if (chain == null) chain = GetBuilderChain (dataObject.GetType());
-			foreach (NodeBuilder nb in chain)
-				nb.OnNodeAdded (dataObject);
+			object currentIt = nodeHash [dataObject];
+			if (currentIt == null) {
+				nodeHash [dataObject] = it;
+				if (chain == null) chain = GetBuilderChain (dataObject.GetType());
+				foreach (NodeBuilder nb in chain)
+					nb.OnNodeAdded (dataObject);
+			} else {
+				if (currentIt is Gtk.TreeIter[]) {
+					Gtk.TreeIter[] arr = (Gtk.TreeIter[]) currentIt;
+					Gtk.TreeIter[] newArr = new Gtk.TreeIter [arr.Length + 1];
+					arr.CopyTo (newArr, 0);
+					newArr [arr.Length] = it;
+					nodeHash [dataObject] = newArr;
+				} else {
+					nodeHash [dataObject] = new Gtk.TreeIter [] { it, (Gtk.TreeIter) currentIt};
+				}
+			}
 		}
 		
-		internal void UnregisterNode (object dataObject, NodeBuilder[] chain)
+		internal void UnregisterNode (object dataObject, Gtk.TreeIter iter, NodeBuilder[] chain)
 		{
-			nodeOptions.Remove (dataObject);
-			nodeHash.Remove (dataObject);
-			if (chain == null) chain = GetBuilderChain (dataObject.GetType());
-			foreach (NodeBuilder nb in chain)
-				nb.OnNodeRemoved (dataObject);
+			if (dataObject == copyObject)
+				copyObject = null;
+				
+			nodeOptions.Remove (iter);
+			object currentIt = nodeHash [dataObject];
+			if (currentIt is Gtk.TreeIter[]) {
+				Gtk.TreeIter[] arr = (Gtk.TreeIter[]) currentIt;
+				int i = Array.IndexOf (arr, iter);
+				if (arr.Length > 2) {
+					Gtk.TreeIter[] newArr = new Gtk.TreeIter[arr.Length - 1];
+					Array.Copy (arr, 0, newArr, 0, i);
+					if (i < newArr.Length)
+						Array.Copy (arr, i+1, newArr, i, arr.Length - i - 1);
+					nodeHash [dataObject] = newArr;
+				} else {
+					if (i == 0) nodeHash [dataObject] = arr[1];
+					else nodeHash [dataObject] = arr[0];
+				}
+			} else {
+				nodeHash.Remove (dataObject);
+				if (chain == null) chain = GetBuilderChain (dataObject.GetType());
+				foreach (NodeBuilder nb in chain)
+					nb.OnNodeRemoved (dataObject);
+			}
 		}
 		
 		internal bool IsRegistered (object dataObject)
@@ -643,9 +738,8 @@
 		{
 			if (nodeOptions.Count == 0) {
 				if (createSpecificOptions) {
-					object dataObject = store.GetValue (iter, DataItemColumn);
-					TreeOptions ops = globalOptions.CloneOptions (dataObject);
-					nodeOptions [dataObject] = ops;
+					TreeOptions ops = globalOptions.CloneOptions (iter);
+					nodeOptions [iter] = ops;
 					return ops;
 				}
 				else
@@ -655,19 +749,15 @@
 			TreeOptions result = null;
 			Gtk.TreeIter it = iter;
 			do {
-				if (store.GetValue (it, BuilderChainColumn) != null) {
-					object ob = store.GetValue (it, DataItemColumn);
-					result = nodeOptions [ob] as TreeOptions;
-				}
+				result = nodeOptions [it] as TreeOptions;
 			} while (result == null && store.IterParent (out it, it));
 
 			if (result == null)
 				result = globalOptions;
 			
 			if (createSpecificOptions && !it.Equals (iter)) {
-				object dataObject = store.GetValue (iter, DataItemColumn);
-				TreeOptions ops = result.CloneOptions (dataObject);
-				nodeOptions [dataObject] = ops;
+				TreeOptions ops = result.CloneOptions (iter);
+				nodeOptions [iter] = ops;
 				return ops;
 			} else
 				return result;
@@ -681,50 +771,55 @@
 			ArrayList toDelete = new ArrayList ();
 			string path = store.GetPath (iter).ToString () + ":";
 			
-			foreach (object ob in nodeOptions.Keys) {
-				Gtk.TreeIter nit = (Gtk.TreeIter) nodeHash [ob];
+			foreach (Gtk.TreeIter nit in nodeOptions.Keys) {
 				string npath = store.GetPath (nit).ToString () + ":";
 				if (npath.StartsWith (path))
-					toDelete.Add (ob);
+					toDelete.Add (nit);
 			}
 
 			foreach (object ob in toDelete)
 				nodeOptions.Remove (ob);
 		}
+		
+		internal TreeOptions GetIterOptions (Gtk.TreeIter iter)
+		{
+			return nodeOptions [iter] as TreeOptions;
+		}
 
+		internal void SetIterOptions (Gtk.TreeIter iter, TreeOptions ops)
+		{
+			ops.Pad = this;
+			ops.Iter = iter;
+			nodeOptions [iter] = ops;
+		}
+
 		internal string GetNamePathFromIter (Gtk.TreeIter iter)
 		{
+			workNode.MoveToIter (iter);
 			StringBuilder sb = new StringBuilder ();
 			do {
-				NodeBuilder[] chain = (NodeBuilder[]) store.GetValue (iter, BuilderChainColumn);
-				string name;
-				if (chain == null)
-					name = (string) store.GetValue (iter, TextColumn);
-				else {
-					object ob = store.GetValue (iter, DataItemColumn);
-					name = ((TypeNodeBuilder)chain[0]).GetNodeName (ob);
-				}
+				string name = workNode.NodeName;
 				if (sb.Length > 0) sb.Insert (0, '/');
 				name = name.Replace ("%","%%");
 				name = name.Replace ("/","_%_");
 				sb.Insert (0, name);
-			} while (store.IterParent (out iter, iter));
+			} while (workNode.MoveToParent ());
 
 			return sb.ToString ();
 		}
 		
-		internal void RefreshNode (object dataObject)
+		internal void RefreshNode (Gtk.TreeIter iter)
 		{
-			ITreeBuilder builder = new TreeBuilder (this);
-			bool found;
-			
-			if (dataObject != null) found = builder.MoveToObject (dataObject);
-			else found = builder.MoveToRoot ();
-			
-			if (found)
-				builder.UpdateAll ();
+			ITreeBuilder builder = new TreeBuilder (this, iter);
+			builder.UpdateAll ();
 		}
 		
+		internal void ResetState (Gtk.TreeIter iter)
+		{
+			TreeBuilder builder = new TreeBuilder (this, iter);
+			builder.ResetState ();
+		}
+		
 		internal bool GetIterFromNamePath (string path, out Gtk.TreeIter iter)
 		{
 			if (!store.GetIterFirst (out iter))
@@ -777,10 +872,10 @@
 			Runtime.ProjectService.CurrentSelectedProject = tnav.GetParentDataItem (typeof(Project), true) as Project;
 			Runtime.ProjectService.CurrentSelectedCombine = tnav.GetParentDataItem (typeof(Combine), true) as Combine;
 			
-			TypeNodeBuilder nb = GetTypeNodeBuilder (tnav.DataItem.GetType ());
+			TypeNodeBuilder nb = GetTypeNodeBuilder (tnav.CurrentPosition._iter);
 			if (nb == null || nb.ContextMenuAddinPath == null) {
 				if (options.Length > 0)
-					Runtime.Gui.Menus.ShowContextMenu (BuildTreeOptionsMenu (tnav.DataItem));
+					Runtime.Gui.Menus.ShowContextMenu (BuildTreeOptionsMenu (tnav));
 			} else {
 				Gtk.Menu menu = Runtime.Gui.Menus.CreateContextMenu (this, nb.ContextMenuAddinPath);
 				if (options.Length > 0) {
@@ -790,16 +885,16 @@
 					
 					mi = new Gtk.MenuItem (GettextCatalog.GetString ("Display Options"));
 					menu.Append (mi);
-					mi.Submenu = BuildTreeOptionsMenu (tnav.DataItem);
+					mi.Submenu = BuildTreeOptionsMenu (tnav);
 					mi.Show ();
 				}
 				Runtime.Gui.Menus.ShowContextMenu (menu);
 			}
 		}
 		
-		Gtk.Menu BuildTreeOptionsMenu (object dataObject)
+		Gtk.Menu BuildTreeOptionsMenu (ITreeNavigator tnav)
 		{
-			ITreeOptions currentOptions = builderContext.GetOptions (dataObject);
+			ITreeOptions currentOptions = tnav.Options;
 			Gtk.Menu omenu = new Gtk.Menu ();
 
 			foreach (TreePadOption op in options) {
@@ -911,17 +1006,24 @@
 			public ITreeBuilder GetTreeBuilder ()
 			{
 				Gtk.TreeIter iter;
-				if (!pad.store.GetIterFirst (out iter)) return null;
-				return new TreeBuilder (pad, iter);
+				if (!pad.store.GetIterFirst (out iter))
+					return new TreeBuilder (pad, Gtk.TreeIter.Zero);
+				else
+					return new TreeBuilder (pad, iter);
 			}
 			
 			public ITreeBuilder GetTreeBuilder (object dataObject)
 			{
-				object pos = pad.nodeHash [dataObject];
-				if (pos == null) return null;
-				return new TreeBuilder (pad, (Gtk.TreeIter) pos);
+				Gtk.TreeIter iter;
+				if (!pad.GetFirstNode (dataObject, out iter)) return null;
+				return new TreeBuilder (pad, iter);
 			}
 			
+			public ITreeBuilder GetTreeBuilder (ITreeNavigator navigator)
+			{
+				return new TreeBuilder (pad, navigator.CurrentPosition._iter);
+			}
+		
 			public Gdk.Pixbuf GetIcon (string id)
 			{
 				Gdk.Pixbuf icon = icons [id] as Gdk.Pixbuf;
@@ -951,20 +1053,17 @@
 			
 			public ITreeNavigator GetTreeNavigator (object dataObject)
 			{
-				object pos = pad.nodeHash [dataObject];
-				if (pos == null) return null;
-				return new TreeNodeNavigator (pad, (Gtk.TreeIter) pos);
+				Gtk.TreeIter iter;
+				if (!pad.GetFirstNode (dataObject, out iter)) return null;
+				return new TreeNodeNavigator (pad, iter);
 			}
 			
-			public ITreeOptions GetOptions (object dataObject)
-			{
-				if (dataObject == null) return pad.globalOptions;
-				object pos = pad.nodeHash [dataObject];
-				if (pos == null) return pad.globalOptions;
-				return new TreeNodeNavigator (pad, (Gtk.TreeIter) pos);
+			public TreeViewPad Tree {
+				get { return pad; }
 			}
 		}
 		
+		
 		class TreeNodeNavigator: ITreeNavigator, ITreeOptions
 		{
 			protected TreeViewPad pad;
@@ -994,6 +1093,10 @@
 				get { return store.GetValue (currentIter, TreeViewPad.DataItemColumn); }
 			}
 			
+			internal NodeBuilder[] NodeBuilderChain {
+				get { return (NodeBuilder[]) store.GetValue (currentIter, TreeViewPad.BuilderChainColumn); }
+			}
+			
 			public bool Selected {
 				get {
 					return tree.Selection.IterIsSelected (currentIter);
@@ -1031,6 +1134,11 @@
 				return true;
 			}
 			
+			internal void MoveToIter (Gtk.TreeIter iter)
+			{
+				currentIter = iter;
+			}
+			
 			public bool MoveToRoot ()
 			{
 				return store.GetIterFirst (out currentIter);
@@ -1038,12 +1146,10 @@
 		
 			public bool MoveToObject (object dataObject)
 			{
-				object pos = pad.nodeHash [dataObject];
-				if (pos != null) {
-					currentIter = (Gtk.TreeIter) pos;
-					return true;
-				} else
-					return false;
+				Gtk.TreeIter iter;
+				if (!pad.GetFirstNode (dataObject, out iter)) return false;
+				currentIter = iter;
+				return true;
 			}
 		
 			public bool MoveToParent ()
@@ -1096,6 +1202,43 @@
 				return store.IterChildren (out it, currentIter);
 			}
 		
+			public bool FindChild (object dataObject)
+			{
+				return FindChild (dataObject, false);
+			}
+			
+			public bool FindChild (object dataObject, bool recursive)
+			{
+				object it = pad.nodeHash [dataObject];
+				
+				if (it == null)
+					return false;
+				else if (it is Gtk.TreeIter) {
+					if (IsChildIter (currentIter, (Gtk.TreeIter)it, recursive)) {
+						currentIter = (Gtk.TreeIter)it;
+						return true;
+					} else
+						return false;
+				} else {
+					foreach (Gtk.TreeIter cit in (Gtk.TreeIter[])it) {
+						if (IsChildIter (currentIter, cit, recursive)) {
+							currentIter = (Gtk.TreeIter)cit;
+							return true;
+						}
+					}
+					return false;
+				}
+			}
+			
+			bool IsChildIter (Gtk.TreeIter pit, Gtk.TreeIter cit, bool recursive)
+			{
+				while (store.IterParent (out cit, cit)) {
+					if (cit.Equals (pit)) return true;
+					if (!recursive) return false;
+				}
+				return false;
+			}
+			
 			public bool MoveToChild (string name, Type dataType)
 			{
 				EnsureFilled ();
@@ -1131,7 +1274,23 @@
 			public ITreeOptions Options {
 				get { return this; }
 			}
+			
+			public NodeState SaveState ()
+			{
+				return NodeState.SaveState (pad, this);
+			}
+			
+			public void RestoreState (NodeState state)
+			{
+				NodeState.RestoreState (pad, this, state);
+			}
 		
+			public void Refresh ()
+			{
+				ITreeBuilder builder = new TreeBuilder (pad, currentIter);
+				builder.UpdateAll ();
+			}
+			
 			public void ExpandToNode ()
 			{
 				Gtk.TreePath path = store.GetPath (currentIter);
@@ -1142,7 +1301,7 @@
 				get {
 					object data = DataItem;
 					NodeBuilder[] chain = BuilderChain;
-					if (chain != null && chain.Length > 0) return ((TypeNodeBuilder)chain[0]).GetNodeName (data);
+					if (chain != null && chain.Length > 0) return ((TypeNodeBuilder)chain[0]).GetNodeName (this, data);
 					else return store.GetValue (currentIter, TreeViewPad.TextColumn) as string;;
 				}
 			}
@@ -1220,6 +1379,24 @@
 				UpdateNode (chain, data);
 			}
 			
+			public void ResetState ()
+			{
+				Update ();
+				RemoveChildren (currentIter);
+
+				object data = store.GetValue (currentIter, TreeViewPad.DataItemColumn);
+				NodeBuilder[] chain = (NodeBuilder[]) store.GetValue (currentIter, TreeViewPad.BuilderChainColumn);
+
+				if (!HasChildNodes (chain, data))
+					FillNode ();
+				else {
+					RemoveChildren (currentIter);
+					store.Append (currentIter);	// Dummy node
+					store.SetValue (currentIter, TreeViewPad.FilledColumn, false);
+				}
+				
+			}
+			
 			public void UpdateChildren ()
 			{
 				object data = store.GetValue (currentIter, TreeViewPad.DataItemColumn);
@@ -1231,22 +1408,8 @@
 					return;
 				}
 				
-				if (!tree.GetRowExpanded (store.GetPath (currentIter))) {
-					if (!HasChildNodes (chain, data))
-						FillNode ();
-					else {
-						RemoveChildren (currentIter);
-						store.Append (currentIter);	// Dummy node
-						store.SetValue (currentIter, TreeViewPad.FilledColumn, false);
-					}
-					return;
-				}
-
-				ArrayList state = new ArrayList ();
-				SaveExpandState (currentIter, state);
-				RemoveChildren (currentIter);
-				CreateChildren (chain, data);
-				RestoreExpandState (state);
+				NodeState ns = SaveState ();
+				RestoreState (ns);
 			}
 			
 			void RemoveChildren (Gtk.TreeIter it)
@@ -1256,39 +1419,16 @@
 					RemoveChildren (child);
 					object childData = store.GetValue (child, TreeViewPad.DataItemColumn);
 					if (childData != null)
-						pad.UnregisterNode (childData, null);
+						pad.UnregisterNode (childData, child, null);
 					store.Remove (ref child);
 				}
 			}
 			
-			void SaveExpandState (Gtk.TreeIter it, ArrayList state)
-			{
-				if (tree.GetRowExpanded (store.GetPath (it)))
-					state.Add (store.GetValue (it, TreeViewPad.DataItemColumn));
-				if (store.IterChildren (out it, it)) {
-					do {
-						SaveExpandState (it, state);
-					} while (store.IterNext (ref it));
-				}
-			}
-			
-			void RestoreExpandState (ArrayList state)
-			{
-				foreach (object ob in state) {
-					object pos = pad.nodeHash [ob];
-					if (pos == null) continue;
-					
-					Gtk.TreeIter it = (Gtk.TreeIter) pos;
-					Gtk.TreePath p = store.GetPath (it);
-					tree.ExpandRow (p, false);
-				}
-			}
-			
 			public void Remove ()
 			{
 				RemoveChildren (currentIter);
 				object data = store.GetValue (currentIter, TreeViewPad.DataItemColumn);
-				pad.UnregisterNode (data, null);
+				pad.UnregisterNode (data, currentIter, null);
 				store.Remove (ref currentIter);
 			}
 			
@@ -1312,11 +1452,6 @@
 			{
 				if (dataObject == null) throw new ArgumentNullException ("dataObject");
 				
-				if (!currentIter.Equals (Gtk.TreeIter.Zero))
-					EnsureFilled ();
-					
-				if (pad.IsRegistered (dataObject)) return;
-
 				NodeBuilder[] chain = pad.GetBuilderChain (dataObject.GetType ());
 				if (chain == null) return;
 				
@@ -1330,10 +1465,12 @@
 				
 				if ((ats & NodeAttributes.Hidden) != 0)
 					return;
-					
+				
 				Gtk.TreeIter it;
-				if (!currentIter.Equals (Gtk.TreeIter.Zero))
+				if (!currentIter.Equals (Gtk.TreeIter.Zero)) {
+					if (!Filled) return;
 					it = store.Append (currentIter);
+				}
 				else
 					store.Append (out it);
 				
@@ -1395,6 +1532,21 @@
 					
 				if (closedIcon == null) closedIcon = icon;
 				
+				if (dataObject == pad.copyObject && pad.currentTransferOperation == DragOperation.Move) {
+					Gdk.Pixbuf gicon = pad.builderContext.GetComposedIcon (icon, "fade");
+					if (gicon == null) {
+						gicon = Runtime.Gui.Icons.MakeTransparent (icon, 0.5);
+						pad.builderContext.CacheComposedIcon (icon, "fade", gicon);
+					}
+					icon = gicon;
+					gicon = pad.builderContext.GetComposedIcon (closedIcon, "fade");
+					if (gicon == null) {
+						gicon = Runtime.Gui.Icons.MakeTransparent (closedIcon, 0.5);
+						pad.builderContext.CacheComposedIcon (closedIcon, "fade", gicon);
+					}
+					closedIcon = gicon;
+				}
+				
 				SetNodeInfo (currentIter, text, icon, closedIcon);
 			}
 			
@@ -1415,19 +1567,19 @@
 			}
 		}
 		
-		class TreeOptions: Hashtable, ITreeOptions
+		internal class TreeOptions: Hashtable, ITreeOptions
 		{
 			TreeViewPad pad;
-			object dataObject;
+			Gtk.TreeIter iter;
 			
 			public TreeOptions ()
 			{
 			}
 			
-			public TreeOptions (TreeViewPad pad, object dataObject)
+			public TreeOptions (TreeViewPad pad, Gtk.TreeIter iter)
 			{
 				this.pad = pad;
-				this.dataObject = dataObject;
+				this.iter = iter;
 			}
 			
 			public TreeViewPad Pad {
@@ -1435,6 +1587,11 @@
 				set { pad = value; }
 			}
 
+			public Gtk.TreeIter Iter {
+				get { return iter; }
+				set { iter = value; }
+			}
+
 			public bool this [string name] {
 				get {
 					object op = base [name];
@@ -1444,15 +1601,13 @@
 				set {
 					base [name] = value;
 					if (pad != null)
-						pad.RefreshNode (dataObject);
+						pad.RefreshNode (iter);
 				}
 			}
 			
-			public TreeOptions CloneOptions (object newDataObject)
+			public TreeOptions CloneOptions (Gtk.TreeIter newIter)
 			{
-				TreeOptions ops = new TreeOptions (pad, null);
-				ops.pad = pad;
-				ops.dataObject = newDataObject;
+				TreeOptions ops = new TreeOptions (pad, newIter);
 				foreach (DictionaryEntry de in this)
 					ops [de.Key] = de.Value;
 				return ops;
@@ -1476,10 +1631,7 @@
 		
 		public void Restore (TreeViewPad view)
 		{
-			XmlElement rootNode = parent ["Node"];
-			if (rootNode != null) {
-				view.RestoreTreeState (rootNode);
-			}
+			view.RestoreTreeState (parent);
 		}
 		
 		public object FromXmlElement (XmlElement element)

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TypeNodeBuilder.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TypeNodeBuilder.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Gui/Pads/SolutionPad/TypeNodeBuilder.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -38,14 +38,14 @@
 		
 		public abstract Type NodeDataType { get; }
 		
-		public abstract string GetNodeName (object dataObject);
+		public abstract string GetNodeName (ITreeNavigator thisNode, object dataObject);
 		
 		// Return -1 if thisDataObject is less than otherDataObject, 0 if equal, 1 if greater
 		// Return DefaultSort is sort is undefined or you want to use default sorting rules
 		// (by default, it compares the node name).
 		// The thisDataObject parameter is an instance valid for this node builder.
 		// otherDataObject may not be an instance valid for this builder.
-		public virtual int CompareObjects (object thisDataObject, object otherDataObject)
+		public virtual int CompareObjects (ITreeNavigator thisNode, ITreeNavigator otherNode)
 		{
 			return DefaultSort;
 		}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Collections/ProjectFileCollection.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Collections/ProjectFileCollection.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Collections/ProjectFileCollection.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -6,6 +6,7 @@
 // </file>
 using System;
 using System.Collections;
+using System.IO;
 
 namespace MonoDevelop.Internal.Project
 {
@@ -44,6 +45,18 @@
 			return null;
 		}
 		
+		public ProjectFile[] GetFilesInPath (string path)
+		{
+			path = path + Path.DirectorySeparatorChar;
+			ArrayList files = new ArrayList ();
+			
+			foreach (ProjectFile file in List) {
+				if ((file.Name + Path.DirectorySeparatorChar).StartsWith (path))
+					files.Add (file);
+			}
+			return (ProjectFile[]) files.ToArray (typeof(ProjectFile));
+		}
+		
 		/// <summary>
 		/// <para>Represents the entry at the specified index of the <see cref='.ProjectFile'/>.</para>
 		/// </summary>

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Project.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Project.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Internal/Project/Project/Project.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -493,26 +493,31 @@
 		
 		internal void NotifyFileRemovedFromProject (ProjectFile file)
 		{
+			isDirty = true;
 			OnFileRemovedFromProject (new ProjectFileEventArgs (this, file));
 		}
 		
 		internal void NotifyFileAddedToProject (ProjectFile file)
 		{
+			isDirty = true;
 			OnFileAddedToProject (new ProjectFileEventArgs (this, file));
 		}
 		
 		internal void NotifyFileRenamedInProject (ProjectFileRenamedEventArgs args)
 		{
+			isDirty = true;
 			OnFileRenamedInProject (args);
 		}
 		
 		internal void NotifyReferenceRemovedFromProject (ProjectReference reference)
 		{
+			isDirty = true;
 			OnReferenceRemovedFromProject (new ProjectReferenceEventArgs (this, reference));
 		}
 		
 		internal void NotifyReferenceAddedToProject (ProjectReference reference)
 		{
+			isDirty = true;
 			OnReferenceAddedToProject (new ProjectReferenceEventArgs (this, reference));
 		}
 		

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Makefile.am
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Makefile.am	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Makefile.am	2005-04-07 00:02:46 UTC (rev 2433)
@@ -49,6 +49,9 @@
 Gui/Pads/ProjectPad/ProjectReferenceNodeBuilder.cs \
 Gui/Pads/ProjectPad/ResourceFolder.cs \
 Gui/Pads/ProjectPad/ResourceFolderNodeBuilder.cs \
+Gui/Pads/ProjectPad/ShowAllFilesBuilderExtension.cs \
+Gui/Pads/ProjectPad/SystemFile.cs \
+Gui/Pads/ProjectPad/SystemFileNodeBuilder.cs \
 Gui/Pads/SolutionPad/DragOperation.cs \
 Gui/Pads/SolutionPad/ITreeBuilder.cs \
 Gui/Pads/SolutionPad/ITreeBuilderContext.cs \
@@ -58,6 +61,7 @@
 Gui/Pads/SolutionPad/NodeBuilder.cs \
 Gui/Pads/SolutionPad/NodeBuilderExtension.cs \
 Gui/Pads/SolutionPad/NodeCommandHandler.cs \
+Gui/Pads/SolutionPad/NodeState.cs \
 Gui/Pads/SolutionPad/SolutionPad.cs \
 Gui/Pads/SolutionPad/TreePadOption.cs \
 Gui/Pads/SolutionPad/TreeViewPad.cs \

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/MonoDevelopCore.addin.xml
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/MonoDevelopCore.addin.xml	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/MonoDevelopCore.addin.xml	2005-04-07 00:02:46 UTC (rev 2433)
@@ -147,6 +147,11 @@
                 <MenuItem id = "AddReference"
 	                  _label = "Edit References"
 	                  class = "MonoDevelop.Commands.ProjectBrowser.AddReferenceToProject"/>
+				<MenuItem id = "Paste"
+							  _label = "_Paste" 
+							  icon = "Icons.16x16.PasteIcon" 
+							  shortcut = "Control|V"
+							  class = "MonoDevelop.Commands.ProjectBrowser.PasteNodeCommand"/>
 	</Extension>
 	
 	<Extension path = "/SharpDevelop/Views/ProjectBrowser/ContextMenu/ReferenceNode">
@@ -155,6 +160,11 @@
 		          icon  = "Icons.16x16.OpenFileIcon"
 		          class = "MonoDevelop.Commands.ProjectBrowser.OpenFileEvent"/>
 		<MenuItem id = "OpenSeparator" _label = "-" />
+		<MenuItem id = "Copy"
+	                  _label = "_Copy" 
+					  icon = "Icons.16x16.CopyIcon" 
+					  shortcut = "Control|C"
+	                  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
 		<MenuItem id = "Remove"
 	                  _label = "_Remove" 
 	                  icon  = "Icons.16x16.DeleteIcon"
@@ -167,6 +177,17 @@
 		          icon  = "Icons.16x16.OpenFileIcon"
 		          class = "MonoDevelop.Commands.ProjectBrowser.OpenFileEvent"/>
 		<MenuItem id = "OpenSeparator" _label = "-" />
+		<MenuItem id = "Copy"
+	                  _label = "_Copy" 
+					  icon = "Icons.16x16.CopyIcon" 
+					  shortcut = "Control|C"
+	                  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
+		<MenuItem id = "Cut"
+				  _label = "_Cut" 
+				  icon = "Icons.16x16.CutIcon" 
+				  shortcut = "Control|X"
+				  class = "MonoDevelop.Commands.ProjectBrowser.CutNodeCommand"/>
+		<MenuItem id = "CutSeparator" _label = "-" />
 		<MenuItem id = "Remove"
 	                  _label = "_Remove" 
 	                  icon  = "Icons.16x16.DeleteIcon"
@@ -202,6 +223,17 @@
 			          class = "MonoDevelop.Commands.IncludeFilesBuilder" />
 			</MenuItem>
 		<MenuItem id = "IncludeSeparator" _label = "-" />
+		<MenuItem id = "Copy"
+	                  _label = "_Copy" 
+					  icon = "Icons.16x16.CopyIcon" 
+					  shortcut = "Control|C"
+	                  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
+		<MenuItem id = "Cut"
+				  _label = "_Cut" 
+				  icon = "Icons.16x16.CutIcon" 
+				  shortcut = "Control|X"
+				  class = "MonoDevelop.Commands.ProjectBrowser.CutNodeCommand"/>
+		<MenuItem id = "CutSeparator" _label = "-" />
 		<MenuItem id = "Remove"
 	                  _label = "Remove" 
 	                  icon  = "Icons.16x16.DeleteIcon"
@@ -211,6 +243,36 @@
 	                  shortcut = "F2"
 	                  class    = "MonoDevelop.Commands.ProjectBrowser.RenameEntryEvent"/>
         </Extension>
+		
+        <Extension path = "/SharpDevelop/Views/ProjectBrowser/ContextMenu/SystemFileNode">
+			<MenuItem id = "OpenFile"
+					_label = "O_pen" 
+					icon  = "Icons.16x16.OpenFileIcon"
+					class = "MonoDevelop.Commands.ProjectBrowser.OpenFileEvent"/>
+			<MenuItem id = "IncludeToProject"
+					_label = "Include To Project" 
+					class = "MonoDevelop.Commands.ProjectBrowser.IncludeFileToProject"/>
+			<MenuItem id = "IncludeToProjectSeparator" _label = "-" />
+			<MenuItem id = "Copy"
+						  _label = "_Copy" 
+						  icon = "Icons.16x16.CopyIcon" 
+						  shortcut = "Control|C"
+						  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
+			<MenuItem id = "Cut"
+					  _label = "_Cut" 
+					  icon = "Icons.16x16.CutIcon" 
+					  shortcut = "Control|X"
+					  class = "MonoDevelop.Commands.ProjectBrowser.CutNodeCommand"/>
+			<MenuItem id = "CutSeparator" _label = "-" />
+			<MenuItem id = "Remove"
+					_label = "Remove" 
+					icon  = "Icons.16x16.DeleteIcon"
+					class = "MonoDevelop.Commands.ProjectBrowser.RemoveEntryEvent"/>
+			<MenuItem id = "Rename"
+					_label    = "Rename" 
+					shortcut = "F2"
+					class    = "MonoDevelop.Commands.ProjectBrowser.RenameEntryEvent"/>
+        </Extension>
         
         <Extension path = "/SharpDevelop/Views/ProjectBrowser/ContextMenu/DefaultDirectoryNode">
                 <MenuItem id = "Add" _label = "Add">
@@ -228,6 +290,22 @@
 		                  class = "MonoDevelop.Commands.ProjectBrowser.NewFolderEvent"/>
         	</MenuItem>
 		<MenuItem id = "AddSeparator" _label = "-" />
+			<MenuItem id = "Copy"
+						  _label = "_Copy" 
+						  icon = "Icons.16x16.CopyIcon" 
+						  shortcut = "Control|C"
+						  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
+			<MenuItem id = "Cut"
+					  _label = "_Cut" 
+					  icon = "Icons.16x16.CutIcon" 
+					  shortcut = "Control|X"
+					  class = "MonoDevelop.Commands.ProjectBrowser.CutNodeCommand"/>
+			<MenuItem id = "Paste"
+					  _label = "_Paste" 
+					  icon = "Icons.16x16.PasteIcon" 
+					  shortcut = "Control|V"
+					  class = "MonoDevelop.Commands.ProjectBrowser.PasteNodeCommand"/>
+			<MenuItem id = "CutSeparator" _label = "-" />
 		<MenuItem id = "Remove"
 	                  _label = "_Remove" 
 	                  icon  = "Icons.16x16.DeleteIcon"
@@ -262,6 +340,22 @@
 		                  class = "MonoDevelop.Commands.ProjectBrowser.NewFolderEvent"/>
         	</MenuItem>
 		<MenuItem id = "AddSeparator" _label = "-" />
+			<MenuItem id = "Copy"
+						  _label = "_Copy" 
+						  icon = "Icons.16x16.CopyIcon" 
+						  shortcut = "Control|C"
+						  class = "MonoDevelop.Commands.ProjectBrowser.CopyNodeCommand"/>
+			<MenuItem id = "Cut"
+					  _label = "_Cut" 
+					  icon = "Icons.16x16.CutIcon" 
+					  shortcut = "Control|X"
+					  class = "MonoDevelop.Commands.ProjectBrowser.CutNodeCommand"/>
+			<MenuItem id = "Paste"
+					  _label = "_Paste" 
+					  icon = "Icons.16x16.PasteIcon" 
+					  shortcut = "Control|V"
+					  class = "MonoDevelop.Commands.ProjectBrowser.PasteNodeCommand"/>
+			<MenuItem id = "CutSeparator" _label = "-" />
 		<MenuItem id = "Remove"
 	                  _label = "_Remove" 
 	                  icon  = "Icons.16x16.DeleteIcon"
@@ -417,6 +511,8 @@
 			<NodeBuilder id = "ProjectFile" class = "MonoDevelop.Gui.Pads.ProjectPad.ProjectFileNodeBuilder"/>
 			<NodeBuilder id = "Folder" class = "MonoDevelop.Gui.Pads.ProjectPad.ProjectFolderNodeBuilder"/>
 			<NodeBuilder id = "ResourceFolder" class = "MonoDevelop.Gui.Pads.ProjectPad.ResourceFolderNodeBuilder"/>
+			<NodeBuilder id = "SystemFile" class = "MonoDevelop.Gui.Pads.ProjectPad.SystemFileNodeBuilder"/>
+			<NodeBuilder id = "ShowAllFilesExtension" class = "MonoDevelop.Gui.Pads.ProjectPad.ShowAllFilesBuilderExtension"/>
 		</SolutionPad>
 
 		<SolutionPad id = "MonoDevelop.Gui.Pads.ClassPad" defaultPlacement = "Left" _label = "Classes" icon = "md-class">

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/DispatchService/DispatchService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/DispatchService/DispatchService.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/DispatchService/DispatchService.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -123,23 +123,25 @@
 
 		private bool guiDispatcher ()
 		{
-			GenericMessageContainer msg;
+			ArrayList msgList;
 			
 			lock (arrGuiQueue) {
 				if (arrGuiQueue.Count == 0) {
 					iIdle = 0;
 					return false;
 				}
-				msg = (GenericMessageContainer)arrGuiQueue[0];
-				arrGuiQueue.RemoveAt (0);
+				msgList = (ArrayList) arrGuiQueue.Clone ();
+				arrGuiQueue.Clear ();
 			}
-			if (msg != null) {
+
+			foreach (GenericMessageContainer msg in msgList) {
 				msg.Run ();
 				if (msg.IsSynchronous)
 					lock (msg) Monitor.PulseAll (msg);
 				else if (msg.Exception != null)
 					HandlerError (msg);
 			}
+			
 			lock (arrGuiQueue) {
 				if (arrGuiQueue.Count == 0) {
 					iIdle = 0;

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/DefaultFileService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/DefaultFileService.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/DefaultFileService.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -10,7 +10,6 @@
 using System.Diagnostics;
 using System.IO;
 using System.Xml;
-using Vfs = Gnome.Vfs.Vfs;
 
 using MonoDevelop.Core.AddIns;
 using MonoDevelop.Core.Services;
@@ -28,7 +27,7 @@
 	
 		private class FileInformation
 		{
-			public FileOpeningFinished OnFileOpened;
+			public IProgressMonitor ProgressMonitor;
 			public string FileName;
 			public bool BringToFront;
 		}
@@ -82,120 +81,110 @@
 			}
 		}
 		
-		public void OpenFile (string fileName)
+		public IAsyncOperation OpenFile (string fileName)
 		{
-			OpenFile (fileName, true);
+			return OpenFile (fileName, true);
 		}
 		
-		public void OpenFile (string fileName, bool bringToFront)
+		public IAsyncOperation OpenFile (string fileName, bool bringToFront)
 		{
-			FileInformation openFileInfo=new FileInformation();
-			openFileInfo.OnFileOpened=null;
-			openFileInfo.FileName=fileName;
+			IProgressMonitor pm = Runtime.TaskService.GetStatusProgressMonitor (string.Format (GettextCatalog.GetString ("Opening {0}"), fileName), Stock.OpenFileIcon, false);
+			FileInformation openFileInfo = new FileInformation();
+			openFileInfo.ProgressMonitor = pm;
+			openFileInfo.FileName = fileName;
 			openFileInfo.BringToFront = bringToFront;
 			Runtime.DispatchService.GuiDispatch (new StatefulMessageHandler (realOpenFile), openFileInfo);
+			return pm.AsyncOperation;
 		}
-
-		public void OpenFile (string fileName, FileOpeningFinished OnFileOpened) {
-			OpenFile (fileName, true, OnFileOpened);
-		}
 		
-		public void OpenFile (string fileName, bool bringToFront, FileOpeningFinished OnFileOpened){
-			FileInformation openFileInfo=new FileInformation();
-			openFileInfo.OnFileOpened=OnFileOpened;
-			openFileInfo.FileName=fileName;
-			openFileInfo.BringToFront = bringToFront;
-			Runtime.DispatchService.GuiDispatch (new StatefulMessageHandler (realOpenFile), openFileInfo);
-		}
-		
 		void realOpenFile (object openFileInfo)
 		{
 			string fileName;
-			FileInformation oFileInfo;
-			if(openFileInfo is FileInformation){
-				oFileInfo=openFileInfo as FileInformation;
-				fileName=oFileInfo.FileName;
-			}else{
-				return;
-			}
-			
-			if (fileName == null)
-				return;
+			FileInformation oFileInfo = openFileInfo as FileInformation;
+			IProgressMonitor monitor = oFileInfo.ProgressMonitor;
 
-			string origName = fileName;
-
-			if (fileName.StartsWith ("file://"))
-				fileName = fileName.Substring (7);
-
-			if (!fileName.StartsWith ("http://"))
-				fileName = System.IO.Path.GetFullPath (fileName);
-			
-			//Debug.Assert(Runtime.FileUtilityService.IsValidFileName(fileName));
-			if (Runtime.FileUtilityService.IsDirectory (fileName)) {
-				return;
-			}
-			// test, if file fileName exists
-			if (!fileName.StartsWith("http://")) {
-				// test, if an untitled file should be opened
-				if (!Path.IsPathRooted(origName)) { 
-					foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) {
-						if (content.IsUntitled && content.UntitledName == origName) {
-							content.WorkbenchWindow.SelectWindow();
-							if(oFileInfo.OnFileOpened!=null) oFileInfo.OnFileOpened();
-							return;
-						}
-					}
-				} else 
-				if (!Runtime.FileUtilityService.TestFileExists(fileName)) {
-					if(oFileInfo.OnFileOpened!=null) oFileInfo.OnFileOpened();
+			using (monitor)
+			{
+				fileName = oFileInfo.FileName;
+				
+				if (fileName == null) {
+					monitor.ReportError (GettextCatalog.GetString ("Invalid file name"), null);
 					return;
 				}
-			}
-			
-			foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) {
-				if (content.ContentName != null && 
-				    content.ContentName == fileName) {
-					content.WorkbenchWindow.SelectWindow();
-					if(oFileInfo.OnFileOpened!=null) oFileInfo.OnFileOpened();
+	
+				string origName = fileName;
+	
+				if (fileName.StartsWith ("file://"))
+					fileName = fileName.Substring (7);
+	
+				if (!fileName.StartsWith ("http://"))
+					fileName = System.IO.Path.GetFullPath (fileName);
+				
+				//Debug.Assert(Runtime.FileUtilityService.IsValidFileName(fileName));
+				if (Runtime.FileUtilityService.IsDirectory (fileName)) {
+					monitor.ReportError (string.Format (GettextCatalog.GetString ("{0} is a directory"), fileName), null);
 					return;
 				}
-			}
-			
-			IDisplayBinding binding = Runtime.Gui.DisplayBindings.GetBindingPerFileName(fileName);
-			
-			if (binding != null) {
-				Project project = null;
-				Combine combine = null;
-				GetProjectAndCombineFromFile (fileName, out project, out combine);
-				
-				if (combine != null && project != null)
-				{
-					if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate(new LoadFileWrapper(binding, project, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
-						Runtime.FileService.RecentOpen.AddLastFile (fileName, project.Name);
+				// test, if file fileName exists
+				if (!fileName.StartsWith("http://")) {
+					// test, if an untitled file should be opened
+					if (!Path.IsPathRooted(origName)) { 
+						foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) {
+							if (content.IsUntitled && content.UntitledName == origName) {
+								content.WorkbenchWindow.SelectWindow();
+								return;
+							}
+						}
+					} else 
+					if (!Runtime.FileUtilityService.TestFileExists(fileName)) {
+						monitor.ReportError (string.Format (GettextCatalog.GetString ("File not found: {0}"), fileName), null);
+						return;
 					}
 				}
-				else
-				{
-					if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate(new LoadFileWrapper(binding, null, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
-						Runtime.FileService.RecentOpen.AddLastFile (fileName, null);
+				
+				foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) {
+					if (content.ContentName != null && 
+						content.ContentName == fileName) {
+						content.WorkbenchWindow.SelectWindow();
+						return;
 					}
 				}
-			} else {
-				try {
-					// FIXME: this doesn't seem finished yet in Gtk#
-					//MimeType mimetype = new MimeType (new Uri ("file://" + fileName));
-					//if (mimetype != null) {
-					//	mimetype.DefaultAction.Launch ();
-					//} else {
-						Gnome.Url.Show ("file://" + fileName);
-					//}
-				} catch {
-					if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate (new LoadFileWrapper (Runtime.Gui.DisplayBindings.LastBinding, null, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
-						Runtime.FileService.RecentOpen.AddLastFile (fileName, null);
+				
+				IDisplayBinding binding = Runtime.Gui.DisplayBindings.GetBindingPerFileName(fileName);
+				
+				if (binding != null) {
+					Project project = null;
+					Combine combine = null;
+					GetProjectAndCombineFromFile (fileName, out project, out combine);
+					
+					if (combine != null && project != null)
+					{
+						if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate(new LoadFileWrapper(binding, project, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
+							Runtime.FileService.RecentOpen.AddLastFile (fileName, project.Name);
+						}
 					}
+					else
+					{
+						if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate(new LoadFileWrapper(binding, null, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
+							Runtime.FileService.RecentOpen.AddLastFile (fileName, null);
+						}
+					}
+				} else {
+					try {
+						// FIXME: this doesn't seem finished yet in Gtk#
+						//MimeType mimetype = new MimeType (new Uri ("file://" + fileName));
+						//if (mimetype != null) {
+						//	mimetype.DefaultAction.Launch ();
+						//} else {
+							Gnome.Url.Show ("file://" + fileName);
+						//}
+					} catch {
+						if (Runtime.FileUtilityService.ObservedLoad(new NamedFileOperationDelegate (new LoadFileWrapper (Runtime.Gui.DisplayBindings.LastBinding, null, oFileInfo.BringToFront).Invoke), fileName) == FileOperationResult.OK) {
+							Runtime.FileService.RecentOpen.AddLastFile (fileName, null);
+						}
+					}
 				}
 			}
-			if(oFileInfo.OnFileOpened!=null) oFileInfo.OnFileOpened();
 		}
 		
 		protected void GetProjectAndCombineFromFile (string fileName, out Project project, out Combine combine)
@@ -245,20 +234,11 @@
 			return null;
 		}
 		
-		public void RemoveFileFromProject(string fileName)
-		{
-			if (Directory.Exists(fileName)) {
-				OnFileRemovedFromProject(new FileEventArgs(fileName, true));
-			} else {
-				OnFileRemovedFromProject(new FileEventArgs(fileName, false));
-			}
-		}
-		
 		public void RemoveFile(string fileName)
 		{
 			if (Directory.Exists(fileName)) {
 				try {
-					Directory.Delete(fileName);
+					Directory.Delete (fileName, true);
 				} catch (Exception e) {
 					Runtime.MessageService.ShowError(e, String.Format (GettextCatalog.GetString ("Can't remove directory {0}"), fileName));
 					return;
@@ -298,28 +278,48 @@
 			}
 		}
 		
-		protected virtual void OnFileRemoved(FileEventArgs e)
+		public void CopyFile (string sourcePath, string destPath)
 		{
+			File.Copy (sourcePath, destPath, true);
+			OnFileCreated (new FileEventArgs (destPath, false));
+		}
+
+		public void MoveFile (string sourcePath, string destPath)
+		{
+			File.Copy (sourcePath, destPath, true);
+			OnFileCreated (new FileEventArgs (destPath, false));
+			File.Delete (sourcePath);
+			OnFileRemoved (new FileEventArgs (destPath, false));
+		}
+		
+		public void CreateDirectory (string path)
+		{
+			Directory.CreateDirectory (path);
+			OnFileCreated (new FileEventArgs (path, true));
+		}
+
+		protected virtual void OnFileCreated (FileEventArgs e)
+		{
+			if (FileCreated != null) {
+				FileCreated (this, e);
+			}
+		}
+		
+		protected virtual void OnFileRemoved (FileEventArgs e)
+		{
 			if (FileRemoved != null) {
 				FileRemoved(this, e);
 			}
 		}
 
-		protected virtual void OnFileRenamed(FileEventArgs e)
+		protected virtual void OnFileRenamed (FileEventArgs e)
 		{
 			if (FileRenamed != null) {
 				FileRenamed(this, e);
 			}
 		}
 
-		protected virtual void OnFileRemovedFromProject(FileEventArgs e)
-		{
-			if (FileRemovedFromProject != null) {
-				FileRemovedFromProject(this, e);
-			}
-		}
-		
-		public event FileEventHandler FileRemovedFromProject;
+		public event FileEventHandler FileCreated;
 		public event FileEventHandler FileRenamed;
 		public event FileEventHandler FileRemoved;
 	}

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/IFileService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/IFileService.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/File/IFileService.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -33,10 +33,8 @@
 		/// Opens the file fileName in SharpDevelop (shows the file in
 		/// the workbench window)
 		/// </remarks>
-		void OpenFile (string fileName);
-		void OpenFile (string fileName, bool bringToFront);
-		void OpenFile (string fileName, FileOpeningFinished onFileOpened);
-		void OpenFile (string fileName, bool bringToFront, FileOpeningFinished onFileOpened);
+		IAsyncOperation OpenFile (string fileName);
+		IAsyncOperation OpenFile (string fileName, bool bringToFront);
 		
 		/// <remarks>
 		/// Opens a new file with a given name, language and file content
@@ -62,7 +60,13 @@
 		/// to know for other parts of the IDE when a file is renamed.
 		/// </remarks>
 		void RenameFile(string oldName, string newName);
+		
+		void CopyFile (string sourcePath, string destPath);
 
+		void MoveFile (string sourcePath, string destPath);
+		
+		void CreateDirectory (string path);
+
 		/// <remarks>
 		/// Is called, when a file is renamed.
 		/// </remarks>
@@ -72,6 +76,11 @@
 		/// Is called, when a file is removed.
 		/// </remarks>
 		event FileEventHandler FileRemoved;
+		
+		/// <remarks>
+		/// Is called, when a file is created.
+		/// </remarks>
+		event FileEventHandler FileCreated;
 	}
 	public delegate void FileOpeningFinished();
 }

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/IProjectService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/IProjectService.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/IProjectService.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -145,6 +145,8 @@
 		/// </remarks>
 		void RemoveFileFromProject(string fileName);
 
+		void TransferFiles (IProgressMonitor monitor, Project sourceProject, string sourcePath, Project targetProject, string targetPath, bool removeFromSource, bool copyOnlyProjectFiles);
+		
 		Project CreateSingleFileProject (string file);
 		
 		Project CreateProject (string type, ProjectCreateInformation info, XmlElement projectOptions);

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/ProjectService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/ProjectService.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Project/ProjectService.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -734,7 +734,7 @@
 			string directory = Runtime.Properties.ConfigDirectory + "CombinePreferences";
 
 			if (!Directory.Exists(directory)) {
-				Directory.CreateDirectory(directory);
+				Runtime.FileService.CreateDirectory(directory);
 			}
 			string combinepath = Path.GetDirectoryName(combinefilename);
 			XmlDocument doc = new XmlDocument();
@@ -837,7 +837,130 @@
 			}
 		}
 		
+		public void TransferFiles (IProgressMonitor monitor, Project sourceProject, string sourcePath, Project targetProject, string targetPath, bool removeFromSource, bool copyOnlyProjectFiles)
+		{
+			if (targetProject == null)
+				throw new ArgumentNullException ("targetProject");
+
+			if (!targetPath.StartsWith (targetProject.BaseDirectory))
+				throw new ArgumentException ("Invalid project folder: " + targetPath);
+
+			if (sourceProject != null && !sourcePath.StartsWith (sourceProject.BaseDirectory))
+				throw new ArgumentException ("Invalid project folder: " + sourcePath);
+				
+			if (copyOnlyProjectFiles && sourceProject == null)
+				throw new ArgumentException ("A source project must be specified if copyOnlyProjectFiles is True");
+
+			// Get the list of files to copy
+
+			ICollection filesToMove;
+			try {
+				if (copyOnlyProjectFiles) {
+					filesToMove = sourceProject.ProjectFiles.GetFilesInPath (sourcePath);
+				} else {
+					ProjectFileCollection col = new ProjectFileCollection ();
+					GetAllFilesRecursive (sourcePath, col);
+					filesToMove = col;
+				}
+			} catch (Exception ex) {
+				monitor.ReportError (string.Format (GettextCatalog.GetString ("Could not get any file from '{0}'."), sourcePath), ex);
+				return;
+			}
+			
+			// Ensure that the destination folder is created, even if no files
+			// are copied
+			
+			try {
+				string newFolder = Path.Combine (targetPath, Path.GetFileName (sourcePath));
+				if (Directory.Exists (sourcePath) && !Directory.Exists (newFolder))
+					Runtime.FileService.CreateDirectory (newFolder);
+			} catch (Exception ex) {
+				monitor.ReportError (string.Format (GettextCatalog.GetString ("Could not create directory '{0}'."), targetPath), ex);
+				return;
+			}
+
+			// Transfer files
+			
+			string basePath = Path.GetDirectoryName (sourcePath);
+			monitor.BeginTask (GettextCatalog.GetString ("Copying files..."), filesToMove.Count);
+			
+			foreach (ProjectFile file in filesToMove) {
+				string sourceFile = file.Name;
+				string newFile = targetPath + sourceFile.Substring (basePath.Length);
+				
+				try {
+					string fileDir = Path.GetDirectoryName (newFile);
+					if (!Directory.Exists (fileDir))
+						Runtime.FileService.CreateDirectory (fileDir);
+					Runtime.FileService.CopyFile (sourceFile, newFile);
+				} catch (Exception ex) {
+					monitor.ReportError (string.Format (GettextCatalog.GetString ("File '{0}' could not be created."), newFile), ex);
+					monitor.Step (1);
+					continue;
+				}
+				
+				if (sourceProject != null) {
+					ProjectFile projectFile = sourceProject.ProjectFiles.GetFile (sourceFile);
+					if (projectFile != null) {
+						if (removeFromSource)
+							sourceProject.ProjectFiles.Remove (projectFile);
+						if (targetProject.ProjectFiles.GetFile (newFile) == null) {
+							projectFile = (ProjectFile) projectFile.Clone ();
+							projectFile.SetProject (null);
+							projectFile.Name = newFile;
+							targetProject.ProjectFiles.Add (projectFile);
+						}
+					}
+				}
+				
+				if (removeFromSource) {
+					try {
+						Runtime.FileService.RemoveFile (sourceFile);
+					} catch (Exception ex) {
+						monitor.ReportError (string.Format (GettextCatalog.GetString ("File '{0}' could not be deleted."), sourceFile), ex);
+					}
+				}
+				monitor.Step (1);
+			}
+			
+			// If moving a folder, remove to source folder
+			
+			if (removeFromSource && Directory.Exists (sourcePath) && (
+					!copyOnlyProjectFiles ||
+					IsDirectoryHierarchyEmpty (sourcePath)))
+			{
+				try {
+					Runtime.FileService.RemoveFile (sourcePath);
+				} catch (Exception ex) {
+					monitor.ReportError (string.Format (GettextCatalog.GetString ("Directory '{0}' could not be deleted."), sourcePath), ex);
+				}
+			}
+			
+			monitor.EndTask ();
+		}
 		
+		void GetAllFilesRecursive (string path, ProjectFileCollection files)
+		{
+			if (File.Exists (path)) {
+				files.Add (new ProjectFile (path));
+				return;
+			}
+			
+			foreach (string file in Directory.GetFiles (path))
+				files.Add (new ProjectFile (file));
+			
+			foreach (string dir in Directory.GetDirectories (path))
+				GetAllFilesRecursive (dir, files);
+		}
+		
+		bool IsDirectoryHierarchyEmpty (string path)
+		{
+			if (Directory.GetFiles(path).Length > 0) return false;
+			foreach (string dir in Directory.GetDirectories (path))
+				if (!IsDirectoryHierarchyEmpty (dir)) return false;
+			return true;
+		}
+
 		void OnStartBuild()
 		{
 			if (StartBuild != null) {

Modified: trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Tasks/Task.cs
===================================================================
--- trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Tasks/Task.cs	2005-04-06 23:49:40 UTC (rev 2432)
+++ trunk/MonoDevelop/Core/src/MonoDevelop.Base/Services/Tasks/Task.cs	2005-04-07 00:02:46 UTC (rev 2433)
@@ -106,7 +106,8 @@
 		public void JumpToPosition()
 		{
 			if (fileName != null && fileName.Length > 0) {
-				Runtime.FileService.OpenFile(fileName,new FileOpeningFinished(OnFileOpened));
+				IAsyncOperation op = Runtime.FileService.OpenFile (fileName);
+				op.Completed += new OperationHandler (OnFileOpened);
 			}
 			
 //			CompilerResultListItem li = (CompilerResultListItem)OpenTaskView.FocusedItem;
@@ -126,8 +127,10 @@
 //			}
 		}
 		
-		private void OnFileOpened()
+		private void OnFileOpened (IAsyncOperation op)
 		{
+			if (!op.Success) return;
+
 			IWorkbenchWindow window = Runtime.FileService.GetOpenFile(fileName);
 			if (window == null) {
 				return;




More information about the Monodevelop-patches-list mailing list