From dfa4b51d2ae44051d6ffd08a8cef8e7e6cc2ce11 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 17 Aug 2008 21:15:57 +0000 Subject: [PATCH] r7440@daniel-notebook (orig r3402): daniel | 2008-08-17 16:48:17 +0200 Use svn copy when copying files/directories using the project browser. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3412 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Commands/AutostartCommands.cs | 46 +++++++++++- .../Project/Src/SvnClientWrapper.cs | 42 ++++++++--- .../Project/Src/SvnMessageView.cs | 11 +++ .../Commands/FolderNodeCommands.cs | 4 +- .../Project/Src/Services/File/FileService.cs | 73 +++++++++++++++++-- 5 files changed, 156 insertions(+), 20 deletions(-) diff --git a/src/AddIns/Misc/SubversionAddIn/Project/Src/Commands/AutostartCommands.cs b/src/AddIns/Misc/SubversionAddIn/Project/Src/Commands/AutostartCommands.cs index df65dda545..d2255049d7 100644 --- a/src/AddIns/Misc/SubversionAddIn/Project/Src/Commands/AutostartCommands.cs +++ b/src/AddIns/Misc/SubversionAddIn/Project/Src/Commands/AutostartCommands.cs @@ -29,6 +29,7 @@ namespace ICSharpCode.Svn.Commands { FileService.FileRemoving += FileRemoving; FileService.FileRenaming += FileRenaming; + FileService.FileCopying += FileCopying; FileService.FileCreated += FileCreated; ProjectService.SolutionCreated += SolutionCreated; @@ -192,7 +193,9 @@ namespace ICSharpCode.Svn.Commands switch (status.TextStatus) { case StatusKind.Unversioned: case StatusKind.Deleted: - client.Add(fullName, Recurse.None); + using (SharpDevelop.Gui.AsynchronousWaitDialog.ShowWaitDialog("svn add")) { + client.Add(fullName, Recurse.None); + } break; } } @@ -298,14 +301,51 @@ namespace ICSharpCode.Svn.Commands e.Cancel = true; return; } + e.OperationAlreadyDone = true; client.Delete(new string [] { fullName }, true); } - e.OperationAlreadyDone = true; } catch (Exception ex) { MessageService.ShowError("File removed exception: " + ex); } } + void FileCopying(object sender, FileRenamingEventArgs e) + { + if (e.Cancel) return; + if (!AddInOptions.AutomaticallyRenameFiles) return; + string fullSource = Path.GetFullPath(e.SourceFile); + if (!CanBeVersionControlledFile(fullSource)) return; + try { + using (SvnClientWrapper client = new SvnClientWrapper()) { + SvnMessageView.HandleNotifications(client); + + Status status = client.SingleStatus(fullSource); + switch (status.TextStatus) { + case StatusKind.Unversioned: + case StatusKind.None: + return; // nothing to do + case StatusKind.Normal: + case StatusKind.Modified: + case StatusKind.Replaced: + case StatusKind.Added: + // copy without problem + break; + default: + MessageService.ShowError("The file/directory cannot be copied because it is in subversion status '" + status.TextStatus + "'."); + e.Cancel = true; + return; + } + e.OperationAlreadyDone = true; + client.Copy(fullSource, + Revision.Working, + Path.GetFullPath(e.TargetFile) + ); + } + } catch (Exception ex) { + MessageService.ShowError("File renamed exception: " + ex); + } + } + void FileRenaming(object sender, FileRenamingEventArgs e) { if (e.Cancel) return; @@ -332,12 +372,12 @@ namespace ICSharpCode.Svn.Commands e.Cancel = true; return; } + e.OperationAlreadyDone = true; client.Move(fullSource, Path.GetFullPath(e.TargetFile), true ); } - e.OperationAlreadyDone = true; } catch (Exception ex) { MessageService.ShowError("File renamed exception: " + ex); } diff --git a/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnClientWrapper.cs b/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnClientWrapper.cs index adc0b0d3f3..c74bb39560 100644 --- a/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnClientWrapper.cs +++ b/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnClientWrapper.cs @@ -266,6 +266,8 @@ namespace ICSharpCode.Svn #endregion #region Notifications + public event EventHandler OperationStarted; + public event EventHandler OperationFinished; public event EventHandler Notify; void OnNotify(IntPtr baton, SvnWcNotify notify, AprPool pool) @@ -292,18 +294,22 @@ namespace ICSharpCode.Svn throw new ObjectDisposedException("SvnClientWrapper"); } - void BeforeOperation() + void BeforeOperation(string operationName) { // before any subversion operation, ensure the object is not disposed // and register authorization if necessary CheckNotDisposed(); OpenAuth(); + if (OperationStarted != null) + OperationStarted(this, new SubversionOperationEventArgs { Operation = operationName }); } void AfterOperation() { // after any subversion operation, clear the memory pool client.Clear(); + if (OperationFinished != null) + OperationFinished(this, EventArgs.Empty); } public void ClearStatusCache() @@ -315,7 +321,7 @@ namespace ICSharpCode.Svn public Status SingleStatus(string filename) { Debug("SVN: SingleStatus(" + filename + ")"); - BeforeOperation(); + BeforeOperation("stat"); try { filename = FileUtility.NormalizePath(filename); Status result; @@ -357,7 +363,7 @@ namespace ICSharpCode.Svn public void Add(string filename, Recurse recurse) { Debug("SVN: Add(" + filename + ", " + recurse + ")"); - BeforeOperation(); + BeforeOperation("add"); try { client.Add3(filename, recurse == Recurse.Full, false, false); } catch (SvnException ex) { @@ -370,7 +376,7 @@ namespace ICSharpCode.Svn public string GetPropertyValue(string fileName, string propertyName) { Debug("SVN: GetPropertyValue(" + fileName + ", " + propertyName + ")"); - BeforeOperation(); + BeforeOperation("propget"); try { AprHash hash = client.PropGet2(propertyName, fileName, Svn.Revision.Working, Svn.Revision.Working, @@ -393,7 +399,7 @@ namespace ICSharpCode.Svn public void SetPropertyValue(string fileName, string propertyName, string newPropertyValue) { Debug("SVN: SetPropertyValue(" + fileName + ", " + propertyName + ", " + newPropertyValue + ")"); - BeforeOperation(); + BeforeOperation("propset"); try { SvnString npv; if (newPropertyValue != null) @@ -420,7 +426,7 @@ namespace ICSharpCode.Svn public void Delete(string[] files, bool force) { Debug("SVN: Delete(" + string.Join(",", files) + ", " + force + ")"); - BeforeOperation(); + BeforeOperation("delete"); try { client.Delete2(ToSvnPaths(files), force); } catch (SvnException ex) { @@ -433,7 +439,7 @@ namespace ICSharpCode.Svn public void Revert(string[] files, Recurse recurse) { Debug("SVN: Revert(" + string.Join(",", files) + ", " + recurse + ")"); - BeforeOperation(); + BeforeOperation("revert"); try { client.Revert(ToSvnPaths(files), recurse == Recurse.Full); } catch (SvnException ex) { @@ -446,7 +452,7 @@ namespace ICSharpCode.Svn public void Move(string from, string to, bool force) { Debug("SVN: Move(" + from + ", " + to + ", " + force + ")"); - BeforeOperation(); + BeforeOperation("move"); try { client.Move3(from, to, force); } catch (SvnException ex) { @@ -456,6 +462,19 @@ namespace ICSharpCode.Svn } } + public void Copy(string from, Revision revision, string to) + { + Debug("SVN: Copy(" + from + ", " + revision + ", " + to); + BeforeOperation("copy"); + try { + client.Copy2(from, revision, to); + } catch (SvnException ex) { + throw new SvnClientException(ex); + } finally { + AfterOperation(); + } + } + public void AddToIgnoreList(string directory, params string[] filesToIgnore) { Debug("SVN: AddToIgnoreList(" + directory + ", " + string.Join(",", filesToIgnore) + ")"); @@ -482,7 +501,7 @@ namespace ICSharpCode.Svn { Debug("SVN: Log({" + string.Join(",", paths) + "}, " + start + ", " + end + ", " + limit + ", " + discoverChangePaths + ", " + strictNodeHistory + ")"); - BeforeOperation(); + BeforeOperation("log"); try { client.Log2( ToSvnPaths(paths), @@ -564,6 +583,11 @@ namespace ICSharpCode.Svn public string Path; } + public class SubversionOperationEventArgs : EventArgs + { + public string Operation; + } + public class LogMessage { public int Revision; diff --git a/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnMessageView.cs b/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnMessageView.cs index ac3942d98b..c9992d636e 100644 --- a/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnMessageView.cs +++ b/src/AddIns/Misc/SubversionAddIn/Project/Src/SvnMessageView.cs @@ -40,6 +40,17 @@ namespace ICSharpCode.Svn client.Notify += delegate(object sender, NotificationEventArgs e) { AppendLine(e.Kind + e.Action + " " + e.Path); }; + AsynchronousWaitDialog waitDialog = null; + client.OperationStarted += delegate(object sender, SubversionOperationEventArgs e) { + if (waitDialog != null) + waitDialog = AsynchronousWaitDialog.ShowWaitDialog("svn " + e.Operation); + }; + client.OperationFinished += delegate { + if (waitDialog != null) { + waitDialog.Dispose(); + waitDialog = null; + } + }; } } } diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/FolderNodeCommands.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/FolderNodeCommands.cs index 09c0dd1b8b..9d3d4106c3 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/FolderNodeCommands.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/Commands/FolderNodeCommands.cs @@ -100,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project.Commands } } - FileUtility.DeepCopy(directoryName, copiedFileName, true); + FileService.CopyFile(directoryName, copiedFileName, true, false); DirectoryNode newNode = new DirectoryNode(copiedFileName); newNode.AddTo(node); if (includeInProject) { @@ -123,7 +123,7 @@ namespace ICSharpCode.SharpDevelop.Project.Commands { string copiedFileName = Path.Combine(node.Directory, Path.GetFileName(fileName)); if (!FileUtility.IsEqualFileName(fileName, copiedFileName)) { - File.Copy(fileName, copiedFileName, true); + FileService.CopyFile(fileName, copiedFileName, false, true); } if (includeInProject) { FileNode fileNode; diff --git a/src/Main/Base/Project/Src/Services/File/FileService.cs b/src/Main/Base/Project/Src/Services/File/FileService.cs index 0aea4dc285..cc19e30d85 100644 --- a/src/Main/Base/Project/Src/Services/File/FileService.cs +++ b/src/Main/Base/Project/Src/Services/File/FileService.cs @@ -127,8 +127,10 @@ namespace ICSharpCode.SharpDevelop LoggingService.Debug("OpenedFileFileNameChange: " + oldName + " => " + newName); - Debug.Assert(openedFileDict[oldName] == file); - Debug.Assert(!openedFileDict.ContainsKey(newName)); + if (openedFileDict[oldName] != file) + throw new ArgumentException("file must be registered as oldName"); + if (openedFileDict.ContainsKey(newName)) + throw new ArgumentException("there already is a file with the newName"); openedFileDict.Remove(oldName); openedFileDict[newName] = file; @@ -137,7 +139,9 @@ namespace ICSharpCode.SharpDevelop /// Called by OpenedFile.UnregisterView to update the dictionary. internal static void OpenedFileClosed(OpenedFile file) { - Debug.Assert(openedFileDict[file.FileName] == file); + if (openedFileDict[file.FileName] != file) + throw new ArgumentException("file must be registered"); + openedFileDict.Remove(file.FileName); LoggingService.Debug("OpenedFileClosed: " + file.FileName); } @@ -392,6 +396,47 @@ namespace ICSharpCode.SharpDevelop return true; } + /// + /// Copies a file, raising the appropriate events. This method may show message boxes. + /// + public static bool CopyFile(string oldName, string newName, bool isDirectory, bool overwrite) + { + if (FileUtility.IsEqualFileName(oldName, newName)) + return false; + FileRenamingEventArgs eargs = new FileRenamingEventArgs(oldName, newName, isDirectory); + OnFileCopying(eargs); + if (eargs.Cancel) + return false; + if (!eargs.OperationAlreadyDone) { + try { + if (isDirectory && Directory.Exists(oldName)) { + + if (!overwrite && Directory.Exists(newName)) { + MessageService.ShowMessage(StringParser.Parse("${res:Gui.ProjectBrowser.FileInUseError}")); + return false; + } + FileUtility.DeepCopy(oldName, newName, overwrite); + + } else if (File.Exists(oldName)) { + if (!overwrite && File.Exists(newName)) { + MessageService.ShowMessage(StringParser.Parse("${res:Gui.ProjectBrowser.FileInUseError}")); + return false; + } + File.Copy(oldName, newName, overwrite); + } + } catch (Exception e) { + if (isDirectory) { + MessageService.ShowError(e, "Can't copy directory " + oldName); + } else { + MessageService.ShowError(e, "Can't copy file " + oldName); + } + return false; + } + } + OnFileCopied(new FileRenameEventArgs(oldName, newName, isDirectory)); + return true; + } + /// /// Opens the specified file and jumps to the specified file position. /// Warning: Unlike parser coordinates, line and column are 0-based. @@ -443,7 +488,7 @@ namespace ICSharpCode.SharpDevelop } #region Event Handlers - + static void OnFileRemoved(FileEventArgs e) { if (FileRemoved != null) { @@ -471,10 +516,23 @@ namespace ICSharpCode.SharpDevelop } } + static void OnFileCopied(FileRenameEventArgs e) + { + if (FileCopied != null) { + FileCopied(null, e); + } + } + + static void OnFileCopying(FileRenamingEventArgs e) { + if (FileCopying != null) { + FileCopying(null, e); + } + } + #endregion Event Handlers #region Static event firing methods - + /// /// Fires the event handlers for a file being created. /// @@ -516,12 +574,15 @@ namespace ICSharpCode.SharpDevelop #endregion Static event firing methods #region Events - + public static event EventHandler FileCreated; public static event EventHandler FileRenaming; public static event EventHandler FileRenamed; + public static event EventHandler FileCopying; + public static event EventHandler FileCopied; + public static event EventHandler FileRemoving; public static event EventHandler FileRemoved;