diff --git a/src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs b/src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs index b732fa190f..4b7761c9bb 100644 --- a/src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs +++ b/src/AddIns/Analysis/UnitTesting/Test/NUnit/CreateNUnitTestRunnerTestFixture.cs @@ -22,6 +22,7 @@ namespace UnitTesting.Tests.NUnit { base.FixtureSetUp(); SD.Services.AddService(typeof(IBookmarkManager), MockRepository.GenerateStub()); + SD.Services.AddService(typeof(IProjectService), MockRepository.GenerateStub()); project = MockRepository.GenerateStub(); testProject = new NUnitTestProject(project); } diff --git a/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs b/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs index 9e76740c04..f6dbeda189 100644 --- a/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs +++ b/src/AddIns/Analysis/UnitTesting/TestRunner/TestExecutionManager.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.UnitTesting.Frameworks cancellationToken.ThrowIfCancellationRequested(); using (IProgressMonitor progressMonitor = statusBarService.CreateProgressMonitor(cancellationToken)) { int projectsLeftToRun = testsByProject.Count; - foreach (IGrouping g in testsByProject) { + foreach (IGrouping g in testsByProject.OrderBy(g => g.Key.DisplayName)) { currentProjectBeingTested = g.Key; progressMonitor.TaskName = GetProgressMonitorLabel(currentProjectBeingTested); progressMonitor.Progress = GetProgress(projectsLeftToRun); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs index 38e71724bd..136e0c77f9 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.Core; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.Editor; @@ -49,7 +50,7 @@ namespace CSharpBinding.Refactoring EntityDeclaration node = (EntityDeclaration)st.GetNodeAt(context.CaretLocation, n => n is TypeDeclaration || n is DelegateDeclaration); IDocument document = context.Editor.Document; - string newFileName = Path.Combine(Path.GetDirectoryName(context.FileName), MakeValidFileName(node.Name)); + FileName newFileName = FileName.Create(Path.Combine(Path.GetDirectoryName(context.FileName), MakeValidFileName(node.Name))); string header = CopyFileHeader(document, info); string footer = CopyFileEnd(document, info); diff --git a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbench.cs b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbench.cs index 64c86331b7..e0211107fb 100644 --- a/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbench.cs +++ b/src/AddIns/BackendBindings/WixBinding/Test/Utils/MockWorkbench.cs @@ -175,7 +175,7 @@ namespace WixBinding.Tests.Utils } } - public bool CloseAllSolutionViews() + public bool CloseAllSolutionViews(bool force) { throw new NotImplementedException(); } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs index c64e3f6b04..fc787df5fd 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.Snippets throw new ArgumentException("textEditor must be an AvalonEdit text editor"); this.codeSnippet = codeSnippet; - this.Priority = CodeCompletionDataUsageCache.GetPriority("snippet" + codeSnippet.Name, true); + //this.Priority = CodeCompletionDataUsageCache.GetPriority("snippet" + codeSnippet.Name, true); } public bool AlwaysInsertSnippet { get; set; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs index 3b9aa8b006..b24abf5d4b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.PackageManagement; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -17,54 +18,29 @@ namespace ICSharpCode.PackageManagement.Design public IProject CurrentProject { get; set; } public ISolution OpenSolution { get; set; } - public event EventHandler ProjectAdded; - public event SolutionFolderEventHandler SolutionFolderRemoved; - public event EventHandler SolutionClosed; - public event EventHandler SolutionLoaded; + public event EventHandler SolutionClosed; public void RefreshProjectBrowser() { IsRefreshProjectBrowserCalled = true; - } - - public void FireProjectAddedEvent(IProject project) - { - if (ProjectAdded != null) { - ProjectAdded(this, new ProjectEventArgs(project)); - } } - public void FireSolutionClosedEvent() + public void FireSolutionClosedEvent(ISolution solution) { if (SolutionClosed != null) { - SolutionClosed(this, new EventArgs()); - } - } - - public void FireSolutionLoadedEvent(ISolution solution) - { - if (SolutionLoaded != null) { - SolutionLoaded(this, new SolutionEventArgs(solution)); - } - } - - public void FireSolutionFolderRemoved(ISolutionItem solutionFolder) - { - if (SolutionFolderRemoved != null) { - SolutionFolderRemoved(this, new SolutionFolderEventArgs(solutionFolder)); + SolutionClosed(this, new SolutionEventArgs(solution)); } } - public List FakeOpenProjects = new List(); + public readonly ConcatModelCollection AllProjects = new ConcatModelCollection(); - public void AddFakeProject(IProject project) - { - FakeOpenProjects.Add(project); + IModelCollection IPackageManagementProjectService.AllProjects { + get { return AllProjects; } } - public IEnumerable GetOpenProjects() + public void AddProject(IProject project) { - return FakeOpenProjects; + AllProjects.Inputs.Add(new ReadOnlyModelCollection(new[] { project })); } public void AddProjectItem(IProject project, ProjectItem item) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs index 26c72dad3c..c11d16c32d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -15,10 +16,7 @@ namespace ICSharpCode.PackageManagement ISolution OpenSolution { get; } IProjectBuilder ProjectBuilder { get; } - event EventHandler ProjectAdded; - event SolutionFolderEventHandler SolutionFolderRemoved; - event EventHandler SolutionClosed; - event EventHandler SolutionLoaded; + event EventHandler SolutionClosed; void RefreshProjectBrowser(); void AddProjectItem(IProject project, ProjectItem item); @@ -26,7 +24,7 @@ namespace ICSharpCode.PackageManagement void Save(IProject project); void Save(ISolution solution); - IEnumerable GetOpenProjects(); + IModelCollection AllProjects { get; } //IProjectContent GetProjectContent(IProject project); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/OpenMSBuildProjects.cs b/src/AddIns/Misc/PackageManagement/Project/Src/OpenMSBuildProjects.cs index 8a6fc325e0..8cedb0dbef 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/OpenMSBuildProjects.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/OpenMSBuildProjects.cs @@ -19,7 +19,7 @@ namespace ICSharpCode.PackageManagement public MSBuildBasedProject FindProject(string name) { - foreach (IProject project in projectService.GetOpenProjects()) { + foreach (IProject project in projectService.AllProjects) { if (IsProjectNameMatch(project, name)) { return project as MSBuildBasedProject; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs index c59f3e8878..008be46c99 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs @@ -7,6 +7,7 @@ using System.Linq; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project.Commands; @@ -48,13 +49,8 @@ namespace ICSharpCode.PackageManagement return SD.MainThread.InvokeIfRequired(callback); } - public IEnumerable GetOpenProjects() - { - ISolution solution = OpenSolution; - if (solution != null) { - return solution.Projects; - } - return new IProject[0]; + public IModelCollection AllProjects { + get { return SD.ProjectService.AllProjects; } } public void AddProjectItem(IProject project, ProjectItem item) @@ -82,26 +78,11 @@ namespace ICSharpCode.PackageManagement // return SD.ParserService.GetProjectContent(project); // } - public event EventHandler ProjectAdded { - add { ProjectService.ProjectAdded += value; } - remove { ProjectService.ProjectAdded -= value; } + public event EventHandler SolutionClosed { + add { SD.ProjectService.SolutionClosed += value; } + remove { SD.ProjectService.SolutionClosed -= value; } } - public event EventHandler SolutionClosed { - add { ProjectService.SolutionClosed += value; } - remove { ProjectService.SolutionClosed -= value; } - } - - public event EventHandler SolutionLoaded { - add { ProjectService.SolutionLoaded += value; } - remove { ProjectService.SolutionLoaded -= value; } - } - - public event SolutionFolderEventHandler SolutionFolderRemoved { - add { ProjectService.SolutionFolderRemoved += value; } - remove { ProjectService.SolutionFolderRemoved -= value; } - } - public IProjectBrowserUpdater CreateProjectBrowserUpdater() { return new ThreadSafeProjectBrowserUpdater(); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementSolution.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementSolution.cs index c1def79231..76adf3db21 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementSolution.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementSolution.cs @@ -126,7 +126,7 @@ namespace ICSharpCode.PackageManagement public IEnumerable GetMSBuildProjects() { - return projectService.GetOpenProjects(); + return projectService.AllProjects; } public bool IsOpen { @@ -135,7 +135,7 @@ namespace ICSharpCode.PackageManagement public bool HasMultipleProjects() { - return projectService.GetOpenProjects().Count() > 1; + return projectService.AllProjects.Count > 1; } public bool IsPackageInstalled(IPackage package) @@ -169,7 +169,7 @@ namespace ICSharpCode.PackageManagement public IEnumerable GetProjects(IPackageRepository sourceRepository) { - foreach (MSBuildBasedProject msbuildProject in GetMSBuildProjects()) { + foreach (MSBuildBasedProject msbuildProject in GetMSBuildProjects().OfType()) { yield return projectFactory.CreateProject(sourceRepository, msbuildProject); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleViewModel.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleViewModel.cs index 712e7f4c3a..4314fcf513 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleViewModel.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleViewModel.cs @@ -10,6 +10,8 @@ using System.Windows.Input; using ICSharpCode.AvalonEdit; using ICSharpCode.Scripting; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; using NuGet; @@ -26,8 +28,6 @@ namespace ICSharpCode.PackageManagement.Scripting ObservableCollection packageSources = new ObservableCollection(); PackageSourceViewModel activePackageSource; - ObservableCollection projects = new ObservableCollection(); - PackageManagementConsole packageManagementConsole; public PackageManagementConsoleViewModel( @@ -47,7 +47,7 @@ namespace ICSharpCode.PackageManagement.Scripting CreateCommands(); UpdatePackageSourceViewModels(); ReceiveNotificationsWhenPackageSourcesUpdated(); - AddProjects(); + UpdateDefaultProject(); ReceiveNotificationsWhenSolutionIsUpdated(); InitConsoleHost(); } @@ -137,57 +137,18 @@ namespace ICSharpCode.PackageManagement.Scripting UpdatePackageSourceViewModels(); } - void AddProjects() - { - ISolution solution = projectService.OpenSolution; - if (solution != null) { - AddProjects(solution); - } - UpdateDefaultProject(); - } - void UpdateDefaultProject() { - DefaultProject = projects.FirstOrDefault(); - } - - void AddProjects(ISolution solution) - { - foreach (IProject project in solution.Projects) { - projects.Add(project); - } + DefaultProject = this.Projects.FirstOrDefault(); } void ReceiveNotificationsWhenSolutionIsUpdated() { - projectService.ProjectAdded += ProjectAdded; - projectService.SolutionClosed += SolutionClosed; - projectService.SolutionLoaded += SolutionLoaded; - projectService.SolutionFolderRemoved += SolutionFolderRemoved; - } - - void ProjectAdded(object sender, ProjectEventArgs e) - { - projects.Add(e.Project); - UpdateDefaultProject(); - } - - void SolutionClosed(object sender, EventArgs e) - { - projects.Clear(); - DefaultProject = null; - } - - void SolutionLoaded(object sender, SolutionEventArgs e) - { - AddProjects(e.Solution); - UpdateDefaultProject(); + projectService.AllProjects.CollectionChanged += OnProjectCollectionChanged; } - void SolutionFolderRemoved(object sender, SolutionFolderEventArgs e) + void OnProjectCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - IProject project = e.SolutionFolder as IProject; - projects.Remove(project); UpdateDefaultProject(); } @@ -212,8 +173,8 @@ namespace ICSharpCode.PackageManagement.Scripting return null; } - public ObservableCollection Projects { - get { return projects; } + public IModelCollection Projects { + get { return projectService.AllProjects; } } public IProject DefaultProject { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeMessageService.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeMessageService.cs index f28802e563..25b6d6cb8b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeMessageService.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeMessageService.cs @@ -45,11 +45,11 @@ namespace PackageManagement.Tests.Helpers { } - public void InformSaveError(string fileName, string message, string dialogName, Exception exceptionGot) + public void InformSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot) { } - public ChooseSaveErrorResult ChooseSaveError(string fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) + public ChooseSaveErrorResult ChooseSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) { return ChooseSaveErrorResult.Ignore; } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs index f14caf2f28..f762031b75 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/InstallProjectTemplatePackagesCommandTests.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using ICSharpCode.PackageManagement; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Internal.Templates; using ICSharpCode.SharpDevelop.Project; using NUnit.Framework; @@ -38,7 +40,7 @@ namespace PackageManagement.Tests var createInfo = new ProjectCreateInformation(projects); createInfo.Solution = projects[0].ParentSolution; - command.FakeProjectService.FakeOpenProjects.AddRange(projects); + command.FakeProjectService.AllProjects.Inputs.Add(new ReadOnlyModelCollection(projects)); RunCommandWithProjectCreateInfoAsOwner(createInfo); } @@ -80,7 +82,7 @@ namespace PackageManagement.Tests var createInfo = new ProjectCreateInformation(projects); TestableProject expectedProject = ProjectHelper.CreateTestProject("TEST"); - command.FakeProjectService.FakeOpenProjects.Add(expectedProject); + command.FakeProjectService.AddProject(expectedProject); RunCommandWithProjectCreateInfoAsOwner(createInfo); diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs index c17644e4d2..5f0b8a7d7b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/NewProjectsCreatedTests.cs @@ -44,7 +44,7 @@ namespace PackageManagement.Tests TestableProject AddProjectToProjectServiceOpenProjects(string projectName) { TestableProject project = CreateProject(projectName); - fakeProjectService.FakeOpenProjects.Add(project); + fakeProjectService.AddProject(project); return project; } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/OpenMSBuildProjectsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/OpenMSBuildProjectsTests.cs index f5fb26e111..01ea08b724 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/OpenMSBuildProjectsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/OpenMSBuildProjectsTests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using ICSharpCode.Core; using ICSharpCode.PackageManagement; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; using NUnit.Framework; using PackageManagement.Tests.Helpers; @@ -17,13 +18,13 @@ namespace PackageManagement.Tests { OpenMSBuildProjects projects; IPackageManagementProjectService fakeProjectService; - List openProjects; + SimpleModelCollection openProjects; void CreateOpenMSBuildProjects() { fakeProjectService = MockRepository.GenerateStub(); - openProjects = new List(); - fakeProjectService.Stub(service => service.GetOpenProjects()).Return(openProjects); + openProjects = new SimpleModelCollection(); + fakeProjectService.Stub(service => service.AllProjects).Return(openProjects); projects = new OpenMSBuildProjects(fakeProjectService); } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/PackageManagementSolutionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/PackageManagementSolutionTests.cs index eb9bf2f984..c341717628 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/PackageManagementSolutionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/PackageManagementSolutionTests.cs @@ -63,7 +63,7 @@ namespace PackageManagement.Tests TestableProject AddProjectToOpenProjects(string projectName) { TestableProject project = ProjectHelper.CreateTestProject(projectName); - fakeProjectService.FakeOpenProjects.Add(project); + fakeProjectService.AddProject(project); return project; } @@ -308,7 +308,7 @@ namespace PackageManagement.Tests AddProjectToOpenProjects("B"); IEnumerable projects = solution.GetMSBuildProjects(); - List expectedProjects = fakeProjectService.FakeOpenProjects; + IEnumerable expectedProjects = fakeProjectService.AllProjects; CollectionAssert.AreEqual(expectedProjects, projects); } @@ -351,7 +351,7 @@ namespace PackageManagement.Tests { CreateSolution(); TestableProject project = ProjectHelper.CreateTestProject(); - fakeProjectService.AddFakeProject(project); + fakeProjectService.AddProject(project); bool hasMultipleProjects = solution.HasMultipleProjects(); @@ -363,9 +363,9 @@ namespace PackageManagement.Tests { CreateSolution(); TestableProject project1 = ProjectHelper.CreateTestProject(); - fakeProjectService.AddFakeProject(project1); + fakeProjectService.AddProject(project1); TestableProject project2 = ProjectHelper.CreateTestProject(); - fakeProjectService.AddFakeProject(project2); + fakeProjectService.AddProject(project2); bool hasMultipleProjects = solution.HasMultipleProjects(); diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleViewModelTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleViewModelTests.cs index 85a868a758..c71ba6ff8c 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleViewModelTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleViewModelTests.cs @@ -102,6 +102,7 @@ namespace PackageManagement.Tests.Scripting ISolution solution = CreateSolutionWithOneProject(); projectService = new FakePackageManagementProjectService(); projectService.OpenSolution = solution; + projectService.AllProjects.Inputs.Add(solution.Projects); CreateViewModel(consoleHost, projectService); return solution; @@ -150,6 +151,7 @@ namespace PackageManagement.Tests.Scripting var solution = ProjectHelper.CreateSolution(); projectService = new FakePackageManagementProjectService(); projectService.OpenSolution = solution; + projectService.AllProjects.Inputs.Add(solution.Projects); CreateViewModel(consoleHost, projectService); return solution; } @@ -162,14 +164,16 @@ namespace PackageManagement.Tests.Scripting void CloseSolution() { + ISolution solution = projectService.OpenSolution; projectService.OpenSolution = null; - projectService.FireSolutionClosedEvent(); + projectService.AllProjects.Inputs.Remove(solution.Projects); + projectService.FireSolutionClosedEvent(solution); } void OpenSolution(ISolution solution) { projectService.OpenSolution = solution; - projectService.FireSolutionLoadedEvent(solution); + projectService.AllProjects.Inputs.Add(solution.Projects); } IProject RemoveProjectFromSolution(ISolution solution) @@ -320,7 +324,6 @@ namespace PackageManagement.Tests.Scripting { var solution = CreateViewModelWithEmptySolutionOpen(); var project = AddProjectToSolution(solution); - projectService.FireProjectAddedEvent(project); var actualProjects = viewModel.Projects; var expectedProjects = solution.Projects; @@ -333,7 +336,6 @@ namespace PackageManagement.Tests.Scripting { var solution = CreateViewModelWithEmptySolutionOpen(); var project = AddProjectToSolution(solution); - projectService.FireProjectAddedEvent(project); var actualProject = viewModel.DefaultProject; @@ -393,7 +395,7 @@ namespace PackageManagement.Tests.Scripting OpenSolution(solution); var actualProject = viewModel.DefaultProject; - var expectedProject = viewModel.Projects[0]; + var expectedProject = viewModel.Projects.FirstOrDefault(); Assert.AreEqual(expectedProject, actualProject); } @@ -416,7 +418,6 @@ namespace PackageManagement.Tests.Scripting { var solution = CreateViewModelWithOneProjectOpen(); var project = RemoveProjectFromSolution(solution); - projectService.FireSolutionFolderRemoved(project); var actualProjects = viewModel.Projects; var expectedProjects = solution.Projects; @@ -429,25 +430,12 @@ namespace PackageManagement.Tests.Scripting { var solution = CreateViewModelWithOneProjectOpen(); var project = RemoveProjectFromSolution(solution); - projectService.FireSolutionFolderRemoved(project); var actualProject = viewModel.DefaultProject; Assert.IsNull(actualProject); } - [Test] - public void Projects_SolutionFolderRemovedFromSolution_ProjectListIsUnchanged() - { - var solution = CreateViewModelWithOneProjectOpen(); - var solutionFolder = MockRepository.GenerateStrictMock(); - projectService.FireSolutionFolderRemoved(solutionFolder); - - int count = viewModel.Projects.Count; - - Assert.AreEqual(1, count); - } - [Test] public void DefaultProject_OneProjectOpenWhenConsoleCreated_DefaultProjectSetForConsole() { diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/ResetPowerShellWorkingDirectoryOnSolutionClosedTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/ResetPowerShellWorkingDirectoryOnSolutionClosedTests.cs index 9f231218a6..ab403dd90a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/ResetPowerShellWorkingDirectoryOnSolutionClosedTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/ResetPowerShellWorkingDirectoryOnSolutionClosedTests.cs @@ -37,7 +37,7 @@ namespace PackageManagement.Tests.Scripting { CreateReset(); fakeConsoleHost.IsRunning = true; - fakeProjectService.FireSolutionClosedEvent(); + fakeProjectService.FireSolutionClosedEvent(fakeProjectService.OpenSolution); bool workingDirectoryUpdated = IsWorkingDirectoryUpdated(); @@ -49,7 +49,7 @@ namespace PackageManagement.Tests.Scripting { CreateReset(); fakeConsoleHost.IsRunning = false; - fakeProjectService.FireSolutionClosedEvent(); + fakeProjectService.FireSolutionClosedEvent(fakeProjectService.OpenSolution); bool workingDirectoryUpdated = IsWorkingDirectoryUpdated(); diff --git a/src/Main/Base/Project/Editor/CodeCompletion/CodeCompletionDataUsageCache.cs b/src/Main/Base/Project/Editor/CodeCompletion/CodeCompletionDataUsageCache.cs index 5ae6158a30..74b1749dc9 100644 --- a/src/Main/Base/Project/Editor/CodeCompletion/CodeCompletionDataUsageCache.cs +++ b/src/Main/Base/Project/Editor/CodeCompletion/CodeCompletionDataUsageCache.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion static void LoadCache() { dict = new Dictionary(); - ProjectService.SolutionClosed += delegate(object sender, EventArgs e) { SaveCache(); }; + ProjectService.SolutionClosed += delegate { SaveCache(); }; string cacheFileName = CodeCompletionDataUsageCache.CacheFilename; if (string.IsNullOrEmpty(cacheFileName) || !File.Exists(cacheFileName)) return; diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin index 5f0b269a38..bf9782f5f8 100755 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin @@ -76,6 +76,8 @@ class="ICSharpCode.SharpDevelop.Project.BuildService"/> + diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 56e2a4b579..e6bf43c5f8 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -161,6 +161,7 @@ + @@ -707,7 +708,6 @@ - diff --git a/src/Main/Base/Project/Project/IProjectService.cs b/src/Main/Base/Project/Project/IProjectService.cs index 118f0f342f..0df11ba69b 100644 --- a/src/Main/Base/Project/Project/IProjectService.cs +++ b/src/Main/Base/Project/Project/IProjectService.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; @@ -20,9 +21,19 @@ namespace ICSharpCode.SharpDevelop.Project /// /// This property is thread-safe. /// - ISolution OpenSolution { get; } + ISolution CurrentSolution { get; } - event PropertyChangedEventHandler OpenSolutionChanged; + event PropertyChangedEventHandler CurrentSolutionChanged; + + /// + /// This event is raised before a solution is closed. + /// + event EventHandler SolutionClosing; + + /// + /// This event is raised after a solution is closed. + /// + event EventHandler SolutionClosed; /// /// Gets/Sets the project that is currently considered 'active' within the IDE. @@ -34,6 +45,13 @@ namespace ICSharpCode.SharpDevelop.Project event PropertyChangedEventHandler CurrentProjectChanged; + /// + /// A collection that contains all projects in the currently open solution. + /// + /// The collection instance is reused when the solution is closed and another is opened. + /// + IModelCollection AllProjects { get; } + /// /// Finds the project that contains the specified file. /// Returns null if none of the open projects contains the file. @@ -56,12 +74,16 @@ namespace ICSharpCode.SharpDevelop.Project void OpenSolutionOrProject(FileName fileName); /// - /// Closes the currently open solution. + /// Closes the solution: cancels build, clears solution data, fires the SolutionClosing and SolutionClosed events. /// + /// Whether to allow the user to cancel closing the solution. + /// + /// True if the solution was closed successfully; false if the operation was aborted. + /// /// /// This method may only be called on the main thread. /// - void CloseSolution(); + bool CloseSolution(bool allowCancel = true); /// /// Returns if the given file is considered a project or solution file. @@ -85,7 +107,7 @@ namespace ICSharpCode.SharpDevelop.Project ISolution LoadSolutionFile(FileName fileName, IProgressMonitor progress); /// - /// Creates a new, empty solution and loads it without opening it in the IDE. + /// Creates a new, empty solution without opening it in the IDE. /// The file is not saved to disk until is called. /// /// diff --git a/src/Main/Base/Project/Project/SolutionEventArgs.cs b/src/Main/Base/Project/Project/SolutionEventArgs.cs new file mode 100644 index 0000000000..a1dd58c216 --- /dev/null +++ b/src/Main/Base/Project/Project/SolutionEventArgs.cs @@ -0,0 +1,38 @@ +// 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; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class SolutionEventArgs : EventArgs + { + readonly ISolution solution; + + public ISolution Solution { + get { return solution; } + } + + public SolutionEventArgs(ISolution solution) + { + this.solution = solution; + } + } + + public class SolutionClosingEventArgs : SolutionEventArgs + { + readonly bool allowCancel; + + public bool AllowCancel { + get { return allowCancel; } + } + + public bool Cancel { get; set; } + + public SolutionClosingEventArgs(ISolution solution, bool allowCancel) + : base(solution) + { + this.allowCancel = allowCancel; + } + } +} diff --git a/src/Main/Base/Project/Services/SD.cs b/src/Main/Base/Project/Services/SD.cs index 32457a3835..38924300b2 100644 --- a/src/Main/Base/Project/Services/SD.cs +++ b/src/Main/Base/Project/Services/SD.cs @@ -5,6 +5,7 @@ using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Linq.Expressions; +using System.Threading.Tasks; using ICSharpCode.Core; using ICSharpCode.Core.Implementation; using ICSharpCode.SharpDevelop.Dom; @@ -53,6 +54,9 @@ namespace ICSharpCode.SharpDevelop /// public static void TearDownForUnitTests() { + var disposableServiceContainer = ServiceSingleton.ServiceProvider as IDisposable; + if (disposableServiceContainer != null) + disposableServiceContainer.Dispose(); ServiceSingleton.ServiceProvider = ServiceSingleton.FallbackServiceProvider; } @@ -72,6 +76,20 @@ namespace ICSharpCode.SharpDevelop return ServiceSingleton.ServiceProvider.GetRequiredService(); } + /// + /// Returns a task that gets completed when the service is initialized. + /// + /// This method does not try to initialize the service -- if no other code forces the service + /// to be initialized, the task will never complete. + /// + /// + /// This method can be used to solve cyclic dependencies in service initialization. + /// + public static Task GetFutureService() where T : class + { + throw new NotImplementedException(); + } + /// /// Equivalent to SD.Workbench.ActiveViewContent.GetService<T>(), /// but does not throw a NullReferenceException when ActiveViewContent is null. diff --git a/src/Main/Base/Project/Src/Commands/BuildCommands.cs b/src/Main/Base/Project/Src/Commands/BuildCommands.cs index 62133627b1..ed28eb5732 100644 --- a/src/Main/Base/Project/Src/Commands/BuildCommands.cs +++ b/src/Main/Base/Project/Src/Commands/BuildCommands.cs @@ -277,8 +277,8 @@ namespace ICSharpCode.SharpDevelop.Project.Commands { public override void Run() { - if (SD.ProjectService.OpenSolution != null) - SD.UIService.ShowSolutionConfigurationEditorDialog(SD.ProjectService.OpenSolution); + if (SD.ProjectService.CurrentSolution != null) + SD.UIService.ShowSolutionConfigurationEditorDialog(SD.ProjectService.CurrentSolution); } } } diff --git a/src/Main/Base/Project/Src/Commands/FileCommands.cs b/src/Main/Base/Project/Src/Commands/FileCommands.cs index 1eae043a9f..1f2c0ce2e1 100644 --- a/src/Main/Base/Project/Src/Commands/FileCommands.cs +++ b/src/Main/Base/Project/Src/Commands/FileCommands.cs @@ -181,7 +181,7 @@ namespace ICSharpCode.SharpDevelop.Commands if (!FileService.CheckFileName(fileName)) { return; } - if (FileUtility.ObservedSave(new NamedFileOperationDelegate(file.SaveToDisk), fileName) == FileOperationResult.OK) { + if (FileUtility.ObservedSave(new NamedFileOperationDelegate(file.SaveToDisk), FileName.Create(fileName)) == FileOperationResult.OK) { SD.FileService.RecentOpen.AddRecentFile(fileName); MessageService.ShowMessage(fileName, "${res:ICSharpCode.SharpDevelop.Commands.SaveFile.FileSaved}"); } diff --git a/src/Main/Base/Project/Src/Commands/FileMenuCommands.cs b/src/Main/Base/Project/Src/Commands/FileMenuCommands.cs index 7381609601..470e993519 100644 --- a/src/Main/Base/Project/Src/Commands/FileMenuCommands.cs +++ b/src/Main/Base/Project/Src/Commands/FileMenuCommands.cs @@ -39,12 +39,7 @@ namespace ICSharpCode.SharpDevelop.Project.Commands { public override void Run() { - if (!ProjectService.IsClosingCanceled()) { - ProjectService.SaveSolutionPreferences(); - if (SD.Workbench.CloseAllSolutionViews()) { - ProjectService.CloseSolution(); - } - } + SD.ProjectService.CloseSolution(); } } } diff --git a/src/Main/Base/Project/Src/Gui/Components/SideBar/TextEditorSideBar.cs b/src/Main/Base/Project/Src/Gui/Components/SideBar/TextEditorSideBar.cs index 5807df8f44..1a8d9dfab1 100644 --- a/src/Main/Base/Project/Src/Gui/Components/SideBar/TextEditorSideBar.cs +++ b/src/Main/Base/Project/Src/Gui/Components/SideBar/TextEditorSideBar.cs @@ -97,8 +97,8 @@ namespace ICSharpCode.SharpDevelop.Gui doc.LoadXml(""); doc.DocumentElement.AppendChild(WriteConfig(doc)); - FileUtility.ObservedSave(new NamedFileOperationDelegate(doc.Save), - Path.Combine(PropertyService.ConfigDirectory, "SideBarConfig.xml"), + FileUtility.ObservedSave(fileName => doc.Save(fileName), + FileName.Create(Path.Combine(PropertyService.ConfigDirectory, "SideBarConfig.xml")), FileErrorPolicy.ProvideAlternative); } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs index f127d1e52c..9ee73d8307 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/NewFileDialog.cs @@ -405,7 +405,7 @@ namespace ICSharpCode.SharpDevelop.Gui } if (Path.IsPathRooted(unresolvedFileName)) { Directory.CreateDirectory(Path.GetDirectoryName(unresolvedFileName)); - viewContent.PrimaryFile.SaveToDisk(unresolvedFileName); + viewContent.PrimaryFile.SaveToDisk(FileName.Create(unresolvedFileName)); } } createdFiles.Add(new KeyValuePair(unresolvedFileName, newfile)); @@ -513,7 +513,7 @@ namespace ICSharpCode.SharpDevelop.Gui } else { SaveFile(newFile, scriptRunner.CompileScript(item.Template, newFile), null); } - }, StringParser.Parse(newFile.Name) + }, FileName.Create(StringParser.Parse(newFile.Name)) ); if (result != FileOperationResult.OK) return; 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 bfe37123f7..819a514108 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs @@ -85,7 +85,6 @@ namespace ICSharpCode.SharpDevelop.Project FileService.FileRemoved += FileServiceFileRemoved; ProjectService.ProjectItemAdded += ProjectServiceProjectItemAdded; - ProjectService.SolutionFolderRemoved += ProjectServiceSolutionFolderRemoved; treeView.DrawNode += TreeViewDrawNode; treeView.DragDrop += TreeViewDragDrop; } @@ -131,10 +130,7 @@ namespace ICSharpCode.SharpDevelop.Project treeNode.AcceptVisitor(visitor, null); } } - void ProjectServiceSolutionFolderRemoved(object sender, SolutionFolderEventArgs e) - { - CallVisitor(new SolutionItemRemoveVisitor(e.SolutionFolder)); - } + void ProjectServiceProjectItemAdded(object sender, ProjectItemEventArgs e) { if (e.ProjectItem is ReferenceProjectItem) { diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs index c95fad6758..18a11a5192 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/ProjectNode.cs @@ -140,8 +140,10 @@ namespace ICSharpCode.SharpDevelop.Project public override void Delete() { - ((ISolutionFolderNode)Parent).Folder.Items.Remove(project); + var parentFolder = ((ISolutionFolderNode)Parent).Folder; + parentFolder.Items.Remove(project); base.Remove(); + parentFolder.ParentSolution.Save(); } public override bool EnableCopy { diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionFolderNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionFolderNode.cs index 6fd3189d17..fa167ad74e 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionFolderNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionFolderNode.cs @@ -102,8 +102,10 @@ namespace ICSharpCode.SharpDevelop.Project public override void Delete() { - folder.ParentFolder.Items.Remove(folder); - solution.Save(); + var parentFolder = ((ISolutionFolderNode)Parent).Folder; + parentFolder.Items.Remove(folder); + base.Remove(); + parentFolder.ParentSolution.Save(); } public override bool EnableCopy { diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionItemNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionItemNode.cs index 802b6ab298..685f63974a 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionItemNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/SolutionItemNode.cs @@ -71,8 +71,10 @@ namespace ICSharpCode.SharpDevelop.Project public override void Delete() { - ((ISolutionFolderNode)Parent).Folder.Items.Remove(item); + var parentFolder = ((ISolutionFolderNode)Parent).Folder; + parentFolder.Items.Remove(item); base.Remove(); + parentFolder.ParentSolution.Save(); } public override bool EnablePaste { diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/Util/SolutionFolderRemoveVisitor.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/Util/SolutionFolderRemoveVisitor.cs deleted file mode 100644 index 3a38953df1..0000000000 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/Util/SolutionFolderRemoveVisitor.cs +++ /dev/null @@ -1,46 +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 ICSharpCode.SharpDevelop.Gui; - -namespace ICSharpCode.SharpDevelop.Project -{ - public class SolutionItemRemoveVisitor : ProjectBrowserTreeNodeVisitor - { - ISolutionItem folder; - - public SolutionItemRemoveVisitor(ISolutionItem folder) - { - this.folder = folder; - } - - public override object Visit(SolutionFolderNode solutionFolderNode, object data) - { - if (folder == solutionFolderNode.Folder) { - ExtTreeNode parent = solutionFolderNode.Parent as ExtTreeNode; - solutionFolderNode.Remove(); - if (parent != null) { - parent.Refresh(); - } - } else { - solutionFolderNode.AcceptChildren(this, data); - } - return data; - } - - public override object Visit(ProjectNode projectNode, object data) - { - if (folder == projectNode.Project) { - ExtTreeNode parent = projectNode.Parent as ExtTreeNode; - projectNode.Remove(); - if (parent != null) { - parent.Refresh(); - } - } - return data; - } - - - } -} diff --git a/src/Main/Base/Project/Src/Internal/ExternalTool/ToolLoader.cs b/src/Main/Base/Project/Src/Internal/ExternalTool/ToolLoader.cs index 3071cbfce3..1cb26bad92 100644 --- a/src/Main/Base/Project/Src/Internal/ExternalTool/ToolLoader.cs +++ b/src/Main/Base/Project/Src/Internal/ExternalTool/ToolLoader.cs @@ -69,7 +69,7 @@ namespace ICSharpCode.SharpDevelop.Internal.ExternalTool doc.DocumentElement.AppendChild(et.ToXmlElement(doc)); } - FileUtility.ObservedSave(new NamedFileOperationDelegate(doc.Save), fileName, FileErrorPolicy.ProvideAlternative); + FileUtility.ObservedSave(fn => doc.Save(fn), FileName.Create(fileName), FileErrorPolicy.ProvideAlternative); } /// diff --git a/src/Main/Base/Project/Src/Project/AbstractProject.cs b/src/Main/Base/Project/Src/Project/AbstractProject.cs index 10191c64a6..ac1340ef7f 100644 --- a/src/Main/Base/Project/Src/Project/AbstractProject.cs +++ b/src/Main/Base/Project/Src/Project/AbstractProject.cs @@ -71,17 +71,19 @@ namespace ICSharpCode.SharpDevelop.Project get { return isDisposed; } } - public event EventHandler Disposed; + //public event EventHandler Disposed = delegate {}; public virtual void Dispose() { SD.MainThread.VerifyAccess(); - if (watcher != null) - watcher.Dispose(); - isDisposed = true; - if (Disposed != null) { - Disposed(this, EventArgs.Empty); + lock (SyncRoot) { + if (isDisposed) + return; + isDisposed = true; + if (watcher != null) + watcher.Dispose(); } + //Disposed(this, EventArgs.Empty); } #endregion diff --git a/src/Main/Base/Project/Src/Project/CustomTool.cs b/src/Main/Base/Project/Src/Project/CustomTool.cs index baafe20792..691dbafde6 100644 --- a/src/Main/Base/Project/Src/Project/CustomTool.cs +++ b/src/Main/Base/Project/Src/Project/CustomTool.cs @@ -196,10 +196,10 @@ namespace ICSharpCode.SharpDevelop.Project codeOutput = writer.ToString(); } - FileUtility.ObservedSave(delegate(string fileName) { + FileUtility.ObservedSave(delegate(FileName fileName) { File.WriteAllText(fileName, codeOutput, Encoding.UTF8); }, - outputFileName, FileErrorPolicy.Inform); + FileName.Create(outputFileName), FileErrorPolicy.Inform); EnsureOutputFileIsInProject(baseItem, outputFileName); SD.ParserService.ParseAsync(FileName.Create(outputFileName), new StringTextSource(codeOutput)).FireAndForget(); } diff --git a/src/Main/Base/Project/Src/Project/IProject.cs b/src/Main/Base/Project/Src/Project/IProject.cs index aa97e5bfc3..cc08d3f4f5 100644 --- a/src/Main/Base/Project/Src/Project/IProject.cs +++ b/src/Main/Base/Project/Src/Project/IProject.cs @@ -309,6 +309,11 @@ namespace ICSharpCode.SharpDevelop.Project /// Never returns null, but may return a permanently empty collection if this project does not support such models. /// ITypeDefinitionModelCollection TypeDefinitionModels { get; } + + /// + /// Gets whether this project was unloaded. + /// + bool IsDisposed { get; } } /// diff --git a/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs b/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs index 361c15160b..094129002d 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.SharpDevelop.Debugging ClearDebugMessages(); }; - ProjectService.BeforeSolutionClosing += OnBeforeSolutionClosing; + SD.ProjectService.SolutionClosing += OnSolutionClosing; } static void GetDescriptors() @@ -151,12 +151,16 @@ namespace ICSharpCode.SharpDevelop.Debugging debugCategory.AppendText(msg); } - static void OnBeforeSolutionClosing(object sender, SolutionCancelEventArgs e) + static void OnSolutionClosing(object sender, SolutionClosingEventArgs e) { if (currentDebugger == null) return; if (currentDebugger.IsDebugging) { + if (!e.AllowCancel) { + currentDebugger.Stop(); + return; + } string caption = StringParser.Parse("${res:XML.MainMenu.DebugMenu.Stop}"); string message = StringParser.Parse("${res:MainWindow.Windows.Debug.StopDebugging.Message}"); string[] buttonLabels = new string[] { StringParser.Parse("${res:Global.Yes}"), StringParser.Parse("${res:Global.No}") }; diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs index 736ad653e2..7878762c04 100644 --- a/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs +++ b/src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs @@ -22,7 +22,7 @@ namespace ICSharpCode.SharpDevelop.Project public static ISolution OpenSolution { [System.Diagnostics.DebuggerStepThrough] get { - return SD.ProjectService.OpenSolution; + return SD.ProjectService.CurrentSolution; } } @@ -46,7 +46,7 @@ namespace ICSharpCode.SharpDevelop.Project /// public static IProject GetProject(FileName projectFilename) { - ISolution sln = SD.ProjectService.OpenSolution; + ISolution sln = SD.ProjectService.CurrentSolution; if (sln == null) return null; foreach (IProject project in sln.Projects) { @@ -83,69 +83,7 @@ namespace ICSharpCode.SharpDevelop.Project public static void LoadSolutionOrProject(string fileName) { - SD.ProjectService.CloseSolution(); SD.ProjectService.OpenSolutionOrProject(FileName.Create(fileName)); - /*IProjectLoader loader = GetProjectLoader(fileName); - if (loader != null) { - loader.Load(fileName); - } else { - MessageService.ShowError(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Commands.OpenCombine.InvalidProjectOrCombine}", new StringTagPair("FileName", fileName))); - }*/ - } - - static void FileServiceFileRenamed(object sender, FileRenameEventArgs e) - { - if (OpenSolution == null) { - return; - } - string oldName = e.SourceFile; - string newName = e.TargetFile; - foreach (ISolutionFileItem fileItem in OpenSolution.AllItems.OfType().ToArray()) { - if (FileUtility.IsBaseDirectory(oldName, fileItem.FileName)) { - string newFullName = FileUtility.RenameBaseDirectory(fileItem.FileName, oldName, newName); - fileItem.FileName = FileName.Create(newFullName); - } - } - - foreach (IProject project in OpenSolution.Projects) { - if (FileUtility.IsBaseDirectory(project.Directory, oldName)) { - foreach (ProjectItem item in project.Items) { - if (FileUtility.IsBaseDirectory(oldName, item.FileName)) { - OnProjectItemRemoved(new ProjectItemEventArgs(project, item)); - item.FileName = FileUtility.RenameBaseDirectory(item.FileName, oldName, newName); - OnProjectItemAdded(new ProjectItemEventArgs(project, item)); - } - } - } - } - } - - static void FileServiceFileRemoved(object sender, FileEventArgs e) - { - if (OpenSolution == null) { - return; - } - string fileName = e.FileName; - - foreach (ISolutionFileItem fileItem in OpenSolution.AllItems.OfType().ToArray()) { - if (FileUtility.IsBaseDirectory(fileName, fileItem.FileName)) { - fileItem.ParentFolder.Items.Remove(fileItem); - } - } - - foreach (IProject project in OpenSolution.Projects) { - if (FileUtility.IsBaseDirectory(project.Directory, fileName)) { - IProjectItemListProvider provider = project as IProjectItemListProvider; - if (provider != null) { - foreach (ProjectItem item in provider.Items.ToArray()) { - if (FileUtility.IsBaseDirectory(fileName, item.FileName)) { - provider.RemoveProjectItem(item); - OnProjectItemRemoved(new ProjectItemEventArgs(project, item)); - } - } - } - } - } } static void ActiveViewContentChanged(object sender, EventArgs e) @@ -377,7 +315,7 @@ namespace ICSharpCode.SharpDevelop.Project public static void SaveSolution() { - var openSolution = SD.ProjectService.OpenSolution; + var openSolution = SD.ProjectService.CurrentSolution; if (openSolution != null) { openSolution.Save(); foreach (IProject project in openSolution.Projects) { @@ -469,68 +407,6 @@ namespace ICSharpCode.SharpDevelop.Project }*/ } - /// - /// Executes the OnBeforeSolutionClosing event. - /// - /// This method must be used after CloseSolution is called. - /// true, if closing solution was canceled; false, otherwise. - internal static bool IsClosingCanceled() - { - // run onbefore closing - var beforeClosingArgs = new SolutionCancelEventArgs(OpenSolution); - OnBeforeSolutionClosing(beforeClosingArgs); - - return beforeClosingArgs.Cancel; - } - - /// - /// Closes the solution: cancels build, clears solution data, fires the SolutionClosing and SolutionClosed events. - /// - /// Before invoking this method, one should check if the closing was canceled (), - /// save solution and project data (e.g. files, bookmarks), then invoke CloseSolution(). - /// - /// - internal static void CloseSolution() - { - throw new NotImplementedException(); - /*// If a build is running, cancel it. - // If we would let a build run but unload the MSBuild projects, the next project.StartBuild call - // could cause an exception. - SD.BuildService.CancelBuild(); - - if (openSolution != null) { - CurrentProject = null; - OnSolutionClosing(new SolutionEventArgs(openSolution)); - - openSolution.Dispose(); - openSolution = null; - - OnSolutionClosed(EventArgs.Empty); - CommandManager.InvalidateRequerySuggested(); - }*/ - } - - static void OnSolutionClosed(EventArgs e) - { - if (SolutionClosed != null) { - SolutionClosed(null, e); - } - } - - static void OnSolutionClosing(SolutionEventArgs e) - { - if (SolutionClosing != null) { - SolutionClosing(null, e); - } - } - - static void OnBeforeSolutionClosing(SolutionCancelEventArgs e) - { - if (BeforeSolutionClosing != null) { - BeforeSolutionClosing(null, e); - } - } - static void OnSolutionLoading(string fileName) { if (SolutionLoading != null) { @@ -552,51 +428,13 @@ namespace ICSharpCode.SharpDevelop.Project } } - /* - public static void RemoveSolutionFolder(string guid) - { - if (OpenSolution == null) { - return; - } - foreach (ISolutionItem folder in OpenSolution.SolutionFolders) { - if (folder.IdGuid == guid) { - folder.Parent.RemoveFolder(folder); - OnSolutionFolderRemoved(new SolutionFolderEventArgs(folder)); - HandleRemovedSolutionFolder(folder); - break; - } - } - } - - static void HandleRemovedSolutionFolder(ISolutionItem folder) - { - IProject project = folder as IProject; - if (project != null) { - OpenSolution.RemoveProjectConfigurations(project.IdGuid); - OnProjectRemoved(new ProjectEventArgs(project)); - project.Dispose(); - } - if (folder is ISolutionFolder) { - // recurse into child folders that were also removed - ((ISolutionFolder)folder).Folders.ForEach(HandleRemovedSolutionFolder); - } - } - - static void OnSolutionFolderRemoved(SolutionFolderEventArgs e) - { - if (SolutionFolderRemoved != null) { - SolutionFolderRemoved(null, e); - } - } - */ - - static void OnProjectItemAdded(ProjectItemEventArgs e) + internal static void OnProjectItemAdded(ProjectItemEventArgs e) { if (ProjectItemAdded != null) { ProjectItemAdded(null, e); } } - static void OnProjectItemRemoved(ProjectItemEventArgs e) + internal static void OnProjectItemRemoved(ProjectItemEventArgs e) { if (ProjectItemRemoved != null) { ProjectItemRemoved(null, e); @@ -640,12 +478,6 @@ namespace ICSharpCode.SharpDevelop.Project /// public static event EventHandler ProjectRemoved; - /// - /// Is raised when a solution folder is removed from the solution. - /// This might remove multiple projects from the solution. - /// - public static event SolutionFolderEventHandler SolutionFolderRemoved; - [Obsolete("Use SD.BuildService.BuildStarted instead")] public static event EventHandler BuildStarted { add { SD.BuildService.BuildStarted += value; } @@ -662,17 +494,15 @@ namespace ICSharpCode.SharpDevelop.Project public static event EventHandler SolutionLoading; public static event EventHandler SolutionLoaded; - public static event EventHandler SolutionClosing; - public static event EventHandler SolutionClosed; + public static event EventHandler SolutionClosed { + add { SD.ProjectService.SolutionClosed += value; } + remove { SD.ProjectService.SolutionClosed -= value; } + } - /// - /// Raised before SolutionClosing. - /// - /// When one modifies the e.Cancel property, should have in mind that other consumers might want to cancel the closing.
- /// Setting e.Cancel = false might override other consumers (if they exist) e.Cancel = true, and might break other functionalities. - ///
- ///
- public static event EventHandler BeforeSolutionClosing; + public static event EventHandler SolutionClosing { + add { SD.ProjectService.SolutionClosing += value; } + remove { SD.ProjectService.SolutionClosing -= value; } + } /// /// Raised before the solution preferences are being saved. Allows you to save diff --git a/src/Main/Base/Project/Src/Services/ProjectService/SolutionEventHandler.cs b/src/Main/Base/Project/Src/Services/ProjectService/SolutionEventHandler.cs index 0a01080ed6..f81416e411 100644 --- a/src/Main/Base/Project/Src/Services/ProjectService/SolutionEventHandler.cs +++ b/src/Main/Base/Project/Src/Services/ProjectService/SolutionEventHandler.cs @@ -6,35 +6,5 @@ using System.ComponentModel; namespace ICSharpCode.SharpDevelop.Project { - public class SolutionEventArgs : EventArgs - { - ISolution solution; - - public ISolution Solution { - get { - return solution; - } - } - - public SolutionEventArgs(ISolution solution) - { - this.solution = solution; - } - } - - public class SolutionCancelEventArgs : CancelEventArgs - { - ISolution solution; - - public ISolution Solution { - get { - return solution; - } - } - - public SolutionCancelEventArgs(ISolution solution) - { - this.solution = solution; - } - } + } diff --git a/src/Main/Base/Project/Util/PropertyChangedEventArgs.cs b/src/Main/Base/Project/Util/PropertyChangedEventArgs.cs index ca63e72be9..979b0f9c98 100644 --- a/src/Main/Base/Project/Util/PropertyChangedEventArgs.cs +++ b/src/Main/Base/Project/Util/PropertyChangedEventArgs.cs @@ -3,27 +3,25 @@ using System; using System.ComponentModel; +using System.Runtime.CompilerServices; namespace ICSharpCode.SharpDevelop { /// - /// PropertyChangedEventHandler that includes the old and new value. + /// PropertyChangedEventHandler with the old and new value. /// public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e); /// - /// PropertyChangedEventArgs that includes the old and new value. + /// PropertyChangedEventArgs that contains the old and new value. /// - public class PropertyChangedEventArgs : PropertyChangedEventArgs + public class PropertyChangedEventArgs : EventArgs { readonly T oldValue; readonly T newValue; - public PropertyChangedEventArgs(string propertyName, T oldValue, T newValue) - : base(propertyName) + public PropertyChangedEventArgs(T oldValue, T newValue) { - if (propertyName == null) - throw new ArgumentNullException("propertyName"); this.oldValue = oldValue; this.newValue = newValue; } diff --git a/src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs b/src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs index 62dea5478f..bb1cbc157d 100644 --- a/src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs +++ b/src/Main/Base/Project/Util/SharpDevelopServiceContainer.cs @@ -38,7 +38,9 @@ namespace ICSharpCode.SharpDevelop SD.Log.Debug("Service startup: " + serviceType); instance = callback(this, serviceType); if (instance != null) { - servicesToDispose.Add(instance as IDisposable); + IDisposable disposableService = instance as IDisposable; + if (disposableService != null) + servicesToDispose.Add(disposableService); services[serviceType] = instance; } else { services.Remove(serviceType); @@ -63,22 +65,17 @@ namespace ICSharpCode.SharpDevelop } // dispose services in reverse order of their creation foreach (IDisposable disposable in disposables.Reverse()) { - if (disposable != null) { - loggingService.Debug("Service shutdown: " + disposable.GetType()); - disposable.Dispose(); - } + loggingService.Debug("Service shutdown: " + disposable.GetType()); + disposable.Dispose(); } - var eh = Disposed; - if (eh != null) - eh(this, EventArgs.Empty); } - public event EventHandler Disposed; - public void AddService(Type serviceType, object serviceInstance) { lock (services) { - servicesToDispose.Add(serviceInstance as IDisposable); + IDisposable disposableService = serviceInstance as IDisposable; + if (disposableService != null) + servicesToDispose.Add(disposableService); services.Add(serviceType, serviceInstance); } } diff --git a/src/Main/Base/Project/Workbench/File/OpenedFile.cs b/src/Main/Base/Project/Workbench/File/OpenedFile.cs index ae4ddbc0da..65b4519466 100644 --- a/src/Main/Base/Project/Workbench/File/OpenedFile.cs +++ b/src/Main/Base/Project/Workbench/File/OpenedFile.cs @@ -102,9 +102,9 @@ namespace ICSharpCode.SharpDevelop.Workbench /// /// Use this method to save the file to disk using a new name. /// - public void SaveToDisk(string newFileName) + public void SaveToDisk(FileName newFileName) { - this.FileName = new FileName(newFileName); + this.FileName = newFileName; this.IsUntitled = false; SaveToDisk(); } diff --git a/src/Main/Base/Project/Workbench/IShutdownService.cs b/src/Main/Base/Project/Workbench/IShutdownService.cs index d0f8b8fa6f..53440a0971 100644 --- a/src/Main/Base/Project/Workbench/IShutdownService.cs +++ b/src/Main/Base/Project/Workbench/IShutdownService.cs @@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Workbench /// Attemps to close the IDE. /// /// - /// This method will + /// This method will: /// - Check if was called and abort the shutdown if it was. /// - Prompt the user to save the open files. The user has the option to cancel the shutdown at that point. /// - Closes the solution. diff --git a/src/Main/Base/Project/Workbench/IWorkbench.cs b/src/Main/Base/Project/Workbench/IWorkbench.cs index ba0ae660f7..c0d82223d5 100644 --- a/src/Main/Base/Project/Workbench/IWorkbench.cs +++ b/src/Main/Base/Project/Workbench/IWorkbench.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Workbench /// /// True if all views were closed properly, false if closing was aborted. /// - bool CloseAllSolutionViews(); + bool CloseAllSolutionViews(bool force); /// /// Gets/Sets the name of the current layout configuration. diff --git a/src/Main/Base/Project/Workbench/WorkbenchSingleton.cs b/src/Main/Base/Project/Workbench/WorkbenchSingleton.cs index 423952b37a..71f9351bdd 100644 --- a/src/Main/Base/Project/Workbench/WorkbenchSingleton.cs +++ b/src/Main/Base/Project/Workbench/WorkbenchSingleton.cs @@ -69,12 +69,10 @@ namespace ICSharpCode.SharpDevelop.Gui /// internal static void OnWorkbenchUnloaded() { - if (!Project.ProjectService.IsClosingCanceled()) { - Project.ProjectService.CloseSolution(); - NavigationService.Unload(); - - WorkbenchUnloaded(null, EventArgs.Empty); - } + SD.ProjectService.CloseSolution(allowCancel: false); + NavigationService.Unload(); + + WorkbenchUnloaded(null, EventArgs.Empty); } #region Safe Thread Caller diff --git a/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs b/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs index 7e710da8ac..69e73ab16c 100644 --- a/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs +++ b/src/Main/Core/Project/Src/Services/FileUtility/FileUtility.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.Core public delegate void FileOperationDelegate(); - public delegate void NamedFileOperationDelegate(string fileName); + public delegate void NamedFileOperationDelegate(FileName fileName); /// /// A utility class related to file utilities. @@ -573,7 +573,7 @@ namespace ICSharpCode.Core } // Observe SAVE functions - public static FileOperationResult ObservedSave(FileOperationDelegate saveFile, string fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedSave(FileOperationDelegate saveFile, FileName fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) { System.Diagnostics.Debug.Assert(IsValidPath(fileName)); try { @@ -587,7 +587,7 @@ namespace ICSharpCode.Core } } - static FileOperationResult ObservedSaveHandleException(Exception e, FileOperationDelegate saveFile, string fileName, string message, FileErrorPolicy policy) + static FileOperationResult ObservedSaveHandleException(Exception e, FileOperationDelegate saveFile, FileName fileName, string message, FileErrorPolicy policy) { var messageService = ServiceSingleton.GetRequiredService(); switch (policy) { @@ -606,7 +606,7 @@ namespace ICSharpCode.Core return FileOperationResult.Failed; } - public static FileOperationResult ObservedSave(FileOperationDelegate saveFile, string fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedSave(FileOperationDelegate saveFile, FileName fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) { return ObservedSave(saveFile, fileName, @@ -614,14 +614,11 @@ namespace ICSharpCode.Core policy); } - public static FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, string fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, FileName fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) { System.Diagnostics.Debug.Assert(IsValidPath(fileName)); try { - string directory = Path.GetDirectoryName(fileName); - if (!Directory.Exists(directory)) { - Directory.CreateDirectory(directory); - } + Directory.CreateDirectory(fileName.GetParentDirectory()); saveFileAs(fileName); RaiseFileSaved(new FileNameEventArgs(fileName)); return FileOperationResult.OK; @@ -632,7 +629,7 @@ namespace ICSharpCode.Core } } - static FileOperationResult ObservedSaveHandleError(Exception e, NamedFileOperationDelegate saveFileAs, string fileName, string message, FileErrorPolicy policy) + static FileOperationResult ObservedSaveHandleError(Exception e, NamedFileOperationDelegate saveFileAs, FileName fileName, string message, FileErrorPolicy policy) { var messageService = ServiceSingleton.GetRequiredService(); switch (policy) { @@ -653,7 +650,7 @@ namespace ICSharpCode.Core return FileOperationResult.Failed; } - public static FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, string fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedSave(NamedFileOperationDelegate saveFileAs, FileName fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) { return ObservedSave(saveFileAs, fileName, @@ -662,7 +659,7 @@ namespace ICSharpCode.Core } // Observe LOAD functions - public static FileOperationResult ObservedLoad(FileOperationDelegate loadFile, string fileName, string message, FileErrorPolicy policy) + public static FileOperationResult ObservedLoad(FileOperationDelegate loadFile, FileName fileName, string message, FileErrorPolicy policy) { try { loadFile(); @@ -675,7 +672,7 @@ namespace ICSharpCode.Core } } - static FileOperationResult ObservedLoadHandleException(Exception e, FileOperationDelegate loadFile, string fileName, string message, FileErrorPolicy policy) + static FileOperationResult ObservedLoadHandleException(Exception e, FileOperationDelegate loadFile, FileName fileName, string message, FileErrorPolicy policy) { var messageService = ServiceSingleton.GetRequiredService(); switch (policy) { @@ -693,7 +690,7 @@ namespace ICSharpCode.Core return FileOperationResult.Failed; } - public static FileOperationResult ObservedLoad(FileOperationDelegate loadFile, string fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedLoad(FileOperationDelegate loadFile, FileName fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) { return ObservedLoad(loadFile, fileName, @@ -701,12 +698,12 @@ namespace ICSharpCode.Core policy); } - public static FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, string fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, FileName fileName, string message, FileErrorPolicy policy = FileErrorPolicy.Inform) { return ObservedLoad(new FileOperationDelegate(delegate { saveFileAs(fileName); }), fileName, message, policy); } - public static FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, string fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) + public static FileOperationResult ObservedLoad(NamedFileOperationDelegate saveFileAs, FileName fileName, FileErrorPolicy policy = FileErrorPolicy.Inform) { return ObservedLoad(saveFileAs, fileName, diff --git a/src/Main/Core/Project/Src/Services/MessageService/IMessageService.cs b/src/Main/Core/Project/Src/Services/MessageService/IMessageService.cs index f6da5beecb..1325e1b8d8 100644 --- a/src/Main/Core/Project/Src/Services/MessageService/IMessageService.cs +++ b/src/Main/Core/Project/Src/Services/MessageService/IMessageService.cs @@ -96,13 +96,13 @@ namespace ICSharpCode.Core /// /// Show a message informing the user about a save error. /// - void InformSaveError(string fileName, string message, string dialogName, Exception exceptionGot); + void InformSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot); /// /// Show a message informing the user about a save error, /// and allow him to retry/save under alternative name. /// - ChooseSaveErrorResult ChooseSaveError(string fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled); + ChooseSaveErrorResult ChooseSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled); } sealed class FallbackMessageService : TextWriterMessageService @@ -115,7 +115,7 @@ namespace ICSharpCode.Core public bool IsRetry { get; private set; } public bool IsIgnore { get; private set; } public bool IsSaveAlternative { get { return AlternativeFileName != null; } } - public string AlternativeFileName { get; private set; } + public FileName AlternativeFileName { get; private set; } private ChooseSaveErrorResult() {} @@ -124,7 +124,7 @@ namespace ICSharpCode.Core [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification="ChooseSaveErrorResult is immutable")] public readonly static ChooseSaveErrorResult Ignore = new ChooseSaveErrorResult { IsIgnore = true }; - public static ChooseSaveErrorResult SaveAlternative(string alternativeFileName) + public static ChooseSaveErrorResult SaveAlternative(FileName alternativeFileName) { if (alternativeFileName == null) throw new ArgumentNullException("alternativeFileName"); diff --git a/src/Main/Core/Project/Src/Services/MessageService/TextWriterMessageService.cs b/src/Main/Core/Project/Src/Services/MessageService/TextWriterMessageService.cs index 2cb603a48e..87b46d2c68 100644 --- a/src/Main/Core/Project/Src/Services/MessageService/TextWriterMessageService.cs +++ b/src/Main/Core/Project/Src/Services/MessageService/TextWriterMessageService.cs @@ -75,14 +75,14 @@ namespace ICSharpCode.Core.Implementation writer.WriteLine(caption + ": " + message); } - public void InformSaveError(string fileName, string message, string dialogName, Exception exceptionGot) + public void InformSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot) { writer.WriteLine(dialogName + ": " + message + " (" + fileName + ")"); if (exceptionGot != null) writer.WriteLine(exceptionGot.ToString()); } - public ChooseSaveErrorResult ChooseSaveError(string fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) + public ChooseSaveErrorResult ChooseSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) { writer.WriteLine(dialogName + ": " + message + " (" + fileName + ")"); if (exceptionGot != null) diff --git a/src/Main/Core/Project/Src/Services/PropertyService/Properties.cs b/src/Main/Core/Project/Src/Services/PropertyService/Properties.cs index 565e8bf9fc..d6381ee283 100644 --- a/src/Main/Core/Project/Src/Services/PropertyService/Properties.cs +++ b/src/Main/Core/Project/Src/Services/PropertyService/Properties.cs @@ -583,7 +583,7 @@ namespace ICSharpCode.Core return result.ToArray(); } - public void Save(string fileName) + public void Save(FileName fileName) { new XDocument(Save()).Save(fileName); } diff --git a/src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs b/src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs index 2a241be050..a672db309c 100644 --- a/src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs +++ b/src/Main/Core/Project/Src/Services/PropertyService/PropertyServiceImpl.cs @@ -129,7 +129,7 @@ namespace ICSharpCode.Core if (string.IsNullOrEmpty(configDirectory) || string.IsNullOrEmpty(propertyFileName)) throw new InvalidOperationException("No file name was specified on service creation"); - string fileName = Path.Combine(configDirectory, propertyFileName); + var fileName = FileName.Create(Path.Combine(configDirectory, propertyFileName)); using (LockPropertyFile()) { properties.Save(fileName); } diff --git a/src/Main/ICSharpCode.Core.WinForms/MessageService/WinFormsMessageService.cs b/src/Main/ICSharpCode.Core.WinForms/MessageService/WinFormsMessageService.cs index 98fde7680b..be8150f2e3 100644 --- a/src/Main/ICSharpCode.Core.WinForms/MessageService/WinFormsMessageService.cs +++ b/src/Main/ICSharpCode.Core.WinForms/MessageService/WinFormsMessageService.cs @@ -167,7 +167,7 @@ namespace ICSharpCode.Core.WinForms return result; } - public void InformSaveError(string fileName, string message, string dialogName, Exception exceptionGot) + public void InformSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot) { BeginInvoke( delegate { @@ -177,7 +177,7 @@ namespace ICSharpCode.Core.WinForms }); } - public ChooseSaveErrorResult ChooseSaveError(string fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) + public ChooseSaveErrorResult ChooseSaveError(FileName fileName, string message, string dialogName, Exception exceptionGot, bool chooseLocationEnabled) { ChooseSaveErrorResult r = ChooseSaveErrorResult.Ignore; Invoke( @@ -195,7 +195,7 @@ namespace ICSharpCode.Core.WinForms fdiag.Title = "Choose alternate file name"; fdiag.FileName = fileName; if (fdiag.ShowDialog() == DialogResult.OK) { - r = ChooseSaveErrorResult.SaveAlternative(fdiag.FileName); + r = ChooseSaveErrorResult.SaveAlternative(FileName.Create(fdiag.FileName)); break; } else { goto restartlabel; diff --git a/src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs b/src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs index 0d9d462525..21008a4ff5 100644 --- a/src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs +++ b/src/Main/SharpDevelop/Project/Build/BuildModifiedProjectsOnlyService.cs @@ -21,15 +21,36 @@ namespace ICSharpCode.SharpDevelop.Project { readonly Dictionary unmodifiedProjects = new Dictionary(); - public BuildModifiedProjectsOnlyService(IBuildService buildService) + public BuildModifiedProjectsOnlyService(IBuildService buildService, IProjectService projectService) { - // these actions cause a full recompilation: - ProjectService.SolutionClosed += MarkAllForRecompilation; + projectService.CurrentSolutionChanged += OnSolutionChanged; buildService.BuildFinished += BuildService_BuildFinished; FileUtility.FileSaved += OnFileSaved; } + void OnSolutionChanged(object sender, PropertyChangedEventArgs e) + { + lock (unmodifiedProjects) { + unmodifiedProjects.Clear(); + } + if (e.OldValue != null) { + e.OldValue.ActiveConfigurationChanged -= MarkAllForRecompilation; + e.OldValue.IsDirtyChanged -= MarkAllForRecompilation; + } + if (e.NewValue != null) { + e.NewValue.ActiveConfigurationChanged += MarkAllForRecompilation; + e.NewValue.IsDirtyChanged += MarkAllForRecompilation; + } + } + + void MarkAllForRecompilation(object sender, EventArgs e) + { + lock (unmodifiedProjects) { + unmodifiedProjects.Clear(); + } + } + void BuildService_BuildFinished(object sender, BuildEventArgs e) { // at the end of an successful build, mark all built projects as unmodified @@ -49,13 +70,6 @@ namespace ICSharpCode.SharpDevelop.Project } } - void MarkAllForRecompilation(object sender, EventArgs e) - { - lock (unmodifiedProjects) { - unmodifiedProjects.Clear(); - } - } - void OnFileSaved(object sender, FileNameEventArgs e) { if (ProjectService.OpenSolution != null) { diff --git a/src/Main/SharpDevelop/Project/Build/BuildService.cs b/src/Main/SharpDevelop/Project/Build/BuildService.cs index 5f5bbfb7cb..52f50afdfc 100644 --- a/src/Main/SharpDevelop/Project/Build/BuildService.cs +++ b/src/Main/SharpDevelop/Project/Build/BuildService.cs @@ -17,7 +17,7 @@ namespace ICSharpCode.SharpDevelop.Project public BuildService() { - this.buildModifiedProjectsOnly = new BuildModifiedProjectsOnlyService(this); + this.buildModifiedProjectsOnly = new BuildModifiedProjectsOnlyService(this, SD.ProjectService); } public event EventHandler BuildStarted; diff --git a/src/Main/SharpDevelop/Project/ProjectService.cs b/src/Main/SharpDevelop/Project/ProjectService.cs index 8a63f88ecc..5766a5b0f5 100644 --- a/src/Main/SharpDevelop/Project/ProjectService.cs +++ b/src/Main/SharpDevelop/Project/ProjectService.cs @@ -21,31 +21,44 @@ namespace ICSharpCode.SharpDevelop.Project var applicationStateInfoService = SD.GetService(); if (applicationStateInfoService != null) { - applicationStateInfoService.RegisterStateGetter("ProjectService.OpenSolution", delegate { return OpenSolution; }); + applicationStateInfoService.RegisterStateGetter("ProjectService.CurrentSolution", delegate { return CurrentSolution; }); applicationStateInfoService.RegisterStateGetter("ProjectService.CurrentProject", delegate { return CurrentProject; }); } } - volatile static ISolution openSolution; - volatile static IProject currentProject; + #region CurrentSolution property + AllProjects collection + volatile static ISolution currentSolution; + ConcatModelCollection allProjects = new ConcatModelCollection(); - public event PropertyChangedEventHandler OpenSolutionChanged = delegate { }; - public event PropertyChangedEventHandler CurrentProjectChanged = delegate { }; + public event PropertyChangedEventHandler CurrentSolutionChanged = delegate { }; - public ISolution OpenSolution { + public ISolution CurrentSolution { [DebuggerStepThrough] - get { return openSolution; } + get { return currentSolution; } private set { SD.MainThread.VerifyAccess(); - var oldValue = openSolution; + var oldValue = currentSolution; if (oldValue != value) { - openSolution = value; - OpenSolutionChanged(this, new PropertyChangedEventArgs("OpenSolution", oldValue, value)); + currentSolution = value; + if (oldValue != null) + allProjects.Inputs.Remove(oldValue.Projects); + CurrentSolutionChanged(this, new PropertyChangedEventArgs(oldValue, value)); + if (value != null) + allProjects.Inputs.Add(value.Projects); CommandManager.InvalidateRequerySuggested(); } } } + public IModelCollection AllProjects { + get { return allProjects; } + } + #endregion + + #region CurrentProject property + volatile static IProject currentProject; + public event PropertyChangedEventHandler CurrentProjectChanged = delegate { }; + public IProject CurrentProject { [DebuggerStepThrough] get { return currentProject; } @@ -55,12 +68,14 @@ namespace ICSharpCode.SharpDevelop.Project if (oldValue != value) { LoggingService.Info("CurrentProject changed to " + (value == null ? "null" : value.Name)); currentProject = value; - CurrentProjectChanged(this, new PropertyChangedEventArgs("CurrentProject", oldValue, value)); + CurrentProjectChanged(this, new PropertyChangedEventArgs(oldValue, value)); CommandManager.InvalidateRequerySuggested(); } } } + #endregion + #region FindProjectContainingFile public IProject FindProjectContainingFile(FileName fileName) { if (fileName == null) @@ -70,12 +85,12 @@ namespace ICSharpCode.SharpDevelop.Project if (currentProject != null && currentProject.IsFileInProject(fileName)) return currentProject; - ISolution openSolution = this.OpenSolution; - if (openSolution == null) + ISolution solution = this.CurrentSolution; + if (solution == null) return null; // Try all project's in the solution. IProject linkedProject = null; - foreach (IProject project in openSolution.Projects) { + foreach (IProject project in solution.Projects) { FileProjectItem file = project.FindFile(fileName); if (file != null) { if (file.IsLink) @@ -86,26 +101,64 @@ namespace ICSharpCode.SharpDevelop.Project } return linkedProject; } + #endregion + #region OpenSolutionOrProject public void OpenSolutionOrProject(FileName fileName) { - CloseSolution(); + if (!IsProjectOrSolutionFile(fileName)) { + MessageService.ShowError(StringParser.Parse("${res:ICSharpCode.SharpDevelop.Commands.OpenCombine.InvalidProjectOrCombine}", new StringTagPair("FileName", fileName))); + return; + } + if (!CloseSolution(allowCancel: true)) + return; FileUtility.ObservedLoad(OpenSolutionOrProjectInternal, fileName); } - void OpenSolutionOrProjectInternal(string fileName) + void OpenSolutionOrProjectInternal(FileName fileName) { using (var progress = AsynchronousWaitDialog.ShowWaitDialog("Loading Solution")) { - ISolution solution = LoadSolutionFile(FileName.Create(fileName), progress); + + ISolution solution = LoadSolutionFile(fileName, progress); throw new NotImplementedException(); } } + #endregion + + #region CloseSolution + public event EventHandler SolutionClosing = delegate { }; + public event EventHandler SolutionClosed = delegate { }; - public void CloseSolution() + public bool CloseSolution(bool allowCancel) { - throw new NotImplementedException(); + SD.MainThread.VerifyAccess(); + var solution = this.CurrentSolution; + if (solution == null) + return true; + + var cancelEventArgs = new SolutionClosingEventArgs(solution, allowCancel); + SolutionClosing(this, cancelEventArgs); + if (allowCancel && cancelEventArgs.Cancel) + return false; + + if (!SD.Workbench.CloseAllSolutionViews(force: !allowCancel)) + return false; + + // If a build is running, cancel it. + // If we would let a build run but unload the MSBuild projects, the next project.StartBuild call + // could cause an exception. + SD.BuildService.CancelBuild(); + + CurrentProject = null; + + this.CurrentSolution = null; // this will fire the CurrentSolutionChanged event + SolutionClosed(this, new SolutionEventArgs(solution)); + solution.Dispose(); + return true; } + #endregion + #region IsProjectOrSolutionFile public bool IsProjectOrSolutionFile(FileName fileName) { AddInTreeNode addinTreeNode = SD.AddInTree.GetTreeNode("/SharpDevelop/Workbench/Combine/FileFilter"); @@ -117,10 +170,12 @@ namespace ICSharpCode.SharpDevelop.Project } return false; } + #endregion + #region LoadSolutionFile + CreateEmptySolutionFile public ISolution LoadSolutionFile(FileName fileName, IProgressMonitor progress) { - Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName)); + Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName), SD.FileService); bool ok = false; try { using (var loader = new SolutionLoader(fileName)) { @@ -136,9 +191,10 @@ namespace ICSharpCode.SharpDevelop.Project public ISolution CreateEmptySolutionFile(FileName fileName) { - Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName)); + Solution solution = new Solution(fileName, new ProjectChangeWatcher(fileName), SD.FileService); solution.LoadPreferences(); return solution; } + #endregion } } diff --git a/src/Main/SharpDevelop/Project/Solution.cs b/src/Main/SharpDevelop/Project/Solution.cs index 4227957a77..ee28b8c311 100644 --- a/src/Main/SharpDevelop/Project/Solution.cs +++ b/src/Main/SharpDevelop/Project/Solution.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Windows.Threading; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Workbench; namespace ICSharpCode.SharpDevelop.Project { @@ -14,18 +16,26 @@ namespace ICSharpCode.SharpDevelop.Project { FileName fileName; DirectoryName directory; - IProjectChangeWatcher changeWatcher; + readonly IProjectChangeWatcher changeWatcher; + readonly IFileService fileService; - public Solution(FileName fileName, IProjectChangeWatcher changeWatcher) + public Solution(FileName fileName, IProjectChangeWatcher changeWatcher, IFileService fileService) { this.changeWatcher = changeWatcher; + this.fileService = fileService; this.ConfigurationNames = new SolutionConfigurationOrPlatformNameCollection(this, false); this.PlatformNames = new SolutionConfigurationOrPlatformNameCollection(this, true); this.FileName = fileName; + + fileService.FileRenamed += FileServiceFileRenamed; + fileService.FileRemoved += FileServiceFileRemoved; } public void Dispose() { + fileService.FileRenamed -= FileServiceFileRenamed; + fileService.FileRemoved -= FileServiceFileRemoved; + changeWatcher.Dispose(); foreach (var project in this.Projects) { project.Dispose(); @@ -111,6 +121,12 @@ namespace ICSharpCode.SharpDevelop.Project projects.Remove(project); if (wasStartupProject) StartupProjectChanged(this, EventArgs.Empty); + + // HACK: ensure the project gets disposed + SD.MainThread.InvokeAsyncAndForget( + delegate { + project.Dispose(); + }, DispatcherPriority.Background); } internal void ReportRemovedItem(ISolutionItem oldItem) @@ -243,6 +259,57 @@ namespace ICSharpCode.SharpDevelop.Project } #endregion + #region Handle FileService.FileRenamed / FileRemoved + void FileServiceFileRenamed(object sender, FileRenameEventArgs e) + { + string oldName = e.SourceFile; + string newName = e.TargetFile; + foreach (ISolutionFileItem fileItem in this.AllItems.OfType()) { + if (FileUtility.IsBaseDirectory(oldName, fileItem.FileName)) { + string newFullName = FileUtility.RenameBaseDirectory(fileItem.FileName, oldName, newName); + fileItem.FileName = FileName.Create(newFullName); + } + } + + foreach (IProject project in this.Projects) { + if (FileUtility.IsBaseDirectory(project.Directory, oldName)) { + foreach (ProjectItem item in project.Items) { + if (FileUtility.IsBaseDirectory(oldName, item.FileName)) { + ProjectService.OnProjectItemRemoved(new ProjectItemEventArgs(project, item)); + item.FileName = FileUtility.RenameBaseDirectory(item.FileName, oldName, newName); + ProjectService.OnProjectItemAdded(new ProjectItemEventArgs(project, item)); + } + } + } + } + } + + void FileServiceFileRemoved(object sender, FileEventArgs e) + { + string fileName = e.FileName; + + foreach (ISolutionFileItem fileItem in this.AllItems.OfType().ToArray()) { + if (FileUtility.IsBaseDirectory(fileName, fileItem.FileName)) { + fileItem.ParentFolder.Items.Remove(fileItem); + } + } + + foreach (IProject project in this.Projects) { + if (FileUtility.IsBaseDirectory(project.Directory, fileName)) { + IProjectItemListProvider provider = project as IProjectItemListProvider; + if (provider != null) { + foreach (ProjectItem item in provider.Items.ToArray()) { + if (FileUtility.IsBaseDirectory(fileName, item.FileName)) { + provider.RemoveProjectItem(item); + ProjectService.OnProjectItemRemoved(new ProjectItemEventArgs(project, item)); + } + } + } + } + } + } + #endregion + public bool IsReadOnly { get { try { diff --git a/src/Main/SharpDevelop/Workbench/FileService.cs b/src/Main/SharpDevelop/Workbench/FileService.cs index 7ea37c2fb5..a91e45dfe9 100644 --- a/src/Main/SharpDevelop/Workbench/FileService.cs +++ b/src/Main/SharpDevelop/Workbench/FileService.cs @@ -332,9 +332,9 @@ namespace ICSharpCode.SharpDevelop.Workbench this.switchToOpenedView = switchToOpenedView; } - public void Invoke(string fileName) + public void Invoke(FileName fileName) { - OpenedFile file = SD.FileService.GetOrCreateOpenedFile(FileName.Create(fileName)); + OpenedFile file = SD.FileService.GetOrCreateOpenedFile(fileName); try { IViewContent newContent = binding.CreateContentForFile(file); if (newContent != null) { diff --git a/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs b/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs index 9d5dd6176c..079b46e1ce 100644 --- a/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs +++ b/src/Main/SharpDevelop/Workbench/WpfWorkbench.cs @@ -443,23 +443,23 @@ namespace ICSharpCode.SharpDevelop.Workbench } } - public bool CloseAllSolutionViews() + public bool CloseAllSolutionViews(bool force) { bool result = true; foreach (IWorkbenchWindow window in this.WorkbenchWindowCollection.ToArray()) { if (window.ActiveViewContent != null && window.ActiveViewContent.CloseWithSolution) - result &= window.CloseWindow(false); + result &= window.CloseWindow(force); } return result; } #region ViewContent Memento Handling - string viewContentMementosFileName; + FileName viewContentMementosFileName; - string ViewContentMementosFileName { + FileName ViewContentMementosFileName { get { if (viewContentMementosFileName == null) { - viewContentMementosFileName = Path.Combine(PropertyService.ConfigDirectory, "LastViewStates.xml"); + viewContentMementosFileName = FileName.Create(Path.Combine(PropertyService.ConfigDirectory, "LastViewStates.xml")); } return viewContentMementosFileName; } @@ -568,31 +568,20 @@ namespace ICSharpCode.SharpDevelop.Workbench return; } - if (!Project.ProjectService.IsClosingCanceled()) { - // save preferences - Project.ProjectService.SaveSolutionPreferences(); - - while (SD.Workbench.WorkbenchWindowCollection.Count > 0) { - IWorkbenchWindow window = SD.Workbench.WorkbenchWindowCollection [0]; - if (!window.CloseWindow(false)) { - e.Cancel = true; - return; - } - } - - Project.ProjectService.CloseSolution(); - ((ParserService)SD.ParserService).StopParserThread(); - - restoreBoundsBeforeClosing = this.RestoreBounds; - - this.WorkbenchLayout = null; - - shutdownService.SignalShutdownToken(); - foreach (PadDescriptor padDescriptor in this.PadContentCollection) { - padDescriptor.Dispose(); - } - } else { + if (!SD.ProjectService.CloseSolution()) { e.Cancel = true; + return; + } + + ((ParserService)SD.ParserService).StopParserThread(); + + restoreBoundsBeforeClosing = this.RestoreBounds; + + this.WorkbenchLayout = null; + + shutdownService.SignalShutdownToken(); + foreach (PadDescriptor padDescriptor in this.PadContentCollection) { + padDescriptor.Dispose(); } } }