Browse Source

Add IPropertyService.LoadExtraProperties + SaveExtraProperties

Add 'IncludeHidden' option for IFileSystem.GetFiles() so that it has the same functionality as FileUtility.SearchFiles()
pull/59/merge
Daniel Grunwald 12 years ago
parent
commit
befea66cf0
  1. 23
      doc/technotes/Versioning.html
  2. 2
      src/AddIns/Analysis/CodeCoverage/Test/Utils/MockFileSystem.cs
  3. 23
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
  4. 2
      src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockFileSystem.cs
  5. 33
      src/Main/Base/Project/Services/IFileSystem.cs
  6. 4
      src/Main/Base/Project/Util/ChrootFileSystem.cs
  7. 12
      src/Main/Base/Project/Util/EmbeddedResourceFileSystem.cs
  8. 10
      src/Main/Base/Project/Workbench/IWorkbench.cs
  9. 62
      src/Main/Core/Project/Src/AddInTree/CoreStartup.cs
  10. 2
      src/Main/Core/Project/Src/AddInTree/IAddInTree.cs
  11. 19
      src/Main/Core/Project/Src/Services/PropertyService/IPropertyService.cs
  12. 4
      src/Main/Core/Project/Src/Services/PropertyService/Properties.cs
  13. 87
      src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs
  14. 6
      src/Main/SharpDevelop/Parser/ParserService.cs
  15. 30
      src/Main/SharpDevelop/Project/Solution.cs
  16. 25
      src/Main/SharpDevelop/Sda/CallHelper.cs
  17. 6
      src/Main/SharpDevelop/Services/FileSystem.cs
  18. 101
      src/Main/SharpDevelop/Services/PropertyService.cs
  19. 1
      src/Main/SharpDevelop/SharpDevelop.csproj
  20. 4
      src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs
  21. 2
      src/Main/SharpDevelop/Templates/TemplateService.cs
  22. 2
      src/Main/SharpDevelop/Workbench/DisplayBinding/DisplayBindingService.cs
  23. 14
      src/Main/SharpDevelop/Workbench/FileService.cs
  24. 4
      src/Main/SharpDevelop/Workbench/LayoutConfiguration.cs
  25. 6
      src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
  26. 6
      src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

23
doc/technotes/Versioning.html

@ -13,15 +13,14 @@
<P>The assemblyInfo.cs files are updated by the tool <P>The assemblyInfo.cs files are updated by the tool
&quot;UpdateAssemblyInfo&quot;. UpdateAssemblyInfo &quot;UpdateAssemblyInfo&quot;. UpdateAssemblyInfo
runs as pre-compile target and always sets the number in GlobalAssemblyInfo.cs runs as pre-compile target and always sets the number in GlobalAssemblyInfo.cs
to the subversion revision number. That number is displayed to the number of commits since a hard-coded start commit (<code>const string BaseCommit</code>). That number is displayed
in the splash screen, error dialog and about dialog. in the splash screen, error dialog and about dialog.
It is also used as assembly version. It is also used as assembly version.
</P> </P>
<p> <p>
The revision number is retrieved by running a function in NSvn.Core.dll equivalent to "svn info" The revision number is retrieved by running "git rev-list" and counting the number of output lines.
in the "src" folder. When this doesn't work (e.g. in an exported tree like the source code download on the build server; or git not present in PATH),
When this doesn't work (e.g. in an exported tree like the source code download on the build server), the the content of the file src/REVISION is used as revision number.
content of the file src/REVISION is used as revision number.
When even this fails, the revision '0' is used. When even this fails, the revision '0' is used.
</p> </p>
<H2>Publisher Policy</H2> <H2>Publisher Policy</H2>
@ -39,7 +38,7 @@ would want to reference.
</P> </P>
<P>The binding redirects always redirect requests of a version in the range <P>The binding redirects always redirect requests of a version in the range
from some past version containing large breaking changes to the current version. from some past version containing large breaking changes to the current version.
We will not do such changes anymore after the first release candidate of a SharpDevelop version, We try to avoid such changes after the first release candidate of a SharpDevelop version,
so after the release of SharpDevelop x.y RC1, all future SharpDevelop x.y.*.* versions will be so after the release of SharpDevelop x.y RC1, all future SharpDevelop x.y.*.* versions will be
in large parts binary compatible. in large parts binary compatible.
<br> <br>
@ -51,5 +50,17 @@ compile it against the oldest SharpDevelop version you want your AddIn to run wi
An AddIn compiled against 2.1.0.1800 will run with 2.1.0.1801 (and hopefully even with 2.1.23.45678), An AddIn compiled against 2.1.0.1800 will run with 2.1.0.1801 (and hopefully even with 2.1.23.45678),
but an AddIn compiled against 2.1.0.1801 will fail to load in SharpDevelop 2.1.0.1800. but an AddIn compiled against 2.1.0.1801 will fail to load in SharpDevelop 2.1.0.1800.
</P> </P>
<P>
Additionally, your AddIn should include a <code>&lt;Dependency&gt;</code> in its
.addin file to indicate which SharpDevelop version it is intended for.
This way, users trying to install the AddIn in an incompatible SharpDevelop version will be warned about the
incompatibility, instead of getting an obscure error message.
</P>
<pre>
&lt;Manifest>
&lt;Identity name = "YourAddInName"/>
&lt;Dependency addin="SharpDevelop" version="5.0"/>
&lt;/Manifest>
</pre>
</BODY> </BODY>
</HTML> </HTML>

2
src/AddIns/Analysis/CodeCoverage/Test/Utils/MockFileSystem.cs

@ -63,7 +63,7 @@ namespace ICSharpCode.CodeCoverage.Tests.Utils
throw new NotImplementedException(); throw new NotImplementedException();
} }
System.Collections.Generic.IEnumerable<FileName> IReadOnlyFileSystem.GetFiles(DirectoryName directory, string searchPattern, SearchOption searchOption) System.Collections.Generic.IEnumerable<FileName> IReadOnlyFileSystem.GetFiles(DirectoryName directory, string searchPattern, DirectorySearchOptions searchOptions)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

23
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs

@ -65,34 +65,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
panel.Children.Add(tree); panel.Children.Add(tree);
// ProjectService.SolutionLoaded += delegate { LoadNodes(); }; // ProjectService.SolutionLoaded += delegate { LoadNodes(); };
// ProjectService.SolutionClosing += delegate { SaveNodes(); }; // SD.ProjectService.CurrentSolution.PreferencesSaving += delegate { SaveNodes(); };
// LoadNodes(); // LoadNodes();
WindowsDebugger.RefreshingPads += RefreshPad; WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad(); RefreshPad();
} }
// void LoadNodes()
// {
// if (ProjectService.OpenSolution != null) {
// var props = ProjectService.OpenSolution.Preferences.NestedProperties("Watches");
// foreach (var key in props.Keys) {
// this.Items.Add(new TreeNode(props.Get(key, ""), () => null).ToSharpTreeNode());
// }
// }
// }
//
// void SaveNodes()
// {
// if (ProjectService.OpenSolution != null) {
// var props = new Properties();
// ProjectService.OpenSolution.Preferences.SetNestedProperties("Watches", props);
// foreach(var node in this.Items.OfType<TreeNode>()) {
// props.Set(node.Name, node.EvalEnabled);
// }
// }
// }
public void AddWatch(string expression = null, bool focus = false) public void AddWatch(string expression = null, bool focus = false)
{ {
var node = MakeNode(expression); var node = MakeNode(expression);

2
src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockFileSystem.cs

@ -36,7 +36,7 @@ namespace XmlEditor.Tests.Utils
directoryFiles.Add(DirectoryName.Create(folder), FileName.Create(file)); directoryFiles.Add(DirectoryName.Create(folder), FileName.Create(file));
} }
public IEnumerable<FileName> GetFiles(DirectoryName folder, string extension, SearchOption searchOption = SearchOption.TopDirectoryOnly) public IEnumerable<FileName> GetFiles(DirectoryName folder, string extension, DirectorySearchOptions searchOptions = DirectorySearchOptions.None)
{ {
searchedFolders.Add(folder); searchedFolders.Add(folder);
searchedForFileExtensions.Add(extension); searchedForFileExtensions.Add(extension);

33
src/Main/Base/Project/Services/IFileSystem.cs

@ -43,7 +43,36 @@ namespace ICSharpCode.SharpDevelop
/// <inheritdoc cref="System.IO.File.OpenText"/> /// <inheritdoc cref="System.IO.File.OpenText"/>
TextReader OpenText(FileName fileName); TextReader OpenText(FileName fileName);
IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly); /// <summary>
/// Retrieves the list of files in the specified directory.
/// </summary>
/// <param name="directory">The directory to search in.</param>
/// <param name="searchPattern">The search pattern used to filter the result list.
/// For example: "*.exe".
/// This method does not use 8.3 patterns; so "*.htm" will not match ".html".</param>
/// <param name="searchOptions">
/// Options that influence the search.
/// </param>
/// <returns>An enumerable that iterates through the directory contents</returns>
/// <exception cref="IOExcption">The directory does not exist / access is denied.</exception>
IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern = "*", DirectorySearchOptions searchOptions = DirectorySearchOptions.None);
}
[Flags]
public enum DirectorySearchOptions
{
/// <summary>
/// Search top directory only; skip hidden files.
/// </summary>
None = 0,
/// <summary>
/// Include hidden files/subdirectories.
/// </summary>
IncludeHidden = 1,
/// <summary>
/// Perform a recurive search into subdirectories.
/// </summary>
IncludeSubdirectories = 2
} }
public static class FileSystemExtensions public static class FileSystemExtensions
@ -98,7 +127,7 @@ namespace ICSharpCode.SharpDevelop
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
IEnumerable<FileName> IReadOnlyFileSystem.GetFiles(DirectoryName directory, string searchPattern, SearchOption searchOption) IEnumerable<FileName> IReadOnlyFileSystem.GetFiles(DirectoryName directory, string searchPattern, DirectorySearchOptions searchOptions)
{ {
return Enumerable.Empty<FileName>(); return Enumerable.Empty<FileName>();
} }

4
src/Main/Base/Project/Util/ChrootFileSystem.cs

@ -47,9 +47,9 @@ namespace ICSharpCode.SharpDevelop
return fileSystem.OpenText(basePath.Combine(fileName)); return fileSystem.OpenText(basePath.Combine(fileName));
} }
public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, SearchOption searchOption) public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, DirectorySearchOptions searchOptions)
{ {
return fileSystem.GetFiles(basePath.Combine(directory), searchPattern, searchOption) return fileSystem.GetFiles(basePath.Combine(directory), searchPattern, searchOptions)
.Select(file => basePath.GetRelativePath(file)); .Select(file => basePath.GetRelativePath(file));
} }
} }

12
src/Main/Base/Project/Util/EmbeddedResourceFileSystem.cs

@ -74,10 +74,16 @@ namespace ICSharpCode.SharpDevelop
return new StreamReader(OpenRead(fileName)); return new StreamReader(OpenRead(fileName));
} }
public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, SearchOption searchOption) public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, DirectorySearchOptions searchOptions)
{ {
return fileNames.Value.Where(fn => FileUtility.IsBaseDirectory(directory, fn) return fileNames.Value.Where(delegate(FileName fn) {
&& FileUtility.MatchesPattern(fn.GetFileName(), searchPattern)); if (!FileUtility.MatchesPattern(fn.GetFileName(), searchPattern))
return false;
if ((searchOptions & DirectorySearchOptions.IncludeSubdirectories) != 0)
return FileUtility.IsBaseDirectory(directory, fn);
else
return directory.Equals(fn.GetParentDirectory());
});
} }
} }
} }

10
src/Main/Base/Project/Workbench/IWorkbench.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// This is the basic interface to the workspace. /// This is the basic interface to the workspace.
/// </summary> /// </summary>
[SDService("SD.Workbench")] [SDService("SD.Workbench")]
public interface IWorkbench : IMementoCapable public interface IWorkbench
{ {
/// <summary> /// <summary>
/// The main window as IWin32Window. /// The main window as IWin32Window.
@ -34,14 +34,6 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary> /// </summary>
bool FullScreen { get; set; } bool FullScreen { get; set; }
/// <summary>
/// The title shown in the title bar.
/// </summary>
string Title {
get;
set;
}
/// <summary> /// <summary>
/// A collection in which all opened view contents (including all secondary view contents) are saved. /// A collection in which all opened view contents (including all secondary view contents) are saved.
/// </summary> /// </summary>

62
src/Main/Core/Project/Src/AddInTree/CoreStartup.cs

@ -32,58 +32,8 @@ namespace ICSharpCode.Core
List<string> addInFiles = new List<string>(); List<string> addInFiles = new List<string>();
List<string> disabledAddIns = new List<string>(); List<string> disabledAddIns = new List<string>();
bool externalAddInsConfigured; bool externalAddInsConfigured;
string propertiesName;
string configDirectory;
string dataDirectory;
string applicationName;
AddInTreeImpl addInTree; AddInTreeImpl addInTree;
string applicationName;
/// <summary>
/// Sets the name used for the properties (only name, without path or extension).
/// Must be set before StartCoreServices() is called.
/// </summary>
public string PropertiesName {
get {
return propertiesName;
}
set {
if (value == null || value.Length == 0)
throw new ArgumentNullException("value");
propertiesName = value;
}
}
/// <summary>
/// Sets the directory name used for the property service.
/// Must be set before StartCoreServices() is called.
/// Use null to use the default path "%ApplicationData%\%ApplicationName%",
/// where %ApplicationData% is the system setting for
/// "c:\documents and settings\username\application data"
/// and %ApplicationName% is the application name you used in the
/// CoreStartup constructor call.
/// </summary>
public string ConfigDirectory {
get {
return configDirectory;
}
set {
configDirectory = value;
}
}
/// <summary>
/// Sets the data directory used to load resources.
/// Must be set before StartCoreServices() is called.
/// Use null to use the default path "ApplicationRootPath\data".
/// </summary>
public string DataDirectory {
get {
return dataDirectory;
}
set {
dataDirectory = value;
}
}
/// <summary> /// <summary>
/// Creates a new CoreStartup instance. /// Creates a new CoreStartup instance.
@ -98,7 +48,6 @@ namespace ICSharpCode.Core
if (applicationName == null) if (applicationName == null)
throw new ArgumentNullException("applicationName"); throw new ArgumentNullException("applicationName");
this.applicationName = applicationName; this.applicationName = applicationName;
propertiesName = applicationName + "Properties";
} }
/// <summary> /// <summary>
@ -198,16 +147,9 @@ namespace ICSharpCode.Core
/// Starts the core services. /// Starts the core services.
/// This initializes the PropertyService and ResourceService. /// This initializes the PropertyService and ResourceService.
/// </summary> /// </summary>
public void StartCoreServices() public void StartCoreServices(IPropertyService propertyService)
{ {
if (configDirectory == null)
configDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
applicationName);
var container = ServiceSingleton.GetRequiredService<IServiceContainer>(); var container = ServiceSingleton.GetRequiredService<IServiceContainer>();
var propertyService = new PropertyServiceImpl(
DirectoryName.Create(configDirectory),
DirectoryName.Create(dataDirectory ?? Path.Combine(FileUtility.ApplicationRootPath, "data")),
propertiesName);
var applicationStateInfoService = new ApplicationStateInfoService(); var applicationStateInfoService = new ApplicationStateInfoService();
addInTree = new AddInTreeImpl(applicationStateInfoService); addInTree = new AddInTreeImpl(applicationStateInfoService);

2
src/Main/Core/Project/Src/AddInTree/IAddInTree.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Core
/// <param name="path">A path in the addin tree.</param> /// <param name="path">A path in the addin tree.</param>
/// <param name="parameter">A parameter that gets passed into the doozer and condition evaluators.</param> /// <param name="parameter">A parameter that gets passed into the doozer and condition evaluators.</param>
/// <param name="throwOnNotFound">If true, throws a <see cref="TreePathNotFoundException"/> /// <param name="throwOnNotFound">If true, throws a <see cref="TreePathNotFoundException"/>
/// if the path is not found. If false, an empty ArrayList is returned when the /// if the path is not found. If false, an empty list is returned when the
/// path is not found.</param> /// path is not found.</param>
IReadOnlyList<T> BuildItems<T>(string path, object parameter, bool throwOnNotFound = true); IReadOnlyList<T> BuildItems<T>(string path, object parameter, bool throwOnNotFound = true);

19
src/Main/Core/Project/Src/Services/PropertyService/IPropertyService.cs

@ -17,13 +17,11 @@ namespace ICSharpCode.Core
/// <summary> /// <summary>
/// Gets the configuration directory. (usually "%ApplicationData%\%ApplicationName%") /// Gets the configuration directory. (usually "%ApplicationData%\%ApplicationName%")
/// </summary> /// </summary>
/// <seealso cref="CoreStartup.ConfigDirectory"/>
DirectoryName ConfigDirectory { get; } DirectoryName ConfigDirectory { get; }
/// <summary> /// <summary>
/// Gets the data directory (usually "ApplicationRootPath\data") /// Gets the data directory (usually "ApplicationRootPath\data")
/// </summary> /// </summary>
/// <seealso cref="CoreStartup.DataDirectory"/>
DirectoryName DataDirectory { get; } DirectoryName DataDirectory { get; }
/// <summary> /// <summary>
@ -56,8 +54,23 @@ namespace ICSharpCode.Core
void Remove(string key); void Remove(string key);
/// <summary> /// <summary>
/// Saves the properties to disk. /// Saves the main properties to disk.
/// </summary> /// </summary>
void Save(); void Save();
/// <summary>
/// Loads extra properties that are not part of the main properties container.
/// Unlike <see cref="NestedProperties"/>, multiple calls to <see cref="LoadExtraProperties"/>
/// will return different instances, as the properties are re-loaded from disk every time.
/// To save the properties, you need to call <see cref="SaveExtraProperties"/>.
/// </summary>
/// <returns>Properties container that was loaded; or an empty properties container
/// if no container with the specified key exists.</returns>
Properties LoadExtraProperties(string key);
/// <summary>
/// Saves extra properties that are not part of the main properties container.
/// </summary>
void SaveExtraProperties(string key, Properties p);
} }
} }

4
src/Main/Core/Project/Src/Services/PropertyService/Properties.cs

@ -190,7 +190,7 @@ namespace ICSharpCode.Core
/// <summary> /// <summary>
/// Sets a single element in this Properties-container. /// Sets a single element in this Properties-container.
/// The element will be serialized using a TypeConverter if possible, or DataContractSerializer otherwise. /// The element will be serialized using a TypeConverter if possible, or XAML serializer otherwise.
/// </summary> /// </summary>
/// <remarks>Setting a key to <c>null</c> has the same effect as calling <see cref="Remove"/>.</remarks> /// <remarks>Setting a key to <c>null</c> has the same effect as calling <see cref="Remove"/>.</remarks>
public void Set<T>(string key, T value) public void Set<T>(string key, T value)
@ -255,7 +255,7 @@ namespace ICSharpCode.Core
/// <summary> /// <summary>
/// Sets a list of elements in this Properties-container. /// Sets a list of elements in this Properties-container.
/// The elements will be serialized using a TypeConverter if possible, or DataContractSerializer otherwise. /// The elements will be serialized using a TypeConverter if possible, or XAML serializer otherwise.
/// </summary> /// </summary>
/// <remarks>Passing <c>null</c> or an empty list as value has the same effect as calling <see cref="Remove"/>.</remarks> /// <remarks>Passing <c>null</c> or an empty list as value has the same effect as calling <see cref="Remove"/>.</remarks>
public void SetList<T>(string key, IEnumerable<T> value) public void SetList<T>(string key, IEnumerable<T> value)

87
src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs

@ -9,17 +9,13 @@ using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Xml; using System.Xml;
using ICSharpCode.Core;
namespace ICSharpCode.Core namespace ICSharpCode.Core
{ {
public sealed class PropertyServiceImpl : IPropertyService public class PropertyServiceImpl : IPropertyService
{ {
string propertyFileName; readonly Properties properties;
DirectoryName configDirectory;
DirectoryName dataDirectory;
Properties properties;
/// <summary> /// <summary>
/// Initializes the service for unit-testing (reset properties to an empty property container). /// Initializes the service for unit-testing (reset properties to an empty property container).
@ -29,25 +25,23 @@ namespace ICSharpCode.Core
{ {
properties = new Properties(); properties = new Properties();
} }
public PropertyServiceImpl(DirectoryName configDirectory, DirectoryName dataDirectory, string propertiesName) public PropertyServiceImpl(Properties properties)
{ {
this.configDirectory = configDirectory; if (properties == null)
this.dataDirectory = dataDirectory; throw new ArgumentNullException("properties");
this.propertyFileName = propertiesName + ".xml"; this.properties = properties;
Directory.CreateDirectory(configDirectory);
LoadPropertiesFromStream(FileName.Create(Path.Combine(configDirectory, propertyFileName)));
} }
public DirectoryName ConfigDirectory { public virtual DirectoryName ConfigDirectory {
get { get {
return configDirectory; throw new NotImplementedException();
} }
} }
public DirectoryName DataDirectory { public virtual DirectoryName DataDirectory {
get { get {
return dataDirectory; throw new NotImplementedException();
} }
} }
@ -105,50 +99,6 @@ namespace ICSharpCode.Core
properties.Remove(key); properties.Remove(key);
} }
bool LoadPropertiesFromStream(FileName fileName)
{
if (!File.Exists(fileName)) {
properties = new Properties();
return false;
}
try {
using (LockPropertyFile()) {
properties = Properties.Load(fileName);
return true;
}
} catch (XmlException ex) {
var msgService = ServiceSingleton.GetRequiredService<IMessageService>();
msgService.ShowError("Error loading properties: " + ex.Message + "\nSettings have been restored to default values.");
}
properties = new Properties();
return false;
}
public void Save()
{
if (string.IsNullOrEmpty(configDirectory) || string.IsNullOrEmpty(propertyFileName))
throw new InvalidOperationException("No file name was specified on service creation");
var fileName = FileName.Create(Path.Combine(configDirectory, propertyFileName));
using (LockPropertyFile()) {
properties.Save(fileName);
}
}
/// <summary>
/// Acquires an exclusive lock on the properties file so that it can be opened safely.
/// </summary>
public IDisposable LockPropertyFile()
{
Mutex mutex = new Mutex(false, "PropertyServiceSave-30F32619-F92D-4BC0-BF49-AA18BF4AC313");
mutex.WaitOne();
return new CallbackOnDispose(
delegate {
mutex.ReleaseMutex();
mutex.Close();
});
}
public event PropertyChangedEventHandler PropertyChanged { public event PropertyChangedEventHandler PropertyChanged {
add { properties.PropertyChanged += value; } add { properties.PropertyChanged += value; }
remove { properties.PropertyChanged -= value; } remove { properties.PropertyChanged -= value; }
@ -157,5 +107,18 @@ namespace ICSharpCode.Core
public Properties MainPropertiesContainer { public Properties MainPropertiesContainer {
get { return properties; } get { return properties; }
} }
public virtual void Save()
{
}
public virtual Properties LoadExtraProperties(string key)
{
return new Properties();
}
public virtual void SaveExtraProperties(string key, Properties p)
{
}
} }
} }

6
src/Main/SharpDevelop/Parser/ParserService.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.SharpDevelop.Parser
SD.MainThread.VerifyAccess(); SD.MainThread.VerifyAccess();
if (!value.SequenceEqual(taskListTokens)) { if (!value.SequenceEqual(taskListTokens)) {
taskListTokens = value.ToArray(); taskListTokens = value.ToArray();
PropertyService.SetList("SharpDevelop.TaskListTokens", taskListTokens); SD.PropertyService.SetList("SharpDevelop.TaskListTokens", taskListTokens);
// TODO: trigger reparse? // TODO: trigger reparse?
} }
} }
@ -75,8 +75,8 @@ namespace ICSharpCode.SharpDevelop.Parser
static IReadOnlyList<string> LoadTaskListTokens() static IReadOnlyList<string> LoadTaskListTokens()
{ {
if (PropertyService.Contains("SharpDevelop.TaskListTokens")) if (SD.PropertyService.Contains("SharpDevelop.TaskListTokens"))
return PropertyService.GetList<string>("SharpDevelop.TaskListTokens").ToArray(); return SD.PropertyService.GetList<string>("SharpDevelop.TaskListTokens");
else else
return new string[] { "HACK", "TODO", "UNDONE", "FIXME" }; return new string[] { "HACK", "TODO", "UNDONE", "FIXME" };
} }

30
src/Main/SharpDevelop/Project/Solution.cs

@ -200,7 +200,7 @@ namespace ICSharpCode.SharpDevelop.Project
get { return globalSections; } get { return globalSections; }
} }
void OnProjectConfigurationMappingChanged(object sender, EventArgs e) void OnProjectConfigurationMappingChanged(object sender, EventArgs e)
{ {
this.IsDirty = true; this.IsDirty = true;
} }
@ -235,26 +235,18 @@ namespace ICSharpCode.SharpDevelop.Project
get { return preferences; } get { return preferences; }
} }
static FileName GetPreferenceFileName(string projectFileName) string GetPreferencesKey()
{ {
string directory = Path.Combine(PropertyService.ConfigDirectory, "preferences"); return "solution:" + fileName.ToString().ToUpperInvariant();
return FileName.Create(Path.Combine(directory,
Path.GetFileName(projectFileName)
+ "." + projectFileName.ToUpperInvariant().GetStableHashCode().ToString("x")
+ ".xml"));
} }
internal void LoadPreferences() internal void LoadPreferences()
{ {
FileName preferencesFile = GetPreferenceFileName(fileName); try {
if (FileUtility.IsValidPath(preferencesFile) && File.Exists(preferencesFile)) { preferences = SD.PropertyService.LoadExtraProperties(GetPreferencesKey());
try { } catch (IOException) {
preferences = Properties.Load(preferencesFile); } catch (XmlException) {
} catch (IOException) { // ignore errors about inaccessible or malformed files
} catch (UnauthorizedAccessException) {
} catch (XmlException) {
// ignore errors about inaccessible or malformed files
}
} }
// Load active configuration from preferences // Load active configuration from preferences
CreateDefaultConfigurationsIfMissing(); CreateDefaultConfigurationsIfMissing();
@ -274,12 +266,10 @@ namespace ICSharpCode.SharpDevelop.Project
preferences.Set("ActiveConfiguration.Platform", activeConfiguration.Platform); preferences.Set("ActiveConfiguration.Platform", activeConfiguration.Platform);
PreferencesSaving(this, EventArgs.Empty); PreferencesSaving(this, EventArgs.Empty);
FileName preferencesFile = GetPreferenceFileName(fileName);
System.IO.Directory.CreateDirectory(preferencesFile.GetParentDirectory());
try { try {
preferences.Save(preferencesFile); SD.PropertyService.SaveExtraProperties(GetPreferencesKey(), preferences);
} catch (IOException) { } catch (IOException) {
} catch (UnauthorizedAccessException) { // ignore errors writing to extra properties
} }
} }
#endregion #endregion

25
src/Main/SharpDevelop/Sda/CallHelper.cs

@ -50,17 +50,28 @@ namespace ICSharpCode.SharpDevelop.Sda
this.useSharpDevelopErrorHandler = true; this.useSharpDevelopErrorHandler = true;
ExceptionBox.RegisterExceptionBoxForUnhandledExceptions(); ExceptionBox.RegisterExceptionBoxForUnhandledExceptions();
} }
startup.ConfigDirectory = properties.ConfigDirectory; string configDirectory = properties.ConfigDirectory;
startup.DataDirectory = properties.DataDirectory; string dataDirectory = properties.DataDirectory;
string propertiesName;
if (properties.PropertiesName != null) { if (properties.PropertiesName != null) {
startup.PropertiesName = properties.PropertiesName; propertiesName = properties.PropertiesName;
} else {
propertiesName = properties.ApplicationName + "Properties";
} }
if (properties.ApplicationRootPath != null) { if (properties.ApplicationRootPath != null) {
FileUtility.ApplicationRootPath = properties.ApplicationRootPath; FileUtility.ApplicationRootPath = properties.ApplicationRootPath;
} }
startup.StartCoreServices(); if (configDirectory == null)
configDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
properties.ApplicationName);
var propertyService = new PropertyService(
DirectoryName.Create(configDirectory),
DirectoryName.Create(dataDirectory ?? Path.Combine(FileUtility.ApplicationRootPath, "data")),
propertiesName);
startup.StartCoreServices(propertyService);
Assembly exe = Assembly.Load(properties.ResourceAssemblyName); Assembly exe = Assembly.Load(properties.ResourceAssemblyName);
SD.ResourceService.RegisterNeutralStrings(new ResourceManager("ICSharpCode.SharpDevelop.Resources.StringResources", exe)); SD.ResourceService.RegisterNeutralStrings(new ResourceManager("ICSharpCode.SharpDevelop.Resources.StringResources", exe));
SD.ResourceService.RegisterNeutralImages(new ResourceManager("ICSharpCode.SharpDevelop.Resources.BitmapResources", exe)); SD.ResourceService.RegisterNeutralImages(new ResourceManager("ICSharpCode.SharpDevelop.Resources.BitmapResources", exe));
@ -80,11 +91,11 @@ namespace ICSharpCode.SharpDevelop.Sda
} }
if (properties.AllowAddInConfigurationAndExternalAddIns) { if (properties.AllowAddInConfigurationAndExternalAddIns) {
startup.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml")); startup.ConfigureExternalAddIns(Path.Combine(configDirectory, "AddIns.xml"));
} }
if (properties.AllowUserAddIns) { if (properties.AllowUserAddIns) {
startup.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"), startup.ConfigureUserAddIns(Path.Combine(configDirectory, "AddInInstallTemp"),
Path.Combine(PropertyService.ConfigDirectory, "AddIns")); Path.Combine(configDirectory, "AddIns"));
} }
LoggingService.Info("Loading AddInTree..."); LoggingService.Info("Loading AddInTree...");

6
src/Main/SharpDevelop/Services/FileSystem.cs

@ -69,10 +69,12 @@ namespace ICSharpCode.SharpDevelop
} }
} }
public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, SearchOption searchOption) public IEnumerable<FileName> GetFiles(DirectoryName directory, string searchPattern, DirectorySearchOptions searchOptions)
{ {
try { try {
return Directory.EnumerateFiles(directory, searchPattern, searchOption).Select(FileName.Create); bool searchSubdirectories = (searchOptions & DirectorySearchOptions.IncludeSubdirectories) != 0;
bool ignoreHidden = (searchOptions & DirectorySearchOptions.IncludeHidden) == 0;
return FileUtility.LazySearchDirectory(directory, searchPattern, searchSubdirectories, ignoreHidden);
} catch (UnauthorizedAccessException ex) { } catch (UnauthorizedAccessException ex) {
throw new IOException(ex.Message, ex); throw new IOException(ex.Message, ex);
} }

101
src/Main/SharpDevelop/Services/PropertyService.cs

@ -0,0 +1,101 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Threading;
using System.Xml;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.SharpDevelop
{
class PropertyService : PropertyServiceImpl
{
DirectoryName dataDirectory;
DirectoryName configDirectory;
FileName propertiesFileName;
public PropertyService(DirectoryName configDirectory, DirectoryName dataDirectory, string propertiesName)
: base(LoadPropertiesFromStream(configDirectory.CombineFile(propertiesName + ".xml")))
{
this.dataDirectory = dataDirectory;
this.configDirectory = configDirectory;
propertiesFileName = configDirectory.CombineFile(propertiesName + ".xml");
}
public override DirectoryName ConfigDirectory {
get {
return configDirectory;
}
}
public override DirectoryName DataDirectory {
get {
return dataDirectory;
}
}
static Properties LoadPropertiesFromStream(FileName fileName)
{
if (!File.Exists(fileName)) {
return new Properties();
}
try {
using (LockPropertyFile()) {
return Properties.Load(fileName);
}
} catch (XmlException ex) {
SD.MessageService.ShowError("Error loading properties: " + ex.Message + "\nSettings have been restored to default values.");
} catch (IOException ex) {
SD.MessageService.ShowError("Error loading properties: " + ex.Message + "\nSettings have been restored to default values.");
}
return new Properties();
}
public override void Save()
{
using (LockPropertyFile()) {
this.MainPropertiesContainer.Save(propertiesFileName);
}
}
/// <summary>
/// Acquires an exclusive lock on the properties file so that it can be opened safely.
/// </summary>
static IDisposable LockPropertyFile()
{
Mutex mutex = new Mutex(false, "PropertyServiceSave-30F32619-F92D-4BC0-BF49-AA18BF4AC313");
mutex.WaitOne();
return new CallbackOnDispose(
delegate {
mutex.ReleaseMutex();
mutex.Close();
});
}
FileName GetExtraFileName(string key)
{
return configDirectory.CombineFile("preferences/" + key.GetStableHashCode().ToString("x8") + ".xml");
}
public override Properties LoadExtraProperties(string key)
{
var fileName = GetExtraFileName(key);
using (LockPropertyFile()) {
if (File.Exists(fileName))
return Properties.Load(fileName);
else
return new Properties();
}
}
public override void SaveExtraProperties(string key, Properties p)
{
var fileName = GetExtraFileName(key);
using (LockPropertyFile()) {
Directory.CreateDirectory(fileName.GetParentDirectory());
p.Save(fileName);
}
}
}
}

1
src/Main/SharpDevelop/SharpDevelop.csproj

@ -168,6 +168,7 @@
<Compile Include="Services\ClipboardWrapper.cs" /> <Compile Include="Services\ClipboardWrapper.cs" />
<Compile Include="Services\DispatcherMessageLoop.cs" /> <Compile Include="Services\DispatcherMessageLoop.cs" />
<Compile Include="Services\FileSystem.cs" /> <Compile Include="Services\FileSystem.cs" />
<Compile Include="Services\PropertyService.cs" />
<Compile Include="Services\UIService.cs" /> <Compile Include="Services\UIService.cs" />
<Compile Include="Startup\App.xaml.cs" /> <Compile Include="Startup\App.xaml.cs" />
<Compile Include="Startup\SharpDevelopMain.cs" /> <Compile Include="Startup\SharpDevelopMain.cs" />

4
src/Main/SharpDevelop/Templates/TemplateFileDoozer.cs

@ -50,8 +50,8 @@ namespace ICSharpCode.SharpDevelop.Templates
{ {
var fileSystem = GetFileSystem(args); var fileSystem = GetFileSystem(args);
var templates = new List<TemplateBase>(); var templates = new List<TemplateBase>();
var xpt = fileSystem.GetFiles(DirectoryName.Create("."), "*.xpt", SearchOption.AllDirectories); var xpt = fileSystem.GetFiles(DirectoryName.Create("."), "*.xpt", DirectorySearchOptions.IncludeSubdirectories);
var xft = fileSystem.GetFiles(DirectoryName.Create("."), "*.xft", SearchOption.AllDirectories); var xft = fileSystem.GetFiles(DirectoryName.Create("."), "*.xft", DirectorySearchOptions.IncludeSubdirectories);
foreach (var fileName in xpt.Concat(xft)) { foreach (var fileName in xpt.Concat(xft)) {
using (var stream = fileSystem.OpenRead(fileName)) { using (var stream = fileSystem.OpenRead(fileName)) {
var relFileSystem = new ReadOnlyChrootFileSystem(fileSystem, fileName.GetParentDirectory()); var relFileSystem = new ReadOnlyChrootFileSystem(fileSystem, fileName.GetParentDirectory());

2
src/Main/SharpDevelop/Templates/TemplateService.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.SharpDevelop.Templates
IReadOnlyList<TextTemplateGroup> LoadTextTemplates() IReadOnlyList<TextTemplateGroup> LoadTextTemplates()
{ {
var dir = PropertyService.DataDirectory.Combine(DirectoryName.Create("options/textlib")); var dir = SD.PropertyService.DataDirectory.CombineDirectory("options/textlib");
return SD.FileSystem.GetFiles(dir, "*.xml") return SD.FileSystem.GetFiles(dir, "*.xml")
.Select(file => TextTemplateGroup.Load(file)) .Select(file => TextTemplateGroup.Load(file))
.ToList(); .ToList();

2
src/Main/SharpDevelop/Workbench/DisplayBinding/DisplayBindingService.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
public DisplayBindingService() public DisplayBindingService()
{ {
bindings = AddInTree.BuildItems<DisplayBindingDescriptor>(displayBindingPath, null, true); bindings = AddInTree.BuildItems<DisplayBindingDescriptor>(displayBindingPath, null, true);
displayBindingServiceProperties = PropertyService.NestedProperties("DisplayBindingService"); displayBindingServiceProperties = SD.PropertyService.NestedProperties("DisplayBindingService");
foreach (var binding in displayBindingServiceProperties.GetList<ExternalProcessDisplayBinding>("ExternalProcesses")) { foreach (var binding in displayBindingServiceProperties.GetList<ExternalProcessDisplayBinding>("ExternalProcesses")) {
if (binding != null) { if (binding != null) {
AddExternalProcessDisplayBindingInternal(binding); AddExternalProcessDisplayBindingInternal(binding);

14
src/Main/SharpDevelop/Workbench/FileService.cs

@ -43,33 +43,33 @@ namespace ICSharpCode.SharpDevelop.Workbench
public IRecentOpen RecentOpen { public IRecentOpen RecentOpen {
get { get {
return LazyInitializer.EnsureInitialized( return LazyInitializer.EnsureInitialized(
ref recentOpen, () => new RecentOpen(PropertyService.NestedProperties("RecentOpen"))); ref recentOpen, () => new RecentOpen(SD.PropertyService.NestedProperties("RecentOpen")));
} }
} }
public bool DeleteToRecycleBin { public bool DeleteToRecycleBin {
get { get {
return PropertyService.Get("SharpDevelop.DeleteToRecycleBin", true); return SD.PropertyService.Get("SharpDevelop.DeleteToRecycleBin", true);
} }
set { set {
PropertyService.Set("SharpDevelop.DeleteToRecycleBin", value); SD.PropertyService.Set("SharpDevelop.DeleteToRecycleBin", value);
} }
} }
public bool SaveUsingTemporaryFile { public bool SaveUsingTemporaryFile {
get { get {
return PropertyService.Get("SharpDevelop.SaveUsingTemporaryFile", true); return SD.PropertyService.Get("SharpDevelop.SaveUsingTemporaryFile", true);
} }
set { set {
PropertyService.Set("SharpDevelop.SaveUsingTemporaryFile", value); SD.PropertyService.Set("SharpDevelop.SaveUsingTemporaryFile", value);
} }
} }
#endregion #endregion
#region DefaultFileEncoding #region DefaultFileEncoding
public int DefaultFileEncodingCodePage { public int DefaultFileEncodingCodePage {
get { return PropertyService.Get("SharpDevelop.DefaultFileEncoding", 65001); } get { return SD.PropertyService.Get("SharpDevelop.DefaultFileEncoding", 65001); }
set { PropertyService.Set("SharpDevelop.DefaultFileEncoding", value); } set { SD.PropertyService.Set("SharpDevelop.DefaultFileEncoding", value); }
} }
public Encoding DefaultFileEncoding { public Encoding DefaultFileEncoding {

4
src/Main/SharpDevelop/Workbench/LayoutConfiguration.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary> /// </summary>
public static string DataLayoutPath { public static string DataLayoutPath {
get { get {
return Path.Combine(PropertyService.DataDirectory, "layouts"); return Path.Combine(SD.PropertyService.DataDirectory, "layouts");
} }
} }
@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary> /// </summary>
public static string ConfigLayoutPath { public static string ConfigLayoutPath {
get { get {
return Path.Combine(PropertyService.ConfigDirectory, "layouts"); return Path.Combine(SD.PropertyService.ConfigDirectory, "layouts");
} }
} }

6
src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
Project.CustomToolsService.Initialize(); Project.CustomToolsService.Initialize();
workbench.Initialize(); workbench.Initialize();
workbench.SetMemento(PropertyService.NestedProperties(workbenchMemento)); workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento));
workbench.WorkbenchLayout = layout; workbench.WorkbenchLayout = layout;
var dlgMsgService = SD.MessageService as IDialogMessageService; var dlgMsgService = SD.MessageService as IDialogMessageService;
@ -111,7 +111,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
} }
// load previous solution // load previous solution
if (!didLoadSolutionOrFile && PropertyService.Get("SharpDevelop.LoadPrevProjectOnStartup", false)) { if (!didLoadSolutionOrFile && SD.PropertyService.Get("SharpDevelop.LoadPrevProjectOnStartup", false)) {
if (SD.FileService.RecentOpen.RecentProjects.Count > 0) { if (SD.FileService.RecentOpen.RecentProjects.Count > 0) {
SD.ProjectService.OpenSolutionOrProject(SD.FileService.RecentOpen.RecentProjects[0]); SD.ProjectService.OpenSolutionOrProject(SD.FileService.RecentOpen.RecentProjects[0]);
didLoadSolutionOrFile = true; didLoadSolutionOrFile = true;
@ -138,7 +138,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
// save the workbench memento in the ide properties // save the workbench memento in the ide properties
try { try {
PropertyService.SetNestedProperties(workbenchMemento, SD.Workbench.CreateMemento()); SD.PropertyService.SetNestedProperties(workbenchMemento, ((WpfWorkbench)SD.Workbench).CreateMemento());
} catch (Exception e) { } catch (Exception e) {
MessageService.ShowException(e, "Exception while saving workbench state."); MessageService.ShowException(e, "Exception while saving workbench state.");
} }

6
src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

@ -478,7 +478,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
FileName ViewContentMementosFileName { FileName ViewContentMementosFileName {
get { get {
if (viewContentMementosFileName == null) { if (viewContentMementosFileName == null) {
viewContentMementosFileName = FileName.Create(Path.Combine(PropertyService.ConfigDirectory, "LastViewStates.xml")); viewContentMementosFileName = SD.PropertyService.ConfigDirectory.CombineFile("LastViewStates.xml");
} }
return viewContentMementosFileName; return viewContentMementosFileName;
} }
@ -500,8 +500,8 @@ namespace ICSharpCode.SharpDevelop.Workbench
} }
public static bool LoadDocumentProperties { public static bool LoadDocumentProperties {
get { return PropertyService.Get("SharpDevelop.LoadDocumentProperties", true); } get { return SD.PropertyService.Get("SharpDevelop.LoadDocumentProperties", true); }
set { PropertyService.Set("SharpDevelop.LoadDocumentProperties", value); } set { SD.PropertyService.Set("SharpDevelop.LoadDocumentProperties", value); }
} }
/// <summary> /// <summary>

Loading…
Cancel
Save