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();
}