diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin index 8162137c74..a280d0ff4a 100644 --- a/AddIns/ICSharpCode.SharpDevelop.addin +++ b/AddIns/ICSharpCode.SharpDevelop.addin @@ -20,6 +20,8 @@ + + @@ -29,6 +31,7 @@ + @@ -203,23 +206,25 @@ class = "ICSharpCode.SharpDevelop.Project.Commands.Clean"/> - - - - - - - + + + + + + + + + --> - - - - - - - - + + + + + + + + + + + + + diff --git a/src/Main/Base/Project/Src/Commands/FileCommands.cs b/src/Main/Base/Project/Src/Commands/FileCommands.cs index 14c5ce50aa..cdd65133a6 100644 --- a/src/Main/Base/Project/Src/Commands/FileCommands.cs +++ b/src/Main/Base/Project/Src/Commands/FileCommands.cs @@ -22,17 +22,26 @@ namespace ICSharpCode.SharpDevelop.Commands { public override void Run() { - if (ProjectBrowserPad.Instance.CurrentProject != null) { - int result = MessageService.ShowCustomDialog("${res:Dialog.NewFile.AddToProjectQuestionTitle}", - "${res:Dialog.NewFile.AddToProjectQuestion}", - "${res:Dialog.NewFile.AddToProjectQuestionProject}", - "${res:Dialog.NewFile.AddToProjectQuestionStandalone}"); - if (result == 0) { - ProjectBrowserPad.Instance.CurrentProject.AddNewItemsToProject(); - return; - } else if (result == -1) { - return; + ProjectNode node = ProjectBrowserPad.Instance.CurrentProject; + if (node != null) { + if (node.Project.ReadOnly) + { + MessageService.ShowWarningFormatted("${res:Dialog.NewFile.ReadOnlyProjectWarning}", node.Project.FileName); } + else + { + int result = MessageService.ShowCustomDialog("${res:Dialog.NewFile.AddToProjectQuestionTitle}", + "${res:Dialog.NewFile.AddToProjectQuestion}", + "${res:Dialog.NewFile.AddToProjectQuestionProject}", + "${res:Dialog.NewFile.AddToProjectQuestionStandalone}"); + if (result == 0) { + node.AddNewItemsToProject(); + return; + } else if (result == -1) { + return; + } + } + } using (NewFileDialog nfd = new NewFileDialog(null)) { nfd.Owner = WorkbenchSingleton.MainForm; diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs index f19ef0c746..94f5ee14dc 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs @@ -49,10 +49,16 @@ namespace ICSharpCode.SharpDevelop.Project { sortOrder = 1; + + this.ContextmenuAddinTreePath = "/SharpDevelop/Pads/ProjectBrowser/ContextMenu/ProjectNode"; this.project = project; Text = project.Name; + if (project.ReadOnly) { + Text += StringParser.Parse(" (${res:Global.ReadOnly})"); + } + autoClearNodes = false; if (project is MissingProject) { diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionNode.cs index d605bb6f97..5350c04a12 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionNode.cs @@ -73,6 +73,9 @@ namespace ICSharpCode.SharpDevelop.Project void UpdateText() { Text = ResourceService.GetString("ICSharpCode.SharpDevelop.Commands.ProjectBrowser.SolutionNodeText") + " " + solution.Name; + if (Solution.ReadOnly) { + Text += StringParser.Parse(" (${res:Global.ReadOnly})"); + } } public void AddItem(string fileName) diff --git a/src/Main/Base/Project/Src/Internal/ConditionEvaluators/ProjectActiveEvaluator.cs b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/ProjectActiveEvaluator.cs index 2c834af7fd..6da3e5761b 100644 --- a/src/Main/Base/Project/Src/Internal/ConditionEvaluators/ProjectActiveEvaluator.cs +++ b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/ProjectActiveEvaluator.cs @@ -41,5 +41,4 @@ namespace ICSharpCode.SharpDevelop return project != null && project.Language == activeproject; } } - } diff --git a/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableProjectEvaluator.cs b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableProjectEvaluator.cs new file mode 100644 index 0000000000..4c5b502baf --- /dev/null +++ b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableProjectEvaluator.cs @@ -0,0 +1,26 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop +{ + /// + /// Tests if the caller project is writable. If caller is not an IProject it tests + /// Project.CurrentProject. + /// + public class WriteableProjectConditionEvaluator : IConditionEvaluator + { + public bool IsValid(object caller, Condition condition) + { + IProject project = (caller as IProject) ?? ProjectService.CurrentProject; + return !project.ReadOnly; + } + } +} diff --git a/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableSolutionEvaluator.cs b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableSolutionEvaluator.cs new file mode 100644 index 0000000000..4e12c13239 --- /dev/null +++ b/src/Main/Base/Project/Src/Internal/ConditionEvaluators/WriteableSolutionEvaluator.cs @@ -0,0 +1,25 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop +{ + /// + /// Description of WriteableSolutionEvaluator. + /// + public class WriteableSolutionConditionEvaluator : IConditionEvaluator + { + public bool IsValid(object caller, Condition condition) + { + Solution solution = ProjectService.OpenSolution; + return (solution != null && !solution.ReadOnly); + } + } +} diff --git a/src/Main/Base/Project/Src/Project/AbstractProject.cs b/src/Main/Base/Project/Src/Project/AbstractProject.cs index c75e0144d3..31fc89609a 100644 --- a/src/Main/Base/Project/Src/Project/AbstractProject.cs +++ b/src/Main/Base/Project/Src/Project/AbstractProject.cs @@ -123,6 +123,18 @@ namespace ICSharpCode.SharpDevelop.Project } } + /// + /// True if the file that contains the project is readonly. + /// + [ReadOnly(true)] + public bool ReadOnly { + get + { + FileAttributes attributes = File.GetAttributes(FileName); + return ((FileAttributes.ReadOnly & attributes) == FileAttributes.ReadOnly); + } + } + /// /// Gets the directory of the project file. /// This is equivalent to Path.GetDirectoryName(project.FileName); diff --git a/src/Main/Base/Project/Src/Project/IProject.cs b/src/Main/Base/Project/Src/Project/IProject.cs index a1da7d67b0..570190a090 100644 --- a/src/Main/Base/Project/Src/Project/IProject.cs +++ b/src/Main/Base/Project/Src/Project/IProject.cs @@ -106,6 +106,19 @@ namespace ICSharpCode.SharpDevelop.Project get; } + /// + /// + /// True if the project is readonly. For project based files this means + /// the project file has the readonly attribute set. For solution folder + /// based projects this means that the sln file containing the project + /// has the readonly attribute set. + /// + /// This member is thread-safe. + /// + bool ReadOnly { + get; + } + #region MSBuild properties used inside SharpDevelop base /// /// Gets/Sets the assembly name of the assembly created when building this project. diff --git a/src/Main/Base/Project/Src/Project/Solution/Solution.cs b/src/Main/Base/Project/Src/Project/Solution/Solution.cs index 8ae733b856..a242f40dec 100644 --- a/src/Main/Base/Project/Src/Project/Solution/Solution.cs +++ b/src/Main/Base/Project/Src/Project/Solution/Solution.cs @@ -12,7 +12,7 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using SearchAndReplace; + using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; using MSBuild = Microsoft.Build.BuildEngine; @@ -36,8 +36,6 @@ namespace ICSharpCode.SharpDevelop.Project string fileName = String.Empty; - bool readOnly = false; - MSBuild.Engine buildEngine = MSBuildInternals.CreateEngine(); public Solution() @@ -211,10 +209,14 @@ namespace ICSharpCode.SharpDevelop.Project } } - /// Property to determine if the solution is readonly. + /// Returns true if the solution is readonly. [Browsable(false)] public bool ReadOnly { - get { return readOnly; } + get + { + FileAttributes attributes = File.GetAttributes(fileName); + return ((FileAttributes.ReadOnly & attributes) == FileAttributes.ReadOnly); + } } #endregion @@ -252,24 +254,17 @@ namespace ICSharpCode.SharpDevelop.Project Save(fileName); return; } catch (IOException ex) { - MessageService.ShowError("Could not save " + fileName + ":\n" + ex.Message); + MessageService.ShowErrorFormatted("${res:SharpDevelop.Solution.CannotSave.IOException}", fileName, ex.Message); } catch (UnauthorizedAccessException ex) { FileAttributes attributes = File.GetAttributes(fileName); if ((FileAttributes.ReadOnly & attributes) == FileAttributes.ReadOnly) { - bool attemptOverwrite = MessageService.AskQuestionFormatted( - "Solution file {0} is marked readonly. Attempt to save anyway?", - new string [] {fileName}); - if (attemptOverwrite) { - try { - attributes &= ~FileAttributes.ReadOnly; - File.SetAttributes(fileName, attributes); - Save(fileName); - return; - } catch { /* If something screws up shows the error */ } - } + MessageService.ShowErrorFormatted("${res:SharpDevelop.Solution.CannotSave.ReadOnly}", fileName); + } + else + { + MessageService.ShowErrorFormatted + ("${res:SharpDevelop.Solution.CannotSave.UnauthorizedAccessException}", fileName, ex.Message); } - this.readOnly = true; - MessageService.ShowError("Could not save " + fileName + ":\n" + ex.Message + "\n\nEnsure the file is writable."); } } @@ -502,8 +497,8 @@ namespace ICSharpCode.SharpDevelop.Project } } } - - if (newSolution.FixSolutionConfiguration(newSolution.Projects) || needsConversion) { + + if (!newSolution.ReadOnly && (newSolution.FixSolutionConfiguration(newSolution.Projects) || needsConversion)) { // save in new format newSolution.Save(); }