diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
index aeae35a99e..6897e02629 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
@@ -57,7 +57,8 @@ namespace CSharpBinding
: base(loadInformation)
{
Init();
- InitializeProjectContent(new CSharpProjectContent());
+ if (loadInformation.InitializeTypeSystem)
+ InitializeProjectContent(new CSharpProjectContent());
}
public const string DefaultTargetsFile = @"$(MSBuildToolsPath)\Microsoft.CSharp.targets";
diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
index 22c53e32b2..e05cb5d3bd 100644
--- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
+++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
@@ -226,7 +226,6 @@
-
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs b/src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs
index ff8c7ce3ff..849e57519a 100644
--- a/src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs
+++ b/src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Internal.Templates;
@@ -64,9 +65,8 @@ namespace ICSharpCode.PackageManagement
IEnumerable GetCreatedProjects()
{
- var createInfo = Owner as ProjectCreateInformation;
- var newCreatedProjects = new NewProjectsCreated(createInfo, projectService);
- return newCreatedProjects.GetProjects();
+ var createInfo = Owner as ProjectCreateOptions;
+ return createInfo != null ? createInfo.CreatedProjects.OfType() : Enumerable.Empty();
}
IPackageReferencesForProject CreatePackageReferencesForProject(MSBuildBasedProject project)
diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/NewProjectsCreated.cs b/src/AddIns/Misc/PackageManagement/Project/Src/NewProjectsCreated.cs
deleted file mode 100644
index 9c52d984b6..0000000000
--- a/src/AddIns/Misc/PackageManagement/Project/Src/NewProjectsCreated.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.Collections.Generic;
-using ICSharpCode.SharpDevelop.Internal.Templates;
-using ICSharpCode.SharpDevelop.Project;
-
-namespace ICSharpCode.PackageManagement
-{
- public class NewProjectsCreated
- {
- ProjectCreateInformation createInfo;
- OpenMSBuildProjects openProjects;
-
- public NewProjectsCreated(
- ProjectCreateInformation createInfo,
- IPackageManagementProjectService projectService)
- : this(createInfo, new OpenMSBuildProjects(projectService))
- {
- }
-
- public NewProjectsCreated(
- ProjectCreateInformation createInfo,
- OpenMSBuildProjects openProjects)
- {
- this.createInfo = createInfo;
- this.openProjects = openProjects;
- }
-
- public IEnumerable GetProjects()
- {
- // ProjectCreateInformation is no longer used to collect the results of the whole solution creation,
- // there now is a separate instance per project.
- #warning Reimplement PackageManagement.NewProjectsCreated
- throw new NotImplementedException();
- /*foreach (IProject project in createInfo.CreatedProjects) {
- MSBuildBasedProject openProject = FindProject(project.Name);
- if (openProject != null) {
- yield return openProject;
- }
- }*/
- }
-
- MSBuildBasedProject FindProject(string name)
- {
- return openProjects.FindProject(name);
- }
- }
-}
diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
index 6c7af232bd..32855883ff 100644
--- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
+++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
@@ -195,7 +195,6 @@
-
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs
index 542789e700..dc6224ff19 100644
--- a/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs
+++ b/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Windows.Input;
using ICSharpCode.PackageManagement;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
@@ -37,20 +38,18 @@ namespace PackageManagement.Tests
void RunCommandWithProjectCreateInfoAsOwner(List projects)
{
- throw new NotImplementedException();
- /*var createInfo = new ProjectCreateInformation(projects);
- createInfo.Solution = projects[0].ParentSolution;
+ var createInfo = new ProjectCreateOptions();
+ createInfo.CreatedProjects.AddRange(projects);
- command.FakeProjectService.AllProjects.Inputs.Add(new ReadOnlyModelCollection(projects));
+ command.FakeProjectService.ProjectCollections.Add(new ReadOnlyModelCollection(projects));
- RunCommandWithProjectCreateInfoAsOwner(createInfo);*/
+ RunCommandWithProjectCreateInfoAsOwner(createInfo);
}
- void RunCommandWithProjectCreateInfoAsOwner(ProjectCreateInformation createInfo)
+ void RunCommandWithProjectCreateInfoAsOwner(ProjectCreateOptions createInfo)
{
- command.Owner = createInfo;
- command.Run();
- }
+ ((ICommand)command).Execute(createInfo);
+ }
void RunCommandWithExceptionThrowingPackageReferences(Exception exception)
{
@@ -73,27 +72,6 @@ namespace PackageManagement.Tests
Assert.AreEqual(expectedProject, project);
}
- [Test]
- public void Run_OneProjectCreatedByNewProjectDialog_ProjectUsedToCreatePackageReferencesIsTakenFromOpenProjectsNotCreateInfo()
- {
- CreateCommand();
- TestableProject createInfoProject = CreateFakeProject("Test");
- var projects = new List();
- projects.Add(createInfoProject);
- throw new NotImplementedException();
-
- /*var createInfo = new ProjectCreateInformation(projects);
-
- TestableProject expectedProject = ProjectHelper.CreateTestProject("TEST");
- command.FakeProjectService.AddProject(expectedProject);
-
- RunCommandWithProjectCreateInfoAsOwner(createInfo);
-
- MSBuildBasedProject project = command.ProjectPassedToCreatePackageReferencesForProject;
-
- Assert.AreEqual(expectedProject, project);*/
- }
-
[Test]
public void Run_TwoProjectsCreatedByNewProjectDialog_TwoProjectsUsedToCreatePackageReferences()
{
diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs
deleted file mode 100644
index b1086f7382..0000000000
--- a/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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.Collections.Generic;
-using ICSharpCode.PackageManagement;
-using ICSharpCode.PackageManagement.Design;
-using ICSharpCode.SharpDevelop.Internal.Templates;
-using ICSharpCode.SharpDevelop.Project;
-using NUnit.Framework;
-using PackageManagement.Tests.Helpers;
-
-namespace PackageManagement.Tests
-{
- [TestFixture, IgnoreAttribute("NewProjectsCreated currently not implemented")]
- public class NewProjectsCreatedTests
- {
- FakePackageManagementProjectService fakeProjectService;
- NewProjectsCreated newProjectsCreated;
-
- TestableProject CreateProject(string name)
- {
- return ProjectHelper.CreateTestProject(name);
- }
-
- ProjectCreateInformation CreateProjectCreateInfo(MSBuildBasedProject project)
- {
- var projects = new List();
- projects.Add(project);
- return CreateProjectCreateInfo(projects);
- }
-
- ProjectCreateInformation CreateProjectCreateInfo(IEnumerable projects)
- {
- throw new NotImplementedException();
- //return new ProjectCreateInformation(projects);
- }
-
- void CreateNewProjectsCreated(ProjectCreateInformation createInfo)
- {
- fakeProjectService = new FakePackageManagementProjectService();
- newProjectsCreated = new NewProjectsCreated(createInfo, fakeProjectService);
- }
-
- TestableProject AddProjectToProjectServiceOpenProjects(string projectName)
- {
- TestableProject project = CreateProject(projectName);
- fakeProjectService.AddProject(project);
- return project;
- }
-
- [Test]
- public void GetProjects_OneProjectCreatedAndOneOldProjectInSolution_ReturnsProjectFromProjectService()
- {
- TestableProject project = CreateProject("TestProject");
- ProjectCreateInformation createInfo = CreateProjectCreateInfo(project);
- CreateNewProjectsCreated(createInfo);
- AddProjectToProjectServiceOpenProjects("OriginalProject");
- TestableProject expectedProject = AddProjectToProjectServiceOpenProjects("TestProject");
-
- var projects = new List();
- projects.AddRange(newProjectsCreated.GetProjects());
-
- var expectedProjects = new MSBuildBasedProject[] {
- expectedProject
- };
-
- Assert.AreEqual(expectedProjects, projects);
- }
-
- [Test]
- public void GetProjects_OneProjectCreatedWithDifferentNameCase_ReturnsProjectFromProjectService()
- {
- TestableProject project = CreateProject("TESTPROJECT");
- ProjectCreateInformation createInfo = CreateProjectCreateInfo(project);
- CreateNewProjectsCreated(createInfo);
- TestableProject expectedProject = AddProjectToProjectServiceOpenProjects("TestProject");
-
- var projects = new List();
- projects.AddRange(newProjectsCreated.GetProjects());
-
- var expectedProjects = new MSBuildBasedProject[] {
- expectedProject
- };
-
- Assert.AreEqual(expectedProjects, projects);
- }
-
- [Test]
- public void GetProjects_OneProjectCreatedButProjectIsNotOpen_ReturnsNoProjects()
- {
- TestableProject project = CreateProject("TestProject");
- ProjectCreateInformation createInfo = CreateProjectCreateInfo(project);
- CreateNewProjectsCreated(createInfo);
-
- var projects = new List();
- projects.AddRange(newProjectsCreated.GetProjects());
-
- Assert.AreEqual(0, projects.Count);
- }
- }
-}
diff --git a/src/Main/Base/Project/Dom/IModelCollection.cs b/src/Main/Base/Project/Dom/IModelCollection.cs
index 836ee4cd37..cdc553b5c1 100644
--- a/src/Main/Base/Project/Dom/IModelCollection.cs
+++ b/src/Main/Base/Project/Dom/IModelCollection.cs
@@ -36,6 +36,14 @@ namespace ICSharpCode.SharpDevelop.Dom
///
public interface IMutableModelCollection : IModelCollection, ICollection
{
+ ///
+ /// Gets the number of items in the collection.
+ ///
+ ///
+ /// Disambiguates between IReadOnlyCollection.Count and ICollection.Count
+ ///
+ new int Count { get; }
+
///
/// Adds the specified items to the collection.
///
diff --git a/src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs b/src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs
index 0e38e2d998..fb6f9301ab 100644
--- a/src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs
+++ b/src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs
@@ -1,5 +1,5 @@
// 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;
+// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/src/Main/Base/Project/Dom/SimpleModelCollection.cs b/src/Main/Base/Project/Dom/SimpleModelCollection.cs
index 154dec956c..1366c94614 100644
--- a/src/Main/Base/Project/Dom/SimpleModelCollection.cs
+++ b/src/Main/Base/Project/Dom/SimpleModelCollection.cs
@@ -202,5 +202,18 @@ namespace ICSharpCode.SharpDevelop.Dom
#endregion
}
+
+ ///
+ /// A model collection implementation that disallows null values.
+ ///
+ public class NullSafeSimpleModelCollection : SimpleModelCollection where T : class
+ {
+ protected override void ValidateItem(T item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("item");
+ base.ValidateItem(item);
+ }
+ }
}
diff --git a/src/Main/Base/Project/Dom/SynchronizedModelCollection.cs b/src/Main/Base/Project/Dom/SynchronizedModelCollection.cs
new file mode 100644
index 0000000000..7436ce5a75
--- /dev/null
+++ b/src/Main/Base/Project/Dom/SynchronizedModelCollection.cs
@@ -0,0 +1,140 @@
+// 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.Collections.Generic;
+using System.Threading;
+using ICSharpCode.NRefactory.Utils;
+
+namespace ICSharpCode.SharpDevelop.Dom
+{
+ ///
+ /// Synchronizing wrapper around IMutableModelCollection.
+ ///
+ public class SynchronizedModelCollection : IMutableModelCollection
+ {
+ readonly IMutableModelCollection underlyingCollection;
+ readonly object syncRoot;
+
+ public SynchronizedModelCollection(IMutableModelCollection underlyingCollection)
+ : this(underlyingCollection, new object())
+ {
+ }
+
+ public SynchronizedModelCollection(IMutableModelCollection underlyingCollection, object syncRoot)
+ {
+ if (underlyingCollection == null)
+ throw new ArgumentNullException("underlyingCollection");
+ if (syncRoot == null)
+ throw new ArgumentNullException("syncRoot");
+ this.underlyingCollection = underlyingCollection;
+ this.syncRoot = syncRoot;
+ }
+
+ // Event registration is thread-safe on the underlying collection
+ public event ModelCollectionChangedEventHandler CollectionChanged {
+ add { underlyingCollection.CollectionChanged += value; }
+ remove { underlyingCollection.CollectionChanged -= value; }
+ }
+
+ #region IMutableModelCollection implementation
+
+ public void Clear()
+ {
+ lock (syncRoot) {
+ underlyingCollection.Clear();
+ }
+ }
+
+ public void Add(T item)
+ {
+ lock (syncRoot) {
+ underlyingCollection.Add(item);
+ }
+ }
+
+ public void AddRange(IEnumerable items)
+ {
+ lock (syncRoot) {
+ underlyingCollection.AddRange(items);
+ }
+ }
+
+ public bool Remove(T item)
+ {
+ lock (syncRoot) {
+ return underlyingCollection.Remove(item);
+ }
+ }
+
+ public int RemoveAll(Predicate predicate)
+ {
+ lock (syncRoot) {
+ return underlyingCollection.RemoveAll(predicate);
+ }
+ }
+
+ public IDisposable BatchUpdate()
+ {
+ Monitor.Enter(syncRoot);
+ IDisposable disposable = underlyingCollection.BatchUpdate();
+ return new CallbackOnDispose(
+ delegate {
+ if (disposable != null)
+ disposable.Dispose();
+ Monitor.Exit(syncRoot);
+ });
+ }
+
+ #endregion
+
+ #region ICollection implementation
+
+ public bool Contains(T item)
+ {
+ lock (syncRoot) {
+ return underlyingCollection.Contains(item);
+ }
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ lock (syncRoot) {
+ underlyingCollection.CopyTo(array, arrayIndex);
+ }
+ }
+
+ public int Count {
+ get {
+ lock (syncRoot) {
+ return underlyingCollection.Count;
+ }
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ lock (syncRoot) {
+ return underlyingCollection.IsReadOnly;
+ }
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ IEnumerable snapshot;
+ lock (syncRoot) {
+ T[] array = new T[underlyingCollection.Count];
+ underlyingCollection.CopyTo(array, 0);
+ snapshot = array;
+ }
+ return snapshot.GetEnumerator();
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ #endregion
+ }
+}
diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
index 78e6ad2054..59aee7e054 100644
--- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
+++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
@@ -95,6 +95,7 @@
+
diff --git a/src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs b/src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs
index c1cfd3122b..9c71c66a37 100644
--- a/src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs
+++ b/src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs
@@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Project
///
/// The configuration mapping was changed.
///
- public event EventHandler Changed;
+ public event EventHandler Changed = delegate { };
Dictionary dict = new Dictionary();
@@ -66,10 +66,13 @@ namespace ICSharpCode.SharpDevelop.Project
{
if (string.IsNullOrEmpty(projectConfiguration.Configuration))
throw new ArgumentException("Invalid project configuration");
- if (string.IsNullOrEmpty(projectConfiguration.Platform) || projectConfiguration.Platform == "Any CPU")
+ if (string.IsNullOrEmpty(projectConfiguration.Platform))
throw new ArgumentException("Invalid project platform");
lock (dict) {
- GetOrCreateEntry(solutionConfiguration).Config = projectConfiguration;
+ GetOrCreateEntry(solutionConfiguration).Config = new ConfigurationAndPlatform(
+ projectConfiguration.Configuration,
+ MSBuildInternals.FixPlatformNameForProject(projectConfiguration.Platform)
+ );
}
Changed(this, EventArgs.Empty);
}
diff --git a/src/Main/Base/Project/Project/IProjectService.cs b/src/Main/Base/Project/Project/IProjectService.cs
index a8dd2f9355..e487022391 100644
--- a/src/Main/Base/Project/Project/IProjectService.cs
+++ b/src/Main/Base/Project/Project/IProjectService.cs
@@ -28,7 +28,7 @@ namespace ICSharpCode.SharpDevelop.Project
///
/// This event is raised after a solution is opened.
///
- event EventHandler SolutionLoaded;
+ event EventHandler SolutionOpened;
///
/// This event is raised before a solution is closed.
@@ -76,7 +76,17 @@ namespace ICSharpCode.SharpDevelop.Project
/// This method may only be called on the main thread.
/// If any errors occur, this method may display an error dialog.
///
- void OpenSolutionOrProject(FileName fileName);
+ bool OpenSolutionOrProject(FileName fileName);
+
+ ///
+ /// Opens a solution in the IDE.
+ ///
+ bool OpenSolution(FileName fileName);
+
+ ///
+ /// Opens a solution in the IDE that was created/loaded earlier.
+ ///
+ bool OpenSolution(ISolution solution);
///
/// Closes the solution: cancels build, clears solution data, fires the SolutionClosing and SolutionClosed events.
@@ -91,13 +101,13 @@ namespace ICSharpCode.SharpDevelop.Project
bool CloseSolution(bool allowCancel = true);
///
- /// Returns if the given file is considered a project or solution file.
+ /// Returns if the given file is considered a solution or project file.
/// This method looks at the list of registered file extensions in /SharpDevelop/Workbench/ProjectBinding.
///
///
/// This method is thread-safe.
///
- bool IsProjectOrSolutionFile(FileName fileName);
+ bool IsSolutionOrProjectFile(FileName fileName);
///
/// Loads a solution file without opening it in the IDE.
diff --git a/src/Main/Base/Project/Project/ISolution.cs b/src/Main/Base/Project/Project/ISolution.cs
index 1c772ca6ad..9167c6a7d4 100644
--- a/src/Main/Base/Project/Project/ISolution.cs
+++ b/src/Main/Base/Project/Project/ISolution.cs
@@ -19,6 +19,11 @@ namespace ICSharpCode.SharpDevelop.Project
///
/// Represents a solution.
///
+ ///
+ /// This interface is thread-safe for read-access. Background threads may read from ISolution
+ /// even while the main thread is modifying the solution.
+ /// However, only the main thread is allowed to modify the solution.
+ ///
public interface ISolution : ISolutionFolder, ICanBeDirty, IConfigurable, IDisposable
{
Microsoft.Build.Evaluation.ProjectCollection MSBuildProjectCollection { get; }
diff --git a/src/Main/Base/Project/Project/ProjectInformation.cs b/src/Main/Base/Project/Project/ProjectInformation.cs
index cfaaeb9329..9dd4cc6dc0 100644
--- a/src/Main/Base/Project/Project/ProjectInformation.cs
+++ b/src/Main/Base/Project/Project/ProjectInformation.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Project
@@ -24,23 +25,47 @@ namespace ICSharpCode.SharpDevelop.Project
this.ProjectSections = new List();
this.ConfigurationMapping = new ConfigurationMapping();
var solutionConfig = solution.ActiveConfiguration;
- // In unit tests, ActiveConfiguration mayb return null
+ // In unit tests, ActiveConfiguration maybe return null
if (solutionConfig.Configuration != null && solutionConfig.Platform != null)
this.ActiveProjectConfiguration = this.ConfigurationMapping.GetProjectConfiguration(solution.ActiveConfiguration);
else
this.ActiveProjectConfiguration = new ConfigurationAndPlatform("Debug", "AnyCPU");
+ this.InitializeTypeSystem = true;
}
public ISolution Solution { get; private set; }
public FileName FileName { get; private set; }
+
+ ///
+ /// Specifies the mapping between solution configurations and project configurations.
+ ///
public ConfigurationMapping ConfigurationMapping { get; set; }
+
+ ///
+ /// Specified the project configuration that should be initially active when the project is loaded.
+ ///
public ConfigurationAndPlatform ActiveProjectConfiguration { get; set; }
+
public IList ProjectSections { get; private set; }
public string ProjectName { get; set; }
+ ///
+ /// Specified the ID GUID for the project.
+ /// If this property isn't set (stays at Guid.Empty), the project should generate a new GUID. (see AbstractProject ctor)
+ ///
public Guid IdGuid { get; set; }
+
+ ///
+ /// Specifies the type GUID for the project.
+ /// Necessary for both project creation and loading.
+ ///
public Guid TypeGuid { get; set; }
+ ///
+ /// Specifies whether to initialize the type system for the project.
+ /// The default is true.
+ ///
+ public bool InitializeTypeSystem { get; set; }
}
///
@@ -91,6 +116,5 @@ namespace ICSharpCode.SharpDevelop.Project
public string RootNamespace { get; set; }
public TargetFramework TargetFramework { get; set; }
- public bool InitializeTypeSystem { get; set; }
}
}
diff --git a/src/Main/Base/Project/Project/SolutionSection.cs b/src/Main/Base/Project/Project/SolutionSection.cs
index 4dcb4a305d..56d020737f 100644
--- a/src/Main/Base/Project/Project/SolutionSection.cs
+++ b/src/Main/Base/Project/Project/SolutionSection.cs
@@ -74,47 +74,56 @@ namespace ICSharpCode.SharpDevelop.Project
}
public int Count {
- get { return entries.Count; }
+ get {
+ lock (entries)
+ return entries.Count;
+ }
}
public void Add(string key, string value)
{
Validate(key, value);
- entries.Add(new KeyValuePair(key, value));
+ lock (entries)
+ entries.Add(new KeyValuePair(key, value));
Changed(this, EventArgs.Empty);
}
public bool Remove(string key)
{
- if (entries.RemoveAll(e => e.Key == key) > 0) {
+ bool result;
+ lock (entries)
+ result = entries.RemoveAll(e => e.Key == key) > 0;
+ if (result)
Changed(this, EventArgs.Empty);
- return true;
- } else {
- return false;
- }
+ return result;
}
public void Clear()
{
- entries.Clear();
+ lock (entries)
+ entries.Clear();
Changed(this, EventArgs.Empty);
}
public bool ContainsKey(string key)
{
- for (int i = 0; i < entries.Count; i++) {
- if (entries[i].Key == key)
- return true;
+ lock (entries) {
+ for (int i = 0; i < entries.Count; i++) {
+ if (entries[i].Key == key)
+ return true;
+ }
}
return false;
}
public bool TryGetValue(string key, out string value)
{
- for (int i = 0; i < entries.Count; i++) {
- if (entries[i].Key == key) {
- value = entries[i].Value;
- return true;
+ lock (entries) {
+ for (int i = 0; i < entries.Count; i++) {
+ if (entries[i].Key == key) {
+ value = entries[i].Value;
+ return true;
+ }
}
}
value = null;
@@ -123,46 +132,56 @@ namespace ICSharpCode.SharpDevelop.Project
public string this[string key] {
get {
- for (int i = 0; i < entries.Count; i++) {
- if (entries[i].Key == key) {
- return entries[i].Value;
+ lock (entries) {
+ for (int i = 0; i < entries.Count; i++) {
+ if (entries[i].Key == key) {
+ return entries[i].Value;
+ }
}
}
return null;
}
set {
Validate(key, value);
- for (int i = 0; i < entries.Count; i++) {
- if (entries[i].Key == key) {
- entries[i] = new KeyValuePair(key, value);
- Changed(this, EventArgs.Empty);
- return;
+ lock (entries) {
+ bool found = false;
+ for (int i = 0; i < entries.Count; i++) {
+ if (entries[i].Key == key) {
+ entries[i] = new KeyValuePair(key, value);
+ found = true;
+ break;
+ }
}
+ if (!found)
+ entries.Add(new KeyValuePair(key, value));
}
- Add(key, value);
+ Changed(this, EventArgs.Empty);
}
}
public IEnumerable Keys {
get {
- return entries.Select(e => e.Key);
+ lock (entries)
+ return entries.Select(e => e.Key).ToArray();
}
}
public IEnumerable Values {
get {
- return entries.Select(e => e.Value);
+ lock (entries)
+ return entries.Select(e => e.Value).ToArray();
}
}
public IEnumerator> GetEnumerator()
{
- return entries.GetEnumerator();
+ lock (entries)
+ return entries.ToList().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
- return entries.GetEnumerator();
+ return GetEnumerator();
}
}
}
diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs
index 8d0274ee85..dc92980afd 100644
--- a/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs
+++ b/src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs
@@ -353,20 +353,21 @@ namespace ICSharpCode.SharpDevelop.Project.Dialogs
NewSolutionLocation = null;
NewProjectLocation = null;
if (createNewSolution) {
- using (ISolution createdSolution = item.Template.CreateSolution(cinfo)) {
- if (createdSolution != null)
- NewSolutionLocation = createdSolution.FileName;
+ if (!SD.ProjectService.CloseSolution())
+ return;
+ ISolution createdSolution = item.Template.CreateSolution(cinfo);
+ if (createdSolution != null) {
+ NewSolutionLocation = createdSolution.FileName;
+ if (!SD.ProjectService.OpenSolution(createdSolution)) {
+ createdSolution.Dispose();
+ return;
+ }
}
- if (NewSolutionLocation != null)
- SD.ProjectService.OpenSolutionOrProject(NewSolutionLocation);
} else {
- using (IProject project = item.Template.CreateProject(SD.ProjectService.CurrentSolution, cinfo)) {
- NewProjectLocation = project.FileName;
- }
- if (NewProjectLocation != null) {
- SolutionFolderNode.Folder.AddExistingProject(NewProjectLocation);
- ProjectService.SaveSolution();
- }
+ IProject project = item.Template.CreateProject(SD.ProjectService.CurrentSolution, cinfo);
+ NewProjectLocation = project.FileName;
+ SolutionFolderNode.Folder.Items.Add(project);
+ ProjectService.SaveSolution();
}
item.Template.RunOpenActions(cinfo);
diff --git a/src/Main/Base/Project/Src/Gui/Pads/FileScout.cs b/src/Main/Base/Project/Src/Gui/Pads/FileScout.cs
index 3215f231d5..e212d56a2a 100644
--- a/src/Main/Base/Project/Src/Gui/Pads/FileScout.cs
+++ b/src/Main/Base/Project/Src/Gui/Pads/FileScout.cs
@@ -399,7 +399,7 @@ namespace ICSharpCode.SharpDevelop.Gui
{
foreach (FileList.FileListItem item in filelister.SelectedItems) {
var fileName = FileName.Create(item.FullName);
- if (SD.ProjectService.IsProjectOrSolutionFile(fileName))
+ if (SD.ProjectService.IsSolutionOrProjectFile(fileName))
SD.ProjectService.OpenSolutionOrProject(fileName);
else
FileService.OpenFile(fileName);
diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs
index 819a514108..581a743b67 100644
--- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs
+++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs
@@ -100,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project
foreach (string file in files) {
try {
var fileName = FileName.Create(file);
- if (SD.ProjectService.IsProjectOrSolutionFile(fileName))
+ if (SD.ProjectService.IsSolutionOrProjectFile(fileName))
SD.ProjectService.OpenSolutionOrProject(fileName);
else
FileService.OpenFile(fileName);
diff --git a/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs b/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs
index 9d85f010c8..32d814f4ee 100644
--- a/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs
+++ b/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs
@@ -507,6 +507,7 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates
ProjectService.OnProjectCreated(new ProjectEventArgs(project));
+ projectCreateOptions.CreatedProjects.Add(project);
success = true;
return project;
} finally {
diff --git a/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs b/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs
index 626baee58a..fbe7ca5633 100644
--- a/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs
+++ b/src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs
@@ -26,6 +26,13 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates
public string SolutionName { get; set; }
public string ProjectName { get; set; }
public TargetFramework TargetFramework { get; set; }
+
+ public IList CreatedProjects { get; private set; }
+
+ public ProjectCreateOptions()
+ {
+ this.CreatedProjects = new List();
+ }
}
///
diff --git a/src/Main/Base/Project/Src/Project/AbstractProject.cs b/src/Main/Base/Project/Src/Project/AbstractProject.cs
index e764cd3795..a0e16c8a6c 100644
--- a/src/Main/Base/Project/Src/Project/AbstractProject.cs
+++ b/src/Main/Base/Project/Src/Project/AbstractProject.cs
@@ -44,7 +44,7 @@ namespace ICSharpCode.SharpDevelop.Project
this.configurationMapping = information.ConfigurationMapping ?? new ConfigurationMapping();
this.Name = information.ProjectName;
this.FileName = information.FileName;
- this.idGuid = information.IdGuid;
+ this.idGuid = (information.IdGuid != Guid.Empty ? information.IdGuid : Guid.NewGuid());
this.TypeGuid = information.TypeGuid;
if (information.ProjectSections != null)
this.projectSections.AddRange(information.ProjectSections);
diff --git a/src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs b/src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
index 66bd768e5f..6129526421 100644
--- a/src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
+++ b/src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
@@ -62,6 +62,11 @@ namespace ICSharpCode.SharpDevelop.Project
};
public override void Dispose()
+ {
+ DisposeThisClass();
+ }
+
+ void DisposeThisClass()
{
base.Dispose();
UnloadCurrentlyOpenProject();
@@ -1113,6 +1118,7 @@ namespace ICSharpCode.SharpDevelop.Project
: base(loadInformation)
{
isLoading = true;
+ bool success = false;
try {
try {
LoadProjectInternal(loadInformation);
@@ -1121,12 +1127,14 @@ namespace ICSharpCode.SharpDevelop.Project
throw;
}
}
+ success = true;
} catch (InvalidProjectFileException ex) {
LoggingService.Warn(ex);
LoggingService.Warn("ErrorCode = " + ex.ErrorCode);
- Dispose();
throw new ProjectLoadException(ex.Message, ex);
} finally {
+ if (!success)
+ DisposeThisClass();
isLoading = false;
}
}
diff --git a/src/Main/Base/Project/Src/Project/MSBuildInternals.cs b/src/Main/Base/Project/Src/Project/MSBuildInternals.cs
index 53caa60031..7475b74477 100644
--- a/src/Main/Base/Project/Src/Project/MSBuildInternals.cs
+++ b/src/Main/Base/Project/Src/Project/MSBuildInternals.cs
@@ -87,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Project
///
public static string FixPlatformNameForProject(string platformName)
{
- if (platformName == "Any CPU") {
+ if (ConfigurationAndPlatform.ConfigurationNameComparer.Equals(platformName, "Any CPU")) {
return "AnyCPU";
} else {
return platformName;
@@ -100,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project
///
public static string FixPlatformNameForSolution(string platformName)
{
- if (platformName == "AnyCPU") {
+ if (ConfigurationAndPlatform.ConfigurationNameComparer.Equals(platformName, "AnyCPU")) {
return "Any CPU";
} else {
return platformName;
diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
index bb9261c28d..7d18e9c352 100644
--- a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
+++ b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
@@ -43,7 +43,7 @@ namespace ICSharpCode.SharpDevelop.Project
[Obsolete("Use SD.ProjectService.IsProjectOrSolutionFile instead")]
public static bool HasProjectLoader(string fileName)
{
- return SD.ProjectService.IsProjectOrSolutionFile(FileName.Create(fileName));
+ return SD.ProjectService.IsSolutionOrProjectFile(FileName.Create(fileName));
}
[Obsolete("Use SD.ProjectService.OpenSolutionOrProject instead")]
@@ -198,8 +198,8 @@ namespace ICSharpCode.SharpDevelop.Project
}
public static event EventHandler SolutionLoaded {
- add { SD.ProjectService.SolutionLoaded += value; }
- remove { SD.ProjectService.SolutionLoaded -= value; }
+ add { SD.ProjectService.SolutionOpened += value; }
+ remove { SD.ProjectService.SolutionOpened -= value; }
}
public static event EventHandler SolutionClosed {
diff --git a/src/Main/Base/Project/Util/IProgressMonitor.cs b/src/Main/Base/Project/Util/IProgressMonitor.cs
index 21c9a7664a..c9428b5a4d 100644
--- a/src/Main/Base/Project/Util/IProgressMonitor.cs
+++ b/src/Main/Base/Project/Util/IProgressMonitor.cs
@@ -39,6 +39,10 @@ namespace ICSharpCode.SharpDevelop
///
/// The amount of work this sub-task performs in relation to the work of this task.
/// That means, this parameter is used as a scaling factor for work performed within the subtask.
+ ///
+ /// A cancellation token that can be used to cancel the sub-task.
+ /// Note: cancelling the main task will not cancel the sub-task.
+ ///
/// A new progress monitor representing the sub-task.
/// Multiple child progress monitors can be used at once; even concurrently on multiple threads.
IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken);
diff --git a/src/Main/Base/Project/Util/ReactiveExtensions.cs b/src/Main/Base/Project/Util/ReactiveExtensions.cs
index ea4d7d253f..bd5f2f7ee9 100644
--- a/src/Main/Base/Project/Util/ReactiveExtensions.cs
+++ b/src/Main/Base/Project/Util/ReactiveExtensions.cs
@@ -43,11 +43,38 @@ namespace ICSharpCode.SharpDevelop
#endregion
#region Create Observable from Task + Callback Delegate
+ ///
+ /// Converts an async function that produces a result collection using callbacks,
+ /// into an IObservable.
+ ///
+ ///
+ /// The async function will run once for each subscription on the observable.
+ ///
+ ///
+ /// The async function gets passed a cancellation token. This token will get signalled when the observable subscription is cancelled.
+ ///
public static IObservable CreateObservable(Func, Task> func)
{
return new AnonymousObservable(observer => new TaskToObserverSubscription(func, observer));
}
+ ///
+ /// Converts an async function that produces a result collection using callbacks,
+ /// into an IObservable.
+ ///
+ ///
+ /// The async function will run once for each subscription on the observable.
+ ///
+ ///
+ /// The progress monitor used to report progress. The monitor will be disposed after the async function
+ /// completes.
+ /// The async function is given a child monitor of this progress monitor: it forwards all
+ /// calls to the parent progress monitor, but uses a cancellation token that gets signalled
+ /// when the observable subscription is cancelled.
+ ///
+ ///
+ /// Multiple subscriptions on the observable do not work well together with progress reporting.
+ ///
public static IObservable CreateObservable(Func, Task> func, IProgressMonitor progressMonitor)
{
return new AnonymousObservable(observer => new TaskToObserverSubscription(func, progressMonitor, observer));
@@ -101,11 +128,122 @@ namespace ICSharpCode.SharpDevelop
}
#endregion
+ #region First/Single/Last
+ public static Task FirstAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return FirstInternalAsync(source, cancellationToken, true);
+ }
+
+ public static Task FirstOrDefaultAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return FirstInternalAsync(source, cancellationToken, false);
+ }
+
+ static async Task FirstInternalAsync(IObservable source, CancellationToken cancellationToken, bool throwIfEmpty)
+ {
+ var tcs = new TaskCompletionSource();
+ Action onCompleted;
+ if (throwIfEmpty)
+ onCompleted = () => tcs.TrySetException(new InvalidOperationException());
+ else
+ onCompleted = () => tcs.TrySetResult(default(T));
+ using (source.Subscribe(item => tcs.TrySetResult(item),
+ exception => tcs.TrySetException(exception),
+ onCompleted))
+ {
+ using (cancellationToken.Register(() => tcs.TrySetCanceled())) {
+ return await tcs.Task.ConfigureAwait(false);
+ }
+ }
+ }
+
+ public static Task SingleAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return SingleInternalAsync(source, cancellationToken, true);
+ }
+
+ public static Task SingleOrDefaultAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return SingleInternalAsync(source, cancellationToken, false);
+ }
+
+ static async Task SingleInternalAsync(IObservable source, CancellationToken cancellationToken, bool throwIfEmpty)
+ {
+ SemaphoreSlim gate = new SemaphoreSlim(0);
+ T value = default(T);
+ bool isEmpty = true;
+ Exception ex = null;
+ using (source.Subscribe(
+ item => {
+ if (isEmpty) {
+ value = item;
+ isEmpty = false;
+ } else {
+ ex = new InvalidOperationException("Sequence contains more than one element.");
+ gate.Release();
+ }
+ },
+ exception => {
+ ex = exception;
+ gate.Release();
+ },
+ () => {
+ gate.Release();
+ }))
+ {
+ await gate.WaitAsync(cancellationToken).ConfigureAwait(false);
+ }
+ if (ex != null)
+ throw ex;
+ if (isEmpty && throwIfEmpty)
+ throw new InvalidOperationException("Sequence contains no elements.");
+ return value;
+ }
+
+ public static Task LastAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return LastInternalAsync(source, cancellationToken, true);
+ }
+
+ public static Task LastOrDefaultAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return LastInternalAsync(source, cancellationToken, false);
+ }
+
+ static async Task LastInternalAsync(IObservable source, CancellationToken cancellationToken, bool throwIfEmpty)
+ {
+ SemaphoreSlim gate = new SemaphoreSlim(0);
+ T value = default(T);
+ bool isEmpty = true;
+ Exception ex = null;
+ using (source.Subscribe(
+ item => {
+ value = item;
+ isEmpty = false;
+ },
+ exception => {
+ ex = exception;
+ gate.Release();
+ },
+ () => {
+ gate.Release();
+ }))
+ {
+ await gate.WaitAsync(cancellationToken).ConfigureAwait(false);
+ }
+ if (ex != null)
+ throw ex;
+ if (isEmpty && throwIfEmpty)
+ throw new InvalidOperationException("Sequence contains no elements.");
+ return value;
+ }
+ #endregion
+
#region ToListAsync
///
/// Converts the observable into a List.
///
- public static async Task> ToListAsync(this IObservable source, CancellationToken cancellationToken)
+ public static async Task> ToListAsync(this IObservable source, CancellationToken cancellationToken = default(CancellationToken))
{
var tcs = new TaskCompletionSource>();
List results = new List();
diff --git a/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs b/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs
index 271c045908..26e6780aca 100644
--- a/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs
+++ b/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs
@@ -12,36 +12,55 @@ using Microsoft.Build.Logging;
namespace ICSharpCode.SharpDevelop.Project
{
+ ///
+ /// Implementation for the and lists.
+ ///
+ ///
+ /// This class provides thread-safe read access even if there is a concurrent write operation.
+ /// However, multiple concurrent writes are not supported.
+ /// The intended use is that only the main thread will write to this collection; but background threads may read at any time.
+ ///
class SolutionConfigurationOrPlatformNameCollection : IConfigurationOrPlatformNameCollection
{
public event ModelCollectionChangedEventHandler CollectionChanged;
-
+
readonly List list = new List();
- readonly Solution solution;
+ volatile IReadOnlyList listSnapshot = EmptyList.Instance;
+ readonly ISolution solution;
readonly bool isPlatform;
- public SolutionConfigurationOrPlatformNameCollection(Solution solution, bool isPlatform)
+ public SolutionConfigurationOrPlatformNameCollection(ISolution solution, bool isPlatform)
{
this.solution = solution;
this.isPlatform = isPlatform;
}
+ void OnCollectionChanged(IReadOnlyCollection oldItems, IReadOnlyCollection newItems)
+ {
+ this.listSnapshot = list.ToArray();
+ var eh = CollectionChanged;
+ if (eh != null)
+ eh(oldItems, newItems);
+ }
+
#region IReadOnlyCollection implementation
-
+
public int Count {
- get { return list.Count; }
+ get {
+ return listSnapshot.Count;
+ }
}
-
+
public IEnumerator GetEnumerator()
{
- return list.GetEnumerator();
+ return listSnapshot.GetEnumerator();
}
-
+
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
- return list.GetEnumerator();
+ return listSnapshot.GetEnumerator();
}
-
+
#endregion
public string ValidateName(string name)
@@ -59,6 +78,7 @@ namespace ICSharpCode.SharpDevelop.Project
void IConfigurationOrPlatformNameCollection.Add(string newName, string copyFrom)
{
+ SD.MainThread.VerifyAccess();
newName = ValidateName(newName);
if (newName == null)
throw new ArgumentException();
@@ -79,12 +99,13 @@ namespace ICSharpCode.SharpDevelop.Project
void IConfigurationOrPlatformNameCollection.Remove(string name)
{
+ SD.MainThread.VerifyAccess();
int pos = GetIndex(name);
- if (pos >= 0) {
- name = list[pos]; // get the name in original case
- list.RemoveAt(pos);
- OnCollectionChanged(new[] { name }, EmptyList.Instance);
- }
+ if (pos < 0)
+ return;
+ name = list[pos]; // get the name in original case
+ list.RemoveAt(pos);
+ OnCollectionChanged(new[] { name }, EmptyList.Instance);
}
void IConfigurationOrPlatformNameCollection.Rename(string oldName, string newName)
@@ -96,19 +117,22 @@ namespace ICSharpCode.SharpDevelop.Project
if (pos < 0)
throw new ArgumentException();
oldName = list[pos]; // get oldName in original case
- foreach (var project in solution.Projects) {
- throw new NotImplementedException();
- //project.ConfigurationMapping.RenameSolutionConfig(oldName, newName, isPlatform);
- }
list[pos] = newName;
+ listSnapshot = null;
OnCollectionChanged(new[] { oldName }, new[] { newName });
- }
-
- void OnCollectionChanged(IReadOnlyCollection oldItems, IReadOnlyCollection newItems)
- {
- if (CollectionChanged != null)
- CollectionChanged(oldItems, newItems);
- solution.IsDirty = true;
+
+ foreach (var project in solution.Projects) {
+ var mapping = project.ConfigurationMapping;
+ foreach (string otherName in isPlatform ? solution.ConfigurationNames : solution.PlatformNames) {
+ var oldSolutionConfig = isPlatform ? new ConfigurationAndPlatform(otherName, oldName) : new ConfigurationAndPlatform(oldName, otherName);
+ var newSolutionConfig = isPlatform ? new ConfigurationAndPlatform(otherName, newName) : new ConfigurationAndPlatform(newName, otherName);
+ var projectConfig = mapping.GetProjectConfiguration(oldSolutionConfig);
+ var buildEnabled = mapping.IsBuildEnabled(oldSolutionConfig);
+ mapping.Remove(oldSolutionConfig);
+ mapping.SetProjectConfiguration(newSolutionConfig, projectConfig);
+ mapping.SetBuildEnabled(newSolutionConfig, buildEnabled);
+ }
+ }
}
}
}
diff --git a/src/Main/SharpDevelop/Project/ProjectService.cs b/src/Main/SharpDevelop/Project/ProjectService.cs
index 6a3407795b..cbd6d51739 100644
--- a/src/Main/SharpDevelop/Project/ProjectService.cs
+++ b/src/Main/SharpDevelop/Project/ProjectService.cs
@@ -124,20 +124,21 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region OpenSolutionOrProject
- public event EventHandler SolutionLoaded = delegate {};
+ public event EventHandler SolutionOpened = delegate {};
- public void OpenSolutionOrProject(FileName fileName)
+ public bool OpenSolutionOrProject(FileName fileName)
{
- if (!IsProjectOrSolutionFile(fileName)) {
+ if (!IsSolutionOrProjectFile(fileName)) {
MessageService.ShowError(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Commands.OpenCombine.InvalidProjectOrCombine}", new StringTagPair("FileName", fileName)));
- return;
+ return false;
}
if (!CloseSolution(allowCancel: true))
- return;
- FileUtility.ObservedLoad(OpenSolutionOrProjectInternal, fileName);
+ return false;
+ FileUtility.ObservedLoad(OpenSolutionInternal, fileName);
+ return currentSolution != null;
}
- void OpenSolutionOrProjectInternal(FileName fileName)
+ void OpenSolutionInternal(FileName fileName)
{
ISolution solution;
using (var progress = AsynchronousWaitDialog.ShowWaitDialog("Loading Solution...")) {
@@ -153,7 +154,29 @@ namespace ICSharpCode.SharpDevelop.Project
this.CurrentSolution = solution;
}
- SolutionLoaded(this, new SolutionEventArgs(solution));
+ OnSolutionOpened(solution);
+ }
+
+ public bool OpenSolution(FileName fileName)
+ {
+ if (!CloseSolution(allowCancel: true))
+ return false;
+ FileUtility.ObservedLoad(OpenSolutionInternal, fileName);
+ return currentSolution != null;
+ }
+
+ public bool OpenSolution(ISolution solution)
+ {
+ if (!CloseSolution(allowCancel: true))
+ return false;
+ this.CurrentSolution = solution;
+ OnSolutionOpened(solution);
+ return true;
+ }
+
+ void OnSolutionOpened(ISolution solution)
+ {
+ SolutionOpened(this, new SolutionEventArgs(solution));
SD.FileService.RecentOpen.AddRecentProject(solution.FileName);
Project.Converter.UpgradeViewContent.ShowIfRequired(solution);
}
@@ -266,8 +289,8 @@ namespace ICSharpCode.SharpDevelop.Project
}
#endregion
- #region IsProjectOrSolutionFile
- public bool IsProjectOrSolutionFile(FileName fileName)
+ #region IsSolutionOrProjectFile
+ public bool IsSolutionOrProjectFile(FileName fileName)
{
AddInTreeNode addinTreeNode = SD.AddInTree.GetTreeNode("/SharpDevelop/Workbench/Combine/FileFilter");
foreach (Codon codon in addinTreeNode.Codons) {
diff --git a/src/Main/SharpDevelop/Project/Solution.cs b/src/Main/SharpDevelop/Project/Solution.cs
index 3af02b44e5..95c3133dce 100644
--- a/src/Main/SharpDevelop/Project/Solution.cs
+++ b/src/Main/SharpDevelop/Project/Solution.cs
@@ -27,6 +27,10 @@ namespace ICSharpCode.SharpDevelop.Project
this.ConfigurationNames = new SolutionConfigurationOrPlatformNameCollection(this, false);
this.PlatformNames = new SolutionConfigurationOrPlatformNameCollection(this, true);
this.FileName = fileName;
+ base.Name = fileName.GetFileNameWithoutExtension();
+
+ this.globalSections = new SynchronizedModelCollection(new NullSafeSimpleModelCollection());
+ globalSections.CollectionChanged += OnSolutionSectionCollectionChanged;
fileService.FileRenamed += FileServiceFileRenamed;
fileService.FileRemoved += FileServiceFileRemoved;
@@ -61,6 +65,15 @@ namespace ICSharpCode.SharpDevelop.Project
public DirectoryName Directory {
get { return directory; }
}
+
+ public override string Name {
+ get {
+ return base.Name;
+ }
+ set {
+ throw new NotImplementedException();
+ }
+ }
#endregion
#region StartupProject
@@ -100,8 +113,7 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region Project list
- SimpleModelCollection projects = new SimpleModelCollection();
- // TODO: thread-safety?
+ IMutableModelCollection projects = new SynchronizedModelCollection(new SimpleModelCollection());
public IModelCollection Projects {
get { return projects; }
@@ -134,6 +146,11 @@ namespace ICSharpCode.SharpDevelop.Project
}, DispatcherPriority.Background);
}
+ internal IDisposable ReportBatch()
+ {
+ return projects.BatchUpdate();
+ }
+
internal void ReportRemovedItem(ISolutionItem oldItem)
{
if (oldItem is ISolutionFolder) {
@@ -165,7 +182,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
- SimpleModelCollection globalSections = new SimpleModelCollection();
+ readonly IMutableModelCollection globalSections;
public IMutableModelCollection GlobalSections {
get { return globalSections; }
diff --git a/src/Main/SharpDevelop/Project/SolutionFolder.cs b/src/Main/SharpDevelop/Project/SolutionFolder.cs
index ea3a0dee19..7af6889fbf 100644
--- a/src/Main/SharpDevelop/Project/SolutionFolder.cs
+++ b/src/Main/SharpDevelop/Project/SolutionFolder.cs
@@ -53,13 +53,15 @@ namespace ICSharpCode.SharpDevelop.Project
protected override void OnCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems)
{
- foreach (ISolutionItem item in removedItems) {
- folder.parentSolution.ReportRemovedItem(item);
- item.ParentFolder = null;
- }
- foreach (ISolutionItem item in addedItems) {
- item.ParentFolder = folder;
- folder.parentSolution.ReportAddedItem(item);
+ using (folder.parentSolution.ReportBatch()) {
+ foreach (ISolutionItem item in removedItems) {
+ folder.parentSolution.ReportRemovedItem(item);
+ item.ParentFolder = null;
+ }
+ foreach (ISolutionItem item in addedItems) {
+ item.ParentFolder = folder;
+ folder.parentSolution.ReportAddedItem(item);
+ }
}
base.OnCollectionChanged(removedItems, addedItems);
folder.parentSolution.IsDirty = true;
@@ -73,7 +75,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
#endregion
- public string Name { get; set; }
+ public virtual string Name { get; set; }
public ISolutionFolder ParentFolder { get; set; }
diff --git a/src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs b/src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
index bad2517d52..a58aec0164 100644
--- a/src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
+++ b/src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
@@ -93,7 +93,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
try {
var fullFileName = FileName.Create(Path.GetFullPath(file));
- if (SD.ProjectService.IsProjectOrSolutionFile(fullFileName)) {
+ if (SD.ProjectService.IsSolutionOrProjectFile(fullFileName)) {
SD.ProjectService.OpenSolutionOrProject(fullFileName);
} else {
SharpDevelop.FileService.OpenFile(fullFileName);
diff --git a/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs b/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs
index 079b46e1ce..0110efe707 100644
--- a/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs
+++ b/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs
@@ -643,7 +643,7 @@ namespace ICSharpCode.SharpDevelop.Workbench
foreach (string file in files) {
if (File.Exists(file)) {
var fileName = FileName.Create(file);
- if (SD.ProjectService.IsProjectOrSolutionFile(fileName)) {
+ if (SD.ProjectService.IsSolutionOrProjectFile(fileName)) {
SD.ProjectService.OpenSolutionOrProject(fileName);
} else {
SD.FileService.OpenFile(fileName);