From 180d7d1cf6d842f92aadb4d0ddc368036dcb46ca Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 29 Sep 2007 20:20:18 +0000 Subject: [PATCH] Show build progress in status bar. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2703 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Gui/Components/StatusBar/SdStatusBar.cs | 222 +++++++----------- .../AsynchronousWaitDialog.Designer.cs | 1 - .../Src/Gui/Dialogs/AsynchronousWaitDialog.cs | 21 +- .../Base/Project/Src/Gui/IProgressMonitor.cs | 16 +- .../Base/Project/Src/Project/BuildEngine.cs | 155 +++++++++++- .../Base/Project/Src/Project/BuildResults.cs | 4 +- .../Services/ParserService/DomHostCallback.cs | 19 +- .../Services/ParserService/ParserService.cs | 6 +- .../Services/StatusBar/StatusBarService.cs | 110 ++++++++- .../Base/Project/Src/Util/ExtensionMethods.cs | 6 + .../Services/LoggingService/LoggingService.cs | 1 + .../BuildJob.cs | 10 + ...CSharpCode.SharpDevelop.BuildWorker.csproj | 1 - .../Program.cs | 7 + 14 files changed, 403 insertions(+), 176 deletions(-) diff --git a/src/Main/Base/Project/Src/Gui/Components/StatusBar/SdStatusBar.cs b/src/Main/Base/Project/Src/Gui/Components/StatusBar/SdStatusBar.cs index 9ebaef84ec..74fae02c87 100644 --- a/src/Main/Base/Project/Src/Gui/Components/StatusBar/SdStatusBar.cs +++ b/src/Main/Base/Project/Src/Gui/Components/StatusBar/SdStatusBar.cs @@ -1,7 +1,7 @@ // // // -// +// // $Revision$ // @@ -13,15 +13,15 @@ using ICSharpCode.Core; namespace ICSharpCode.SharpDevelop.Gui { - public class SdStatusBar : StatusStrip, IProgressMonitor + public class SdStatusBar : StatusStrip { - ToolStripProgressBar statusProgressBar = new ToolStripProgressBar(); - ToolStripStatusLabel jobNamePanel = new ToolStripStatusLabel(); + ToolStripProgressBar statusProgressBar = new ToolStripProgressBar(); + ToolStripStatusLabel jobNamePanel = new ToolStripStatusLabel(); - ToolStripStatusLabel txtStatusBarPanel = new ToolStripStatusLabel(); - ToolStripStatusLabel cursorStatusBarPanel = new ToolStripStatusLabel(); - ToolStripStatusLabel modeStatusBarPanel = new ToolStripStatusLabel(); - ToolStripStatusLabel springLabel = new ToolStripStatusLabel(); + ToolStripStatusLabel txtStatusBarPanel = new ToolStripStatusLabel(); + ToolStripStatusLabel cursorStatusBarPanel = new ToolStripStatusLabel(); + ToolStripStatusLabel modeStatusBarPanel = new ToolStripStatusLabel(); + ToolStripStatusLabel springLabel = new ToolStripStatusLabel(); public ToolStripStatusLabel CursorStatusBarPanel { get { @@ -38,27 +38,27 @@ namespace ICSharpCode.SharpDevelop.Gui public SdStatusBar() { -// txtStatusBarPanel.Width = 500; -// txtStatusBarPanel.AutoSize = StatusBarPanelAutoSize.Spring; -// Panels.Add(txtStatusBarPanel); -// // manager.Add(new StatusBarContributionItem("TextPanel", txtStatusBarPanel)); -// -// statusProgressBar.Width = 200; -// statusProgressBar.Height = 14; -// statusProgressBar.Location = new Point(160, 6); -// statusProgressBar.Minimum = 0; -// statusProgressBar.Visible = false; -// Controls.Add(statusProgressBar); -// -// cursorStatusBarPanel.Width = 200; -// cursorStatusBarPanel.AutoSize = StatusBarPanelAutoSize.None; -// cursorStatusBarPanel.Alignment = HorizontalAlignment.Left; -// Panels.Add(cursorStatusBarPanel); -// -// modeStatusBarPanel.Width = 44; -// modeStatusBarPanel.AutoSize = StatusBarPanelAutoSize.None; -// modeStatusBarPanel.Alignment = HorizontalAlignment.Right; -// Panels.Add(modeStatusBarPanel); + // txtStatusBarPanel.Width = 500; + // txtStatusBarPanel.AutoSize = StatusBarPanelAutoSize.Spring; + // Panels.Add(txtStatusBarPanel); + // // manager.Add(new StatusBarContributionItem("TextPanel", txtStatusBarPanel)); + // + // statusProgressBar.Width = 200; + // statusProgressBar.Height = 14; + // statusProgressBar.Location = new Point(160, 6); + // statusProgressBar.Minimum = 0; + // statusProgressBar.Visible = false; + // Controls.Add(statusProgressBar); + // + // cursorStatusBarPanel.Width = 200; + // cursorStatusBarPanel.AutoSize = StatusBarPanelAutoSize.None; + // cursorStatusBarPanel.Alignment = HorizontalAlignment.Left; + // Panels.Add(cursorStatusBarPanel); + // + // modeStatusBarPanel.Width = 44; + // modeStatusBarPanel.AutoSize = StatusBarPanelAutoSize.None; + // modeStatusBarPanel.Alignment = HorizontalAlignment.Right; + // Panels.Add(modeStatusBarPanel); springLabel.Spring = true; cursorStatusBarPanel.AutoSize = false; @@ -71,12 +71,6 @@ namespace ICSharpCode.SharpDevelop.Gui Items.AddRange(new ToolStripItem[] { txtStatusBarPanel, springLabel, jobNamePanel, statusProgressBar, cursorStatusBarPanel, modeStatusBarPanel }); } - protected override void OnHandleCreated(EventArgs e) - { - base.OnHandleCreated(e); - UpdateText(); - } - public void ShowErrorMessage(string message) { SetMessage("Error : " + message); @@ -87,8 +81,6 @@ namespace ICSharpCode.SharpDevelop.Gui SetMessage(image, "Error : " + message); } - string currentMessage; - public void SetMessage(string message) { SetMessage(message, false); @@ -96,22 +88,20 @@ namespace ICSharpCode.SharpDevelop.Gui public void SetMessage(string message, bool highlighted) { - if (highlighted) { - txtStatusBarPanel.BackColor = SystemColors.Highlight; - txtStatusBarPanel.ForeColor = Color.White; - } else if (txtStatusBarPanel.BackColor == SystemColors.Highlight) { - txtStatusBarPanel.BackColor = SystemColors.Control; - txtStatusBarPanel.ForeColor = SystemColors.ControlText; - } - - currentMessage = message; - if (this.IsHandleCreated) - BeginInvoke(new MethodInvoker(UpdateText)); - } - - void UpdateText() - { - txtStatusBarPanel.Text = currentMessage; + Action setMessageAction = delegate { + if (highlighted) { + txtStatusBarPanel.BackColor = SystemColors.Highlight; + txtStatusBarPanel.ForeColor = Color.White; + } else if (txtStatusBarPanel.BackColor == SystemColors.Highlight) { + txtStatusBarPanel.BackColor = SystemColors.Control; + txtStatusBarPanel.ForeColor = SystemColors.ControlText; + } + txtStatusBarPanel.Text = message; + }; + if (WorkbenchSingleton.InvokeRequired) + WorkbenchSingleton.SafeThreadAsyncCall(setMessageAction); + else + setMessageAction(); } public void SetMessage(Image image, string message) @@ -119,90 +109,56 @@ namespace ICSharpCode.SharpDevelop.Gui SetMessage(message); } - // Progress Monitor implementation - int totalWork; - - public void BeginTask(string name, int totalWork, bool allowCancel) - { - taskName = name; - this.totalWork = totalWork; - this.workDone = 0; - if (this.IsHandleCreated) { - this.BeginInvoke(new MethodInvoker(MakeVisible)); - } - } - - void MakeVisible() - { - statusProgressBar.Value = 0; - statusProgressBar.Maximum = totalWork; - SetTaskName(); - jobNamePanel.Visible = true; - statusProgressBar.Visible = true; - } - - void MakeInvisible() - { - // Setting jobNamePanel.Visible = false will also hide the other labels to the right (WinForms Bug?) - jobNamePanel.Text = ""; - statusProgressBar.Visible = false; - } - - int workDone; - - public int WorkDone { - get { - return workDone; - } - set { - if (workDone == value) return; - workDone = value; - this.BeginInvoke(new MethodInvoker(SetWorkDone)); - } - } + // Displaying progress - void SetWorkDone() - { - if (workDone < statusProgressBar.Maximum) { - statusProgressBar.Value = workDone; - } - } + bool statusProgressBarIsVisible; + string currentTaskName; - public void Done() + public void DisplayProgress(string taskName, int workDone, int totalWork) { - taskName = null; - if (this.IsHandleCreated) { - this.BeginInvoke(new MethodInvoker(MakeInvisible)); - } - } - - string taskName; - - public string TaskName { - get { - return taskName; - } - set { - if (taskName == value) return; - taskName = value; - this.BeginInvoke(new MethodInvoker(SetTaskName)); - } - } - - void SetTaskName() + if (taskName == null) + taskName = ""; + if (totalWork < 0) + totalWork = 0; + if (workDone < 0) + workDone = 0; + if (workDone > totalWork) + workDone = totalWork; + + WorkbenchSingleton.SafeThreadAsyncCall( + delegate { + if (!statusProgressBarIsVisible) { + statusProgressBar.Visible = true; + statusProgressBarIsVisible = true; + } + + if (totalWork == 0) { + statusProgressBar.Style = ProgressBarStyle.Marquee; + } else { + statusProgressBar.Style = ProgressBarStyle.Continuous; + if (statusProgressBar.Maximum != totalWork) { + if (statusProgressBar.Value > totalWork) + statusProgressBar.Value = 0; + statusProgressBar.Maximum = totalWork; + } + statusProgressBar.Value = workDone; + } + + if (currentTaskName != taskName) { + currentTaskName = taskName; + jobNamePanel.Text = StringParser.Parse(taskName); + } + }); + } + + public void HideProgress() { - jobNamePanel.Text = StringParser.Parse(taskName); - } - - bool showingDialog; - - public bool ShowingDialog { - get { return showingDialog; } - set { showingDialog = value; } - } - - public bool IsCancelled { - get { return false; } + WorkbenchSingleton.SafeThreadAsyncCall( + delegate { + statusProgressBarIsVisible = false; + statusProgressBar.Visible = false; + jobNamePanel.Text = currentTaskName = ""; + }); } } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.Designer.cs b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.Designer.cs index 6fab5d7f8c..bfe0804d21 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.Designer.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.Designer.cs @@ -68,7 +68,6 @@ namespace ICSharpCode.SharpDevelop.Gui this.cancelButton.TabIndex = 2; this.cancelButton.Text = "button1"; this.cancelButton.UseVisualStyleBackColor = true; - this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick); // // AsynchronousWaitDialogForm // diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs index d321106840..f967bfa96f 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs @@ -21,11 +21,6 @@ namespace ICSharpCode.SharpDevelop.Gui InitializeComponent(); cancelButton.Text = ResourceService.GetString("Global.CancelButtonText"); } - - void CancelButtonClick(object sender, System.EventArgs e) - { - cancelButton.Enabled = false; - } } /// @@ -100,7 +95,7 @@ namespace ICSharpCode.SharpDevelop.Gui return; dlg = new AsynchronousWaitDialogForm(); dlg.Text = StringParser.Parse(titleName); - dlg.cancelButton.Click += delegate { cancelled = true; }; + dlg.cancelButton.Click += CancelButtonClick; UpdateTask(); dlg.CreateControl(); IntPtr h = dlg.Handle; // force handle creation @@ -257,10 +252,24 @@ namespace ICSharpCode.SharpDevelop.Gui } } + void CancelButtonClick(object sender, EventArgs e) + { + dlg.cancelButton.Enabled = false; + if (!cancelled) { + cancelled = true; + EventHandler eh = Cancelled; + if (eh != null) { + eh(this, e); + } + } + } + public bool IsCancelled { get { return cancelled; } } + + public event EventHandler Cancelled; } } diff --git a/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs b/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs index c2b7411a0f..7dcb962b06 100644 --- a/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs +++ b/src/Main/Base/Project/Src/Gui/IProgressMonitor.cs @@ -1,10 +1,12 @@ // // // -// +// // $Revision$ // +using System; + namespace ICSharpCode.SharpDevelop.Gui { /// @@ -43,8 +45,8 @@ namespace ICSharpCode.SharpDevelop.Gui } /// - /// Gets/sets if the task current shows a modal dialog. Set this property to true to make progress dialogs windows - /// temporarily invisible while your modal dialog is showing. + /// Gets/sets if the task current shows a modal dialog. Set this property to true to make progress + /// dialogs windows temporarily invisible while your modal dialog is showing. /// bool ShowingDialog { get; @@ -57,6 +59,12 @@ namespace ICSharpCode.SharpDevelop.Gui bool IsCancelled { get; } + + /// + /// Occurs when the user cancels the operation. + /// This event could be raised on any thread. + /// + event EventHandler Cancelled; } internal class DummyProgressMonitor : IProgressMonitor @@ -93,5 +101,7 @@ namespace ICSharpCode.SharpDevelop.Gui get { return showingDialog; } set { showingDialog = value; } } + + public event EventHandler Cancelled { add { } remove { } } } } diff --git a/src/Main/Base/Project/Src/Project/BuildEngine.cs b/src/Main/Base/Project/Src/Project/BuildEngine.cs index 2dde78881b..d6a9acc4b1 100644 --- a/src/Main/Base/Project/Src/Project/BuildEngine.cs +++ b/src/Main/Base/Project/Src/Project/BuildEngine.cs @@ -9,6 +9,9 @@ using System; using System.Collections.Generic; using System.Linq; +using ICSharpCode.SharpDevelop.Gui; +using System.Text; + namespace ICSharpCode.SharpDevelop.Project { /// @@ -20,19 +23,37 @@ namespace ICSharpCode.SharpDevelop.Project public sealed class BuildEngine { #region Building in the SharpDevelop GUI - static bool guiBuildRunning; + static CancellableProgressMonitor guiBuildProgressMonitor; public static void BuildInGui(IBuildable project, BuildOptions options) { - if (guiBuildRunning) { + WorkbenchSingleton.DebugAssertMainThread(); + if (guiBuildProgressMonitor != null) { BuildResults results = new BuildResults(); results.Add(new BuildError(null, Core.ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning"))); results.Result = BuildResultCode.MSBuildAlreadyRunning; options.Callback(results); } else { - guiBuildRunning = true; + guiBuildProgressMonitor = new CancellableProgressMonitor(StatusBarService.CreateProgressMonitor()); Gui.WorkbenchSingleton.Workbench.GetPad(typeof(Gui.CompilerMessageView)).BringPadToFront(); - StartBuild(project, options, new MessageViewSink(TaskService.BuildMessageViewCategory)); + StartBuild(project, options, + new MessageViewSink(TaskService.BuildMessageViewCategory), + guiBuildProgressMonitor); + } + } + + public static bool IsGuiBuildRunning { + get { + WorkbenchSingleton.DebugAssertMainThread(); + return guiBuildProgressMonitor != null; + } + } + + public static void CancelGuiBuild() + { + WorkbenchSingleton.DebugAssertMainThread(); + if (guiBuildProgressMonitor != null) { + guiBuildProgressMonitor.Cancel(); } } @@ -56,13 +77,82 @@ namespace ICSharpCode.SharpDevelop.Project public void Done(bool success) { - guiBuildRunning = false; + WorkbenchSingleton.SafeThreadAsyncCall(delegate { guiBuildProgressMonitor = null; }); + } + } + + sealed class CancellableProgressMonitor : IProgressMonitor + { + IProgressMonitor baseProgressMonitor; + + public CancellableProgressMonitor(IProgressMonitor baseProgressMonitor) + { + this.baseProgressMonitor = baseProgressMonitor; + } + + readonly object lockObject = new object(); + bool isCancelAllowed; + bool isCancelled; + + public bool IsCancelAllowed { + get { return isCancelAllowed; } + } + + public bool IsCancelled { + get { return isCancelled; } + } + + public void Cancel() + { + EventHandler eh = null; + lock (lockObject) { + if (isCancelAllowed) { + ICSharpCode.Core.LoggingService.Debug(""); + isCancelled = true; + eh = Cancelled; + } + } + if (eh != null) + eh(this, EventArgs.Empty); + } + + public event EventHandler Cancelled; + + public void BeginTask(string name, int totalWork, bool allowCancel) + { + baseProgressMonitor.BeginTask(name, totalWork, allowCancel); + lock (lockObject) { + isCancelAllowed = allowCancel; + } + } + + public void Done() + { + lock (lockObject) { + isCancelAllowed = false; + } + baseProgressMonitor.Done(); + } + + public int WorkDone { + get { return baseProgressMonitor.WorkDone; } + set { baseProgressMonitor.WorkDone = value; } + } + + public string TaskName { + get { return baseProgressMonitor.TaskName; } + set { baseProgressMonitor.TaskName = value; } + } + + public bool ShowingDialog { + get { return baseProgressMonitor.ShowingDialog; } + set { baseProgressMonitor.ShowingDialog = value; } } } #endregion #region StartBuild - public static void StartBuild(IBuildable project, BuildOptions options, IBuildFeedbackSink realtimeBuildFeedbackSink) + public static void StartBuild(IBuildable project, BuildOptions options, IBuildFeedbackSink realtimeBuildFeedbackSink, IProgressMonitor progressMonitor) { if (project == null) throw new ArgumentNullException("solution"); @@ -81,6 +171,7 @@ namespace ICSharpCode.SharpDevelop.Project BuildEngine engine = new BuildEngine(options, project); engine.buildStart = DateTime.Now; engine.combinedBuildFeedbackSink = realtimeBuildFeedbackSink; + engine.progressMonitor = progressMonitor; engine.configMatchings = solution.GetActiveConfigurationsAndPlatformsForProjects(options.SolutionConfiguration, options.SolutionPlatform); try { engine.rootNode = engine.CreateBuildGraph(project); @@ -99,8 +190,14 @@ namespace ICSharpCode.SharpDevelop.Project if (engine.workersToStart < 1) engine.workersToStart = 1; + if (progressMonitor != null) { + progressMonitor.Cancelled += engine.BuildCancelled; + progressMonitor.BeginTask("", engine.nodeDict.Count, true); + } + engine.ReportMessageInternal("${res:MainWindow.CompilerMessages.BuildStarted}"); engine.StartBuildProjects(); + engine.UpdateProgressTaskName(); } #endregion @@ -184,12 +281,14 @@ namespace ICSharpCode.SharpDevelop.Project #region BuildEngine fields and constructor readonly Dictionary nodeDict = new Dictionary(); readonly BuildOptions options; + IProgressMonitor progressMonitor; List configMatchings; BuildNode rootNode; IBuildable rootProject; BuildResults results = new BuildResults(); DateTime buildStart; + List projectsCurrentlyBuilding = new List(); List projectsReadyForBuildStart = new List(); int workersToStart, runningWorkers; @@ -289,7 +388,7 @@ namespace ICSharpCode.SharpDevelop.Project { lock (this) { while (workersToStart > 0) { - if (projectsReadyForBuildStart.Count == 0) { + if (buildIsCancelled || projectsReadyForBuildStart.Count == 0) { if (runningWorkers == 0) { BuildDone(); } @@ -319,6 +418,7 @@ namespace ICSharpCode.SharpDevelop.Project ICSharpCode.Core.LoggingService.Debug("Start building " + node.project.Name); runningWorkers++; + projectsCurrentlyBuilding.Add(node); if (hasDependencyErrors) { ICSharpCode.Core.LoggingService.Debug("Skipped building " + node.project.Name + " (errors in dependencies)"); node.hasErrors = true; @@ -366,6 +466,12 @@ namespace ICSharpCode.SharpDevelop.Project runningWorkers--; node.buildFinished = true; node.hasErrors = !success; + + projectsCurrentlyBuilding.Remove(node); + if (progressMonitor != null) { + progressMonitor.WorkDone += 1; + } + foreach (BuildNode n in node.dependentOnThis) { n.outstandingDependencies--; if (n.outstandingDependencies == 0) @@ -375,6 +481,7 @@ namespace ICSharpCode.SharpDevelop.Project } LogBuildFinished(node); StartBuildProjects(); + UpdateProgressTaskName(); } bool buildIsDone; @@ -393,7 +500,11 @@ namespace ICSharpCode.SharpDevelop.Project } string buildTime = " (" + (DateTime.Now - buildStart).ToString() + ")"; - if (rootNode.hasErrors) { + if (buildIsCancelled) { + results.Result = BuildResultCode.Cancelled; + + ReportMessageInternal("Build was cancelled."); + } else if (rootNode.hasErrors) { results.Result = BuildResultCode.Error; ReportMessageInternal("${res:MainWindow.CompilerMessages.BuildFailed}" + buildTime); @@ -404,6 +515,9 @@ namespace ICSharpCode.SharpDevelop.Project ReportMessageInternal("${res:MainWindow.CompilerMessages.BuildFinished}" + buildTime); //StatusBarService.SetMessage("${res:MainWindow.CompilerMessages.BuildFinished}"); } + if (progressMonitor != null) { + progressMonitor.Done(); + } if (combinedBuildFeedbackSink != null) { combinedBuildFeedbackSink.Done(results.Result == BuildResultCode.Success); } @@ -413,6 +527,20 @@ namespace ICSharpCode.SharpDevelop.Project } #endregion + #region Cancel build + bool buildIsCancelled; + + void BuildCancelled(object sender, EventArgs e) + { + lock (this) { + if (buildIsDone) + return; + buildIsCancelled = true; + } + results.Add(new BuildError(null, "Build was cancelled.")); + } + #endregion + #region Logging IBuildFeedbackSink combinedBuildFeedbackSink; /// @@ -487,6 +615,17 @@ namespace ICSharpCode.SharpDevelop.Project if (combinedBuildFeedbackSink != null) combinedBuildFeedbackSink.ReportMessage(message); } + + void UpdateProgressTaskName() + { + lock (this) { + if (progressMonitor != null) { + progressMonitor.TaskName = "Building " + + projectsCurrentlyBuilding.Select(n => n.project.Name).Join(", ") + + "..."; + } + } + } #endregion } } diff --git a/src/Main/Base/Project/Src/Project/BuildResults.cs b/src/Main/Base/Project/Src/Project/BuildResults.cs index bc96117587..3a025eed2a 100644 --- a/src/Main/Base/Project/Src/Project/BuildResults.cs +++ b/src/Main/Base/Project/Src/Project/BuildResults.cs @@ -21,7 +21,9 @@ namespace ICSharpCode.SharpDevelop.Project /// A project build file is not valid BuildFileError, /// Build was not executed because another build is running - MSBuildAlreadyRunning + MSBuildAlreadyRunning, + /// Build was cancelled. + Cancelled } /// diff --git a/src/Main/Base/Project/Src/Services/ParserService/DomHostCallback.cs b/src/Main/Base/Project/Src/Services/ParserService/DomHostCallback.cs index 91a89683cb..52b0a70441 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/DomHostCallback.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/DomHostCallback.cs @@ -19,6 +19,8 @@ namespace ICSharpCode.SharpDevelop /// internal static class DomHostCallback { + static IProgressMonitor assemblyLoadProgressMonitor; + internal static void Register() { HostCallback.RenameMember = Refactoring.FindReferencesAndRenameHelper.RenameMember; @@ -32,13 +34,16 @@ namespace ICSharpCode.SharpDevelop MessageService.ShowError(ex, message); }; - HostCallback.BeginAssemblyLoad = delegate(string shortName) { - StatusBarService.ProgressMonitor.BeginTask( - StringParser.Parse("${res:ICSharpCode.SharpDevelop.LoadingFile}", new string[,] {{"Filename", shortName}}), - 100, false - ); - }; - HostCallback.FinishAssemblyLoad = StatusBarService.ProgressMonitor.Done; + if (WorkbenchSingleton.MainForm != null) { + assemblyLoadProgressMonitor = StatusBarService.CreateProgressMonitor(); + HostCallback.BeginAssemblyLoad = delegate(string shortName) { + assemblyLoadProgressMonitor.BeginTask( + StringParser.Parse("${res:ICSharpCode.SharpDevelop.LoadingFile}", new string[,] {{"Filename", shortName}}), + 100, false + ); + }; + HostCallback.FinishAssemblyLoad = assemblyLoadProgressMonitor.Done; + } HostCallback.ShowAssemblyLoadError = delegate(string fileName, string include, string message) { WorkbenchSingleton.SafeThreadAsyncCall(ShowAssemblyLoadError, diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index f3f0ce3103..96820da5f4 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -154,7 +154,7 @@ namespace ICSharpCode.SharpDevelop static void LoadSolutionProjectsInternal() { - IProgressMonitor progressMonitor = StatusBarService.ProgressMonitor; + IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); List createdContents = new List(); foreach (IProject project in ProjectService.OpenSolution.Projects) { try { @@ -195,7 +195,7 @@ namespace ICSharpCode.SharpDevelop static void InitAddedProject(object state) { ParseProjectContent newContent = (ParseProjectContent)state; - IProgressMonitor progressMonitor = StatusBarService.ProgressMonitor; + IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); newContent.Initialize1(progressMonitor); progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", newContent.GetInitializationWorkAmount(), false); newContent.Initialize2(progressMonitor); @@ -225,7 +225,7 @@ namespace ICSharpCode.SharpDevelop { bool parsing = false; ParseProjectContent job; - IProgressMonitor progressMonitor = StatusBarService.ProgressMonitor; + IProgressMonitor progressMonitor = StatusBarService.CreateProgressMonitor(); while (true) { // get next job diff --git a/src/Main/Base/Project/Src/Services/StatusBar/StatusBarService.cs b/src/Main/Base/Project/Src/Services/StatusBar/StatusBarService.cs index e262cab971..79ed8aeb31 100644 --- a/src/Main/Base/Project/Src/Services/StatusBar/StatusBarService.cs +++ b/src/Main/Base/Project/Src/Services/StatusBar/StatusBarService.cs @@ -1,11 +1,12 @@ // // // -// +// // $Revision$ // using System; +using System.Linq; using System.Drawing; using System.Windows.Forms; @@ -41,19 +42,15 @@ namespace ICSharpCode.SharpDevelop } } - public static IProgressMonitor ProgressMonitor { - get { - System.Diagnostics.Debug.Assert(statusBar != null); - return statusBar; - } - } - public static void SetCaretPosition(int x, int y, int charOffset) { - statusBar.CursorStatusBarPanel.Text = StringParser.Parse("${res:StatusBarService.CursorStatusBarPanelText}", - new string[,] { {"Line", String.Format("{0,-10}", y + 1)}, - {"Column", String.Format("{0,-5}", x + 1)}, - {"Character", String.Format("{0,-5}", charOffset + 1)}}); + statusBar.CursorStatusBarPanel.Text = StringParser.Parse( + "${res:StatusBarService.CursorStatusBarPanelText}", + new string[,] { + {"Line", String.Format("{0,-10}", y + 1)}, + {"Column", String.Format("{0,-5}", x + 1)}, + {"Character", String.Format("{0,-5}", charOffset + 1)} + }); } public static void SetInsertMode(bool insertMode) @@ -102,7 +99,7 @@ namespace ICSharpCode.SharpDevelop public static void Update() { System.Diagnostics.Debug.Assert(statusBar != null); - /* statusBar.Panels.Clear(); + /* statusBar.Panels.Clear(); statusBar.Controls.Clear(); foreach (StatusBarContributionItem item in Items) { @@ -115,5 +112,92 @@ namespace ICSharpCode.SharpDevelop } }*/ } + + #region Progress Monitor + static HashSet activeProgressMonitors = new HashSet(); + static StatusBarProgressMonitor currentProgressMonitor; + + public static IProgressMonitor CreateProgressMonitor() + { + System.Diagnostics.Debug.Assert(statusBar != null); + return new StatusBarProgressMonitor(); + } + + sealed class StatusBarProgressMonitor : IProgressMonitor + { + int workDone, totalWork; + + public int WorkDone { + get { return workDone; } + set { + if (workDone == value) + return; + workDone = value; + lock (activeProgressMonitors) { + if (currentProgressMonitor == this) { + UpdateDisplay(); + } + } + } + } + + void UpdateDisplay() + { + statusBar.DisplayProgress(taskName, workDone, totalWork); + } + + string taskName; + + public string TaskName { + get { return taskName; } + set { + if (taskName == value) + return; + taskName = value; + lock (activeProgressMonitors) { + if (currentProgressMonitor == this) { + UpdateDisplay(); + } + } + } + } + + public bool ShowingDialog { get; set; } + + public bool IsCancelled { + get { return false; } + } + + public void BeginTask(string name, int totalWork, bool allowCancel) + { + lock (activeProgressMonitors) { + activeProgressMonitors.Add(this); + currentProgressMonitor = this; + this.taskName = name; + this.workDone = 0; + this.totalWork = totalWork; + UpdateDisplay(); + } + } + + public void Done() + { + lock (activeProgressMonitors) { + activeProgressMonitors.Remove(this); + if (currentProgressMonitor == this) { + if (activeProgressMonitors.Count > 0) { + currentProgressMonitor = activeProgressMonitors.First(); + currentProgressMonitor.UpdateDisplay(); + } else { + currentProgressMonitor = null; + statusBar.HideProgress(); + } + } + } + } + + public event EventHandler Cancelled { add { } remove { } } + } + #endregion } } diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs index feb027462d..ffdd0913f5 100644 --- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs +++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs @@ -9,6 +9,7 @@ using System; using System.Collections; using System.Collections.ObjectModel; using System.Collections.Generic; +using System.Linq; namespace ICSharpCode.SharpDevelop { @@ -33,5 +34,10 @@ namespace ICSharpCode.SharpDevelop { return Array.AsReadOnly(arr); } + + public static string Join(this IEnumerable input, string separator) + { + return string.Join(separator, input.ToArray()); + } } } diff --git a/src/Main/Core/Project/Src/Services/LoggingService/LoggingService.cs b/src/Main/Core/Project/Src/Services/LoggingService/LoggingService.cs index b274020c73..c58e159cbb 100644 --- a/src/Main/Core/Project/Src/Services/LoggingService/LoggingService.cs +++ b/src/Main/Core/Project/Src/Services/LoggingService/LoggingService.cs @@ -7,6 +7,7 @@ using System; using System.IO; +using System.Diagnostics; using log4net; using log4net.Config; diff --git a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/BuildJob.cs b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/BuildJob.cs index 16dcf210e6..1eba4680c8 100644 --- a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/BuildJob.cs +++ b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/BuildJob.cs @@ -68,5 +68,15 @@ namespace ICSharpCode.SharpDevelop.BuildWorker } return b.ToString(); } + + [NonSerialized] + internal Action CancelCallback; + + public void Cancel() + { + if (CancelCallback != null) { + CancelCallback(); + } + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/ICSharpCode.SharpDevelop.BuildWorker.csproj b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/ICSharpCode.SharpDevelop.BuildWorker.csproj index 7b54bba4b4..84d40629fc 100644 --- a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/ICSharpCode.SharpDevelop.BuildWorker.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/ICSharpCode.SharpDevelop.BuildWorker.csproj @@ -66,7 +66,6 @@ - diff --git a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs index 6323586d16..8bdd0de987 100644 --- a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs +++ b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs @@ -165,6 +165,13 @@ namespace ICSharpCode.SharpDevelop.BuildWorker requestCancellation = false; hostEventSource = new EventSource(); } + job.CancelCallback = delegate { + lock (this) { + if (currentJob == job) { + requestCancellation = true; + } + } + }; bool success = false; try { if (engine == null) {