Browse Source

Fix various issues with the new solution model.

pull/32/merge
Daniel Grunwald 13 years ago
parent
commit
918b47ca70
  1. 3
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
  2. 1
      src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
  3. 6
      src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs
  4. 50
      src/AddIns/Misc/PackageManagement/Project/Src/NewProjectsCreated.cs
  5. 1
      src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
  6. 38
      src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs
  7. 102
      src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs
  8. 8
      src/Main/Base/Project/Dom/IModelCollection.cs
  9. 2
      src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs
  10. 13
      src/Main/Base/Project/Dom/SimpleModelCollection.cs
  11. 140
      src/Main/Base/Project/Dom/SynchronizedModelCollection.cs
  12. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  13. 9
      src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs
  14. 18
      src/Main/Base/Project/Project/IProjectService.cs
  15. 5
      src/Main/Base/Project/Project/ISolution.cs
  16. 28
      src/Main/Base/Project/Project/ProjectInformation.cs
  17. 75
      src/Main/Base/Project/Project/SolutionSection.cs
  18. 25
      src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs
  19. 2
      src/Main/Base/Project/Src/Gui/Pads/FileScout.cs
  20. 2
      src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs
  21. 1
      src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs
  22. 7
      src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs
  23. 2
      src/Main/Base/Project/Src/Project/AbstractProject.cs
  24. 10
      src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
  25. 4
      src/Main/Base/Project/Src/Project/MSBuildInternals.cs
  26. 6
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
  27. 4
      src/Main/Base/Project/Util/IProgressMonitor.cs
  28. 140
      src/Main/Base/Project/Util/ReactiveExtensions.cs
  29. 76
      src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs
  30. 43
      src/Main/SharpDevelop/Project/ProjectService.cs
  31. 23
      src/Main/SharpDevelop/Project/Solution.cs
  32. 18
      src/Main/SharpDevelop/Project/SolutionFolder.cs
  33. 2
      src/Main/SharpDevelop/Workbench/WorkbenchStartup.cs
  34. 2
      src/Main/SharpDevelop/Workbench/WpfWorkbench.cs

3
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs

@ -57,7 +57,8 @@ namespace CSharpBinding @@ -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";

1
src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj

@ -226,7 +226,6 @@ @@ -226,7 +226,6 @@
<Compile Include="Src\PackageManagementServiceProvider.cs" />
<Compile Include="Src\ProjectBuilder.cs" />
<Compile Include="Src\VirtualMethodUpdater.cs" />
<Compile Include="Src\NewProjectsCreated.cs" />
<Compile Include="Src\OpenMSBuildProjects.cs" />
<Compile Include="Src\PackageActionRunner.cs" />
<Compile Include="Src\PackageActionsToRun.cs" />

6
src/AddIns/Misc/PackageManagement/Project/Src/InstallProjectTemplatePackagesCommand.cs

@ -3,6 +3,7 @@ @@ -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 @@ -64,9 +65,8 @@ namespace ICSharpCode.PackageManagement
IEnumerable<MSBuildBasedProject> 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<MSBuildBasedProject>() : Enumerable.Empty<MSBuildBasedProject>();
}
IPackageReferencesForProject CreatePackageReferencesForProject(MSBuildBasedProject project)

50
src/AddIns/Misc/PackageManagement/Project/Src/NewProjectsCreated.cs

@ -1,50 +0,0 @@ @@ -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<MSBuildBasedProject> 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);
}
}
}

1
src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj

@ -195,7 +195,6 @@ @@ -195,7 +195,6 @@
<Compile Include="Src\OpenMSBuildProjectsTests.cs" />
<Compile Include="Src\PackageManagementServiceProviderTests.cs" />
<Compile Include="Src\VirtualMethodUpdaterTests.cs" />
<Compile Include="Src\NewProjectsCreatedTests.cs" />
<Compile Include="Src\PackageActionRunnerTests.cs" />
<Compile Include="Src\PackageActionsToRunTests.cs" />
<Compile Include="Src\PackageFilesTests.cs" />

38
src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs

@ -3,6 +3,7 @@ @@ -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 @@ -37,20 +38,18 @@ namespace PackageManagement.Tests
void RunCommandWithProjectCreateInfoAsOwner(List<TestableProject> 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<IProject>(projects));
command.FakeProjectService.ProjectCollections.Add(new ReadOnlyModelCollection<IProject>(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 @@ -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<IProject>();
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()
{

102
src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs

@ -1,102 +0,0 @@ @@ -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<MSBuildBasedProject>();
projects.Add(project);
return CreateProjectCreateInfo(projects);
}
ProjectCreateInformation CreateProjectCreateInfo(IEnumerable<MSBuildBasedProject> 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<MSBuildBasedProject>();
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<MSBuildBasedProject>();
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<MSBuildBasedProject>();
projects.AddRange(newProjectsCreated.GetProjects());
Assert.AreEqual(0, projects.Count);
}
}
}

8
src/Main/Base/Project/Dom/IModelCollection.cs

@ -36,6 +36,14 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -36,6 +36,14 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary>
public interface IMutableModelCollection<T> : IModelCollection<T>, ICollection<T>
{
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
/// <remarks>
/// Disambiguates between IReadOnlyCollection.Count and ICollection.Count
/// </remarks>
new int Count { get; }
/// <summary>
/// Adds the specified items to the collection.
/// </summary>

2
src/Main/Base/Project/Dom/ReadOnlyModelCollection.cs

@ -1,5 +1,5 @@ @@ -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;

13
src/Main/Base/Project/Dom/SimpleModelCollection.cs

@ -202,5 +202,18 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -202,5 +202,18 @@ namespace ICSharpCode.SharpDevelop.Dom
#endregion
}
/// <summary>
/// A model collection implementation that disallows null values.
/// </summary>
public class NullSafeSimpleModelCollection<T> : SimpleModelCollection<T> where T : class
{
protected override void ValidateItem(T item)
{
if (item == null)
throw new ArgumentNullException("item");
base.ValidateItem(item);
}
}
}

140
src/Main/Base/Project/Dom/SynchronizedModelCollection.cs

@ -0,0 +1,140 @@ @@ -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
{
/// <summary>
/// Synchronizing wrapper around IMutableModelCollection.
/// </summary>
public class SynchronizedModelCollection<T> : IMutableModelCollection<T>
{
readonly IMutableModelCollection<T> underlyingCollection;
readonly object syncRoot;
public SynchronizedModelCollection(IMutableModelCollection<T> underlyingCollection)
: this(underlyingCollection, new object())
{
}
public SynchronizedModelCollection(IMutableModelCollection<T> 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<T> 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<T> items)
{
lock (syncRoot) {
underlyingCollection.AddRange(items);
}
}
public bool Remove(T item)
{
lock (syncRoot) {
return underlyingCollection.Remove(item);
}
}
public int RemoveAll(Predicate<T> 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<T> GetEnumerator()
{
IEnumerable<T> 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
}
}

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -95,6 +95,7 @@ @@ -95,6 +95,7 @@
<Compile Include="Dom\ModelCollectionLinq.cs" />
<Compile Include="Dom\ReadOnlyModelCollection.cs" />
<Compile Include="Dom\SimpleModelCollection.cs" />
<Compile Include="Dom\SynchronizedModelCollection.cs" />
<Compile Include="Editor\AvalonEditTextEditorAdapter.cs" />
<Compile Include="Editor\Bookmarks\BookmarkBase.cs" />
<Compile Include="Editor\Bookmarks\BookmarkEventArgs.cs" />

9
src/Main/Base/Project/Project/Configuration/ConfigurationMapping.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -29,7 +29,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary>
/// The configuration mapping was changed.
/// </summary>
public event EventHandler Changed;
public event EventHandler Changed = delegate { };
Dictionary<ConfigurationAndPlatform, Entry> dict = new Dictionary<ConfigurationAndPlatform, Entry>();
@ -66,10 +66,13 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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);
}

18
src/Main/Base/Project/Project/IProjectService.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -28,7 +28,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary>
/// This event is raised after a solution is opened.
/// </summary>
event EventHandler<SolutionEventArgs> SolutionLoaded;
event EventHandler<SolutionEventArgs> SolutionOpened;
/// <summary>
/// This event is raised before a solution is closed.
@ -76,7 +76,17 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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.
/// </remarks>
void OpenSolutionOrProject(FileName fileName);
bool OpenSolutionOrProject(FileName fileName);
/// <summary>
/// Opens a solution in the IDE.
/// </summary>
bool OpenSolution(FileName fileName);
/// <summary>
/// Opens a solution in the IDE that was created/loaded earlier.
/// </summary>
bool OpenSolution(ISolution solution);
/// <summary>
/// Closes the solution: cancels build, clears solution data, fires the SolutionClosing and SolutionClosed events.
@ -91,13 +101,13 @@ namespace ICSharpCode.SharpDevelop.Project @@ -91,13 +101,13 @@ namespace ICSharpCode.SharpDevelop.Project
bool CloseSolution(bool allowCancel = true);
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// This method is thread-safe.
/// </remarks>
bool IsProjectOrSolutionFile(FileName fileName);
bool IsSolutionOrProjectFile(FileName fileName);
/// <summary>
/// Loads a solution file without opening it in the IDE.

5
src/Main/Base/Project/Project/ISolution.cs

@ -19,6 +19,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -19,6 +19,11 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary>
/// Represents a solution.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public interface ISolution : ISolutionFolder, ICanBeDirty, IConfigurable, IDisposable
{
Microsoft.Build.Evaluation.ProjectCollection MSBuildProjectCollection { get; }

28
src/Main/Base/Project/Project/ProjectInformation.cs

@ -3,6 +3,7 @@ @@ -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 @@ -24,23 +25,47 @@ namespace ICSharpCode.SharpDevelop.Project
this.ProjectSections = new List<SolutionSection>();
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; }
/// <summary>
/// Specifies the mapping between solution configurations and project configurations.
/// </summary>
public ConfigurationMapping ConfigurationMapping { get; set; }
/// <summary>
/// Specified the project configuration that should be initially active when the project is loaded.
/// </summary>
public ConfigurationAndPlatform ActiveProjectConfiguration { get; set; }
public IList<SolutionSection> ProjectSections { get; private set; }
public string ProjectName { get; set; }
/// <summary>
/// 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)
/// </summary>
public Guid IdGuid { get; set; }
/// <summary>
/// Specifies the type GUID for the project.
/// Necessary for both project creation and loading.
/// </summary>
public Guid TypeGuid { get; set; }
/// <summary>
/// Specifies whether to initialize the type system for the project.
/// The default is <c>true</c>.
/// </summary>
public bool InitializeTypeSystem { get; set; }
}
/// <summary>
@ -91,6 +116,5 @@ namespace ICSharpCode.SharpDevelop.Project @@ -91,6 +116,5 @@ namespace ICSharpCode.SharpDevelop.Project
public string RootNamespace { get; set; }
public TargetFramework TargetFramework { get; set; }
public bool InitializeTypeSystem { get; set; }
}
}

75
src/Main/Base/Project/Project/SolutionSection.cs

@ -74,47 +74,56 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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<string, string>(key, value));
lock (entries)
entries.Add(new KeyValuePair<string, string>(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 @@ -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<string, string>(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<string, string>(key, value);
found = true;
break;
}
}
if (!found)
entries.Add(new KeyValuePair<string, string>(key, value));
}
Add(key, value);
Changed(this, EventArgs.Empty);
}
}
public IEnumerable<string> Keys {
get {
return entries.Select(e => e.Key);
lock (entries)
return entries.Select(e => e.Key).ToArray();
}
}
public IEnumerable<string> Values {
get {
return entries.Select(e => e.Value);
lock (entries)
return entries.Select(e => e.Value).ToArray();
}
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return entries.GetEnumerator();
lock (entries)
return entries.ToList().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return entries.GetEnumerator();
return GetEnumerator();
}
}
}

25
src/Main/Base/Project/Src/Gui/Dialogs/NewProjectDialog.cs

@ -353,20 +353,21 @@ namespace ICSharpCode.SharpDevelop.Project.Dialogs @@ -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);

2
src/Main/Base/Project/Src/Gui/Pads/FileScout.cs

@ -399,7 +399,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -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);

2
src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs

@ -100,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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);

1
src/Main/Base/Project/Src/Internal/Templates/Project/ProjectDescriptor.cs

@ -507,6 +507,7 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates @@ -507,6 +507,7 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates
ProjectService.OnProjectCreated(new ProjectEventArgs(project));
projectCreateOptions.CreatedProjects.Add(project);
success = true;
return project;
} finally {

7
src/Main/Base/Project/Src/Internal/Templates/Project/ProjectTemplate.cs

@ -26,6 +26,13 @@ namespace ICSharpCode.SharpDevelop.Internal.Templates @@ -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<IProject> CreatedProjects { get; private set; }
public ProjectCreateOptions()
{
this.CreatedProjects = new List<IProject>();
}
}
/// <summary>

2
src/Main/Base/Project/Src/Project/AbstractProject.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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);

10
src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs

@ -62,6 +62,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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 @@ -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 @@ -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;
}
}

4
src/Main/Base/Project/Src/Project/MSBuildInternals.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -87,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
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 @@ -100,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public static string FixPlatformNameForSolution(string platformName)
{
if (platformName == "AnyCPU") {
if (ConfigurationAndPlatform.ConfigurationNameComparer.Equals(platformName, "AnyCPU")) {
return "Any CPU";
} else {
return platformName;

6
src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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 @@ -198,8 +198,8 @@ namespace ICSharpCode.SharpDevelop.Project
}
public static event EventHandler<SolutionEventArgs> 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<SolutionEventArgs> SolutionClosed {

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

@ -39,6 +39,10 @@ namespace ICSharpCode.SharpDevelop @@ -39,6 +39,10 @@ namespace ICSharpCode.SharpDevelop
/// </summary>
/// <param name="workAmount">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.</param>
/// <param name="childCancellationToken">
/// A cancellation token that can be used to cancel the sub-task.
/// Note: cancelling the main task will not cancel the sub-task.
/// </param>
/// <returns>A new progress monitor representing the sub-task.
/// Multiple child progress monitors can be used at once; even concurrently on multiple threads.</returns>
IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken);

140
src/Main/Base/Project/Util/ReactiveExtensions.cs

@ -43,11 +43,38 @@ namespace ICSharpCode.SharpDevelop @@ -43,11 +43,38 @@ namespace ICSharpCode.SharpDevelop
#endregion
#region Create Observable from Task + Callback Delegate
/// <summary>
/// Converts an async function that produces a result collection using callbacks,
/// into an IObservable.
/// </summary>
/// <param name="func">
/// The async function will run once for each subscription on the observable.
/// </param>
/// <remarks>
/// The async function gets passed a cancellation token. This token will get signalled when the observable subscription is cancelled.
/// </remarks>
public static IObservable<T> CreateObservable<T>(Func<CancellationToken, Action<T>, Task> func)
{
return new AnonymousObservable<T>(observer => new TaskToObserverSubscription<T>(func, observer));
}
/// <summary>
/// Converts an async function that produces a result collection using callbacks,
/// into an IObservable.
/// </summary>
/// <param name="func">
/// The async function will run once for each subscription on the observable.
/// </param>
/// <param name="progressMonitor">
/// 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.
/// </param>
/// <remarks>
/// Multiple subscriptions on the observable do not work well together with progress reporting.
/// </remarks>
public static IObservable<T> CreateObservable<T>(Func<IProgressMonitor, Action<T>, Task> func, IProgressMonitor progressMonitor)
{
return new AnonymousObservable<T>(observer => new TaskToObserverSubscription<T>(func, progressMonitor, observer));
@ -101,11 +128,122 @@ namespace ICSharpCode.SharpDevelop @@ -101,11 +128,122 @@ namespace ICSharpCode.SharpDevelop
}
#endregion
#region First/Single/Last
public static Task<T> FirstAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return FirstInternalAsync(source, cancellationToken, true);
}
public static Task<T> FirstOrDefaultAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return FirstInternalAsync(source, cancellationToken, false);
}
static async Task<T> FirstInternalAsync<T>(IObservable<T> source, CancellationToken cancellationToken, bool throwIfEmpty)
{
var tcs = new TaskCompletionSource<T>();
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<T> SingleAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return SingleInternalAsync(source, cancellationToken, true);
}
public static Task<T> SingleOrDefaultAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return SingleInternalAsync(source, cancellationToken, false);
}
static async Task<T> SingleInternalAsync<T>(IObservable<T> 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<T> LastAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return LastInternalAsync(source, cancellationToken, true);
}
public static Task<T> LastOrDefaultAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
return LastInternalAsync(source, cancellationToken, false);
}
static async Task<T> LastInternalAsync<T>(IObservable<T> 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
/// <summary>
/// Converts the observable into a List.
/// </summary>
public static async Task<List<T>> ToListAsync<T>(this IObservable<T> source, CancellationToken cancellationToken)
public static async Task<List<T>> ToListAsync<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken))
{
var tcs = new TaskCompletionSource<List<T>>();
List<T> results = new List<T>();

76
src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs

@ -12,36 +12,55 @@ using Microsoft.Build.Logging; @@ -12,36 +12,55 @@ using Microsoft.Build.Logging;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// Implementation for the <see cref="ISolution.ConfigurationNames"/> and <see cref="ISolution.PlatformNames"/> lists.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
class SolutionConfigurationOrPlatformNameCollection : IConfigurationOrPlatformNameCollection
{
public event ModelCollectionChangedEventHandler<string> CollectionChanged;
readonly List<string> list = new List<string>();
readonly Solution solution;
volatile IReadOnlyList<string> listSnapshot = EmptyList<string>.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<string> oldItems, IReadOnlyCollection<string> 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<string> 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 @@ -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 @@ -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<string>.Instance);
}
if (pos < 0)
return;
name = list[pos]; // get the name in original case
list.RemoveAt(pos);
OnCollectionChanged(new[] { name }, EmptyList<string>.Instance);
}
void IConfigurationOrPlatformNameCollection.Rename(string oldName, string newName)
@ -96,19 +117,22 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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<string> oldItems, IReadOnlyCollection<string> 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);
}
}
}
}
}

43
src/Main/SharpDevelop/Project/ProjectService.cs

@ -124,20 +124,21 @@ namespace ICSharpCode.SharpDevelop.Project @@ -124,20 +124,21 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region OpenSolutionOrProject
public event EventHandler<SolutionEventArgs> SolutionLoaded = delegate {};
public event EventHandler<SolutionEventArgs> 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 @@ -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 @@ -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) {

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

@ -27,6 +27,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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<SolutionSection>(new NullSafeSimpleModelCollection<SolutionSection>());
globalSections.CollectionChanged += OnSolutionSectionCollectionChanged;
fileService.FileRenamed += FileServiceFileRenamed;
fileService.FileRemoved += FileServiceFileRemoved;
@ -61,6 +65,15 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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 @@ -100,8 +113,7 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region Project list
SimpleModelCollection<IProject> projects = new SimpleModelCollection<IProject>();
// TODO: thread-safety?
IMutableModelCollection<IProject> projects = new SynchronizedModelCollection<IProject>(new SimpleModelCollection<IProject>());
public IModelCollection<IProject> Projects {
get { return projects; }
@ -134,6 +146,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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 @@ -165,7 +182,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
SimpleModelCollection<SolutionSection> globalSections = new SimpleModelCollection<SolutionSection>();
readonly IMutableModelCollection<SolutionSection> globalSections;
public IMutableModelCollection<SolutionSection> GlobalSections {
get { return globalSections; }

18
src/Main/SharpDevelop/Project/SolutionFolder.cs

@ -53,13 +53,15 @@ namespace ICSharpCode.SharpDevelop.Project @@ -53,13 +53,15 @@ namespace ICSharpCode.SharpDevelop.Project
protected override void OnCollectionChanged(IReadOnlyCollection<ISolutionItem> removedItems, IReadOnlyCollection<ISolutionItem> 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 @@ -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; }

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

@ -93,7 +93,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -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);

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

@ -643,7 +643,7 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -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);

Loading…
Cancel
Save