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. 81
      src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs
  14. 6
      src/Main/SharpDevelop/Parser/ParserService.cs
  15. 20
      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 @@ @@ -13,15 +13,14 @@
<P>The assemblyInfo.cs files are updated by the tool
&quot;UpdateAssemblyInfo&quot;. UpdateAssemblyInfo
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.
It is also used as assembly version.
</P>
<p>
The revision number is retrieved by running a function in NSvn.Core.dll equivalent to "svn info"
in the "src" folder.
When this doesn't work (e.g. in an exported tree like the source code download on the build server), the
content of the file src/REVISION is used as revision number.
The revision number is retrieved by running "git rev-list" and counting the number of output lines.
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),
the content of the file src/REVISION is used as revision number.
When even this fails, the revision '0' is used.
</p>
<H2>Publisher Policy</H2>
@ -39,7 +38,7 @@ would want to reference. @@ -39,7 +38,7 @@ would want to reference.
</P>
<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.
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
in large parts binary compatible.
<br>
@ -51,5 +50,17 @@ compile it against the oldest SharpDevelop version you want your AddIn to run wi @@ -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),
but an AddIn compiled against 2.1.0.1801 will fail to load in SharpDevelop 2.1.0.1800.
</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>
</HTML>

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

@ -63,7 +63,7 @@ namespace ICSharpCode.CodeCoverage.Tests.Utils @@ -63,7 +63,7 @@ namespace ICSharpCode.CodeCoverage.Tests.Utils
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();
}

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

@ -65,34 +65,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -65,34 +65,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
panel.Children.Add(tree);
// ProjectService.SolutionLoaded += delegate { LoadNodes(); };
// ProjectService.SolutionClosing += delegate { SaveNodes(); };
// SD.ProjectService.CurrentSolution.PreferencesSaving += delegate { SaveNodes(); };
// LoadNodes();
WindowsDebugger.RefreshingPads += 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)
{
var node = MakeNode(expression);

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

@ -36,7 +36,7 @@ namespace XmlEditor.Tests.Utils @@ -36,7 +36,7 @@ namespace XmlEditor.Tests.Utils
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);
searchedForFileExtensions.Add(extension);

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

@ -43,7 +43,36 @@ namespace ICSharpCode.SharpDevelop @@ -43,7 +43,36 @@ namespace ICSharpCode.SharpDevelop
/// <inheritdoc cref="System.IO.File.OpenText"/>
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
@ -98,7 +127,7 @@ namespace ICSharpCode.SharpDevelop @@ -98,7 +127,7 @@ namespace ICSharpCode.SharpDevelop
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>();
}

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

@ -47,9 +47,9 @@ namespace ICSharpCode.SharpDevelop @@ -47,9 +47,9 @@ namespace ICSharpCode.SharpDevelop
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));
}
}

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

@ -74,10 +74,16 @@ namespace ICSharpCode.SharpDevelop @@ -74,10 +74,16 @@ namespace ICSharpCode.SharpDevelop
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)
&& FileUtility.MatchesPattern(fn.GetFileName(), searchPattern));
return fileNames.Value.Where(delegate(FileName fn) {
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 @@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// This is the basic interface to the workspace.
/// </summary>
[SDService("SD.Workbench")]
public interface IWorkbench : IMementoCapable
public interface IWorkbench
{
/// <summary>
/// The main window as IWin32Window.
@ -34,14 +34,6 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -34,14 +34,6 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary>
bool FullScreen { get; set; }
/// <summary>
/// The title shown in the title bar.
/// </summary>
string Title {
get;
set;
}
/// <summary>
/// A collection in which all opened view contents (including all secondary view contents) are saved.
/// </summary>

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

@ -32,58 +32,8 @@ namespace ICSharpCode.Core @@ -32,58 +32,8 @@ namespace ICSharpCode.Core
List<string> addInFiles = new List<string>();
List<string> disabledAddIns = new List<string>();
bool externalAddInsConfigured;
string propertiesName;
string configDirectory;
string dataDirectory;
string applicationName;
AddInTreeImpl addInTree;
/// <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;
}
}
string applicationName;
/// <summary>
/// Creates a new CoreStartup instance.
@ -98,7 +48,6 @@ namespace ICSharpCode.Core @@ -98,7 +48,6 @@ namespace ICSharpCode.Core
if (applicationName == null)
throw new ArgumentNullException("applicationName");
this.applicationName = applicationName;
propertiesName = applicationName + "Properties";
}
/// <summary>
@ -198,16 +147,9 @@ namespace ICSharpCode.Core @@ -198,16 +147,9 @@ namespace ICSharpCode.Core
/// Starts the core services.
/// This initializes the PropertyService and ResourceService.
/// </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 propertyService = new PropertyServiceImpl(
DirectoryName.Create(configDirectory),
DirectoryName.Create(dataDirectory ?? Path.Combine(FileUtility.ApplicationRootPath, "data")),
propertiesName);
var applicationStateInfoService = new ApplicationStateInfoService();
addInTree = new AddInTreeImpl(applicationStateInfoService);

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

@ -31,7 +31,7 @@ namespace ICSharpCode.Core @@ -31,7 +31,7 @@ namespace ICSharpCode.Core
/// <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="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>
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 @@ -17,13 +17,11 @@ namespace ICSharpCode.Core
/// <summary>
/// Gets the configuration directory. (usually "%ApplicationData%\%ApplicationName%")
/// </summary>
/// <seealso cref="CoreStartup.ConfigDirectory"/>
DirectoryName ConfigDirectory { get; }
/// <summary>
/// Gets the data directory (usually "ApplicationRootPath\data")
/// </summary>
/// <seealso cref="CoreStartup.DataDirectory"/>
DirectoryName DataDirectory { get; }
/// <summary>
@ -56,8 +54,23 @@ namespace ICSharpCode.Core @@ -56,8 +54,23 @@ namespace ICSharpCode.Core
void Remove(string key);
/// <summary>
/// Saves the properties to disk.
/// Saves the main properties to disk.
/// </summary>
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 @@ -190,7 +190,7 @@ namespace ICSharpCode.Core
/// <summary>
/// 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>
/// <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)
@ -255,7 +255,7 @@ namespace ICSharpCode.Core @@ -255,7 +255,7 @@ namespace ICSharpCode.Core
/// <summary>
/// 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>
/// <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)

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

@ -9,17 +9,13 @@ using System.IO; @@ -9,17 +9,13 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using ICSharpCode.Core;
namespace ICSharpCode.Core
{
public sealed class PropertyServiceImpl : IPropertyService
public class PropertyServiceImpl : IPropertyService
{
string propertyFileName;
DirectoryName configDirectory;
DirectoryName dataDirectory;
Properties properties;
readonly Properties properties;
/// <summary>
/// Initializes the service for unit-testing (reset properties to an empty property container).
@ -30,24 +26,22 @@ namespace ICSharpCode.Core @@ -30,24 +26,22 @@ namespace ICSharpCode.Core
properties = new Properties();
}
public PropertyServiceImpl(DirectoryName configDirectory, DirectoryName dataDirectory, string propertiesName)
public PropertyServiceImpl(Properties properties)
{
this.configDirectory = configDirectory;
this.dataDirectory = dataDirectory;
this.propertyFileName = propertiesName + ".xml";
Directory.CreateDirectory(configDirectory);
LoadPropertiesFromStream(FileName.Create(Path.Combine(configDirectory, propertyFileName)));
if (properties == null)
throw new ArgumentNullException("properties");
this.properties = properties;
}
public DirectoryName ConfigDirectory {
public virtual DirectoryName ConfigDirectory {
get {
return configDirectory;
throw new NotImplementedException();
}
}
public DirectoryName DataDirectory {
public virtual DirectoryName DataDirectory {
get {
return dataDirectory;
throw new NotImplementedException();
}
}
@ -105,57 +99,26 @@ namespace ICSharpCode.Core @@ -105,57 +99,26 @@ namespace ICSharpCode.Core
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 event PropertyChangedEventHandler PropertyChanged {
add { properties.PropertyChanged += value; }
remove { properties.PropertyChanged -= value; }
}
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);
}
public Properties MainPropertiesContainer {
get { return properties; }
}
/// <summary>
/// Acquires an exclusive lock on the properties file so that it can be opened safely.
/// </summary>
public IDisposable LockPropertyFile()
public virtual void Save()
{
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 {
add { properties.PropertyChanged += value; }
remove { properties.PropertyChanged -= value; }
public virtual Properties LoadExtraProperties(string key)
{
return new Properties();
}
public Properties MainPropertiesContainer {
get { return properties; }
public virtual void SaveExtraProperties(string key, Properties p)
{
}
}
}

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

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

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

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

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

@ -50,17 +50,28 @@ namespace ICSharpCode.SharpDevelop.Sda @@ -50,17 +50,28 @@ namespace ICSharpCode.SharpDevelop.Sda
this.useSharpDevelopErrorHandler = true;
ExceptionBox.RegisterExceptionBoxForUnhandledExceptions();
}
startup.ConfigDirectory = properties.ConfigDirectory;
startup.DataDirectory = properties.DataDirectory;
string configDirectory = properties.ConfigDirectory;
string dataDirectory = properties.DataDirectory;
string propertiesName;
if (properties.PropertiesName != null) {
startup.PropertiesName = properties.PropertiesName;
propertiesName = properties.PropertiesName;
} else {
propertiesName = properties.ApplicationName + "Properties";
}
if (properties.ApplicationRootPath != null) {
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);
SD.ResourceService.RegisterNeutralStrings(new ResourceManager("ICSharpCode.SharpDevelop.Resources.StringResources", exe));
SD.ResourceService.RegisterNeutralImages(new ResourceManager("ICSharpCode.SharpDevelop.Resources.BitmapResources", exe));
@ -80,11 +91,11 @@ namespace ICSharpCode.SharpDevelop.Sda @@ -80,11 +91,11 @@ namespace ICSharpCode.SharpDevelop.Sda
}
if (properties.AllowAddInConfigurationAndExternalAddIns) {
startup.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml"));
startup.ConfigureExternalAddIns(Path.Combine(configDirectory, "AddIns.xml"));
}
if (properties.AllowUserAddIns) {
startup.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"),
Path.Combine(PropertyService.ConfigDirectory, "AddIns"));
startup.ConfigureUserAddIns(Path.Combine(configDirectory, "AddInInstallTemp"),
Path.Combine(configDirectory, "AddIns"));
}
LoggingService.Info("Loading AddInTree...");

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

@ -69,10 +69,12 @@ namespace ICSharpCode.SharpDevelop @@ -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 {
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) {
throw new IOException(ex.Message, ex);
}

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

@ -0,0 +1,101 @@ @@ -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 @@ @@ -168,6 +168,7 @@
<Compile Include="Services\ClipboardWrapper.cs" />
<Compile Include="Services\DispatcherMessageLoop.cs" />
<Compile Include="Services\FileSystem.cs" />
<Compile Include="Services\PropertyService.cs" />
<Compile Include="Services\UIService.cs" />
<Compile Include="Startup\App.xaml.cs" />
<Compile Include="Startup\SharpDevelopMain.cs" />

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

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

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

@ -67,7 +67,7 @@ namespace ICSharpCode.SharpDevelop.Templates @@ -67,7 +67,7 @@ namespace ICSharpCode.SharpDevelop.Templates
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")
.Select(file => TextTemplateGroup.Load(file))
.ToList();

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

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

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

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

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

@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary>
public static string DataLayoutPath {
get {
return Path.Combine(PropertyService.DataDirectory, "layouts");
return Path.Combine(SD.PropertyService.DataDirectory, "layouts");
}
}
@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
/// </summary>
public static string ConfigLayoutPath {
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 @@ -50,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
Project.CustomToolsService.Initialize();
workbench.Initialize();
workbench.SetMemento(PropertyService.NestedProperties(workbenchMemento));
workbench.SetMemento(SD.PropertyService.NestedProperties(workbenchMemento));
workbench.WorkbenchLayout = layout;
var dlgMsgService = SD.MessageService as IDialogMessageService;
@ -111,7 +111,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -111,7 +111,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
}
// 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) {
SD.ProjectService.OpenSolutionOrProject(SD.FileService.RecentOpen.RecentProjects[0]);
didLoadSolutionOrFile = true;
@ -138,7 +138,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -138,7 +138,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
// save the workbench memento in the ide properties
try {
PropertyService.SetNestedProperties(workbenchMemento, SD.Workbench.CreateMemento());
SD.PropertyService.SetNestedProperties(workbenchMemento, ((WpfWorkbench)SD.Workbench).CreateMemento());
} catch (Exception e) {
MessageService.ShowException(e, "Exception while saving workbench state.");
}

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

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

Loading…
Cancel
Save