#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

291 lines
7.4 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Gui
{
internal sealed partial class AsynchronousWaitDialogForm
{
internal AsynchronousWaitDialogForm()
{
InitializeComponent();
cancelButton.Text = ResourceService.GetString("Global.CancelButtonText");
}
}
/// <summary>
/// Shows an wait dialog on a separate thread if the action takes longer than 500ms.
/// Usage:
/// using (AsynchronousWaitDialog.ShowWaitDialog("title")) {
/// long_running_action();
/// }
/// or:
/// using (AsynchronousWaitDialog monitor = AsynchronousWaitDialog.ShowWaitDialog("title")) {
/// long_running_action(monitor);
/// }
/// </summary>
public sealed class AsynchronousWaitDialog : IProgressMonitor, IDisposable
{
/// <summary>
/// Delay until the wait dialog becomes visible, in ms.
/// </summary>
public const int ShowWaitDialogDelay = 500;
readonly object lockObject = new object();
bool disposed;
AsynchronousWaitDialogForm dlg;
volatile int totalWork;
volatile string titleName;
volatile string taskName;
volatile int workDone;
volatile bool cancelled;
volatile bool allowCancel;
/// <summary>
/// Shows a wait dialog.
/// </summary>
/// <param name="titleName">Title of the wait dialog</param>
/// <returns>AsynchronousWaitDialog object - you can use it to access the wait dialog's properties.
/// To close the wait dialog, call Dispose() on the AsynchronousWaitDialog object</returns>
public static AsynchronousWaitDialog ShowWaitDialog(string titleName)
{
if (titleName == null)
throw new ArgumentNullException("titleName");
AsynchronousWaitDialog h = new AsynchronousWaitDialog(titleName, false);
h.Start();
return h;
}
/// <summary>
/// Shows a wait dialog.
/// </summary>
/// <param name="titleName">Title of the wait dialog</param>
/// <param name="allowCancel">Specifies whether a cancel button should be shown.</param>
/// <returns>AsynchronousWaitDialog object - you can use it to access the wait dialog's properties.
/// To close the wait dialog, call Dispose() on the AsynchronousWaitDialog object</returns>
public static AsynchronousWaitDialog ShowWaitDialog(string titleName, bool allowCancel)
{
if (titleName == null)
throw new ArgumentNullException("titleName");
AsynchronousWaitDialog h = new AsynchronousWaitDialog(titleName, allowCancel);
h.Start();
return h;
}
private AsynchronousWaitDialog(string titleName, bool allowCancel)
{
this.titleName = titleName;
Done(); // set default values for titleName
this.allowCancel = allowCancel;
}
#region Start waiting thread
/// <summary>
/// Start waiting thread
/// </summary>
internal void Start()
{
Thread newThread = new Thread(Run);
newThread.Name = "AsynchronousWaitDialog thread";
newThread.Start();
Thread.Sleep(0); // allow new thread to start
}
[STAThread]
void Run()
{
Thread.Sleep(ShowWaitDialogDelay);
lock (lockObject) {
if (disposed)
return;
dlg = new AsynchronousWaitDialogForm();
dlg.Text = StringParser.Parse(titleName);
dlg.cancelButton.Click += CancelButtonClick;
UpdateTask();
dlg.CreateControl();
IntPtr h = dlg.Handle; // force handle creation
}
if (showingDialog) {
Application.Run();
} else {
Application.Run(dlg);
}
}
#endregion
/// <summary>
/// Closes the wait dialog.
/// </summary>
public void Dispose()
{
lock (lockObject) {
if (disposed) return;
disposed = true;
if (dlg != null) {
dlg.BeginInvoke(new MethodInvoker(DisposeInvoked));
}
}
}
void DisposeInvoked()
{
dlg.Dispose();
Application.ExitThread();
}
public int WorkDone {
get {
return workDone;
}
set {
if (workDone != value) {
lock (lockObject) {
workDone = value;
if (dlg != null && disposed == false) {
dlg.BeginInvoke(new MethodInvoker(UpdateProgress));
}
}
}
}
}
public string TaskName {
get {
lock (lockObject) {
return taskName;
}
}
set {
if (taskName != value) {
lock (lockObject) {
taskName = value;
if (dlg != null && disposed == false) {
dlg.BeginInvoke(new MethodInvoker(UpdateTask));
}
}
}
}
}
/// <summary>
/// Begins a new task with the specified name and total amount of work.
/// </summary>
/// <param name="name">Name of the task. Use null to display "please wait..." message</param>
/// <param name="totalWork">Total amount of work in work units. Use 0 for unknown amount of work.</param>
public void BeginTask(string name, int totalWork, bool allowCancel)
{
if (name == null)
name = "${res:Global.PleaseWait}";
if (totalWork < 0)
totalWork = 0;
lock (lockObject) {
this.allowCancel = allowCancel;
this.totalWork = totalWork;
this.taskName = name;
if (dlg != null && disposed == false) {
dlg.BeginInvoke(new MethodInvoker(UpdateTask));
}
}
}
/// <summary>
/// Resets the task to a generic "please wait" with marquee progress bar.
/// </summary>
public void Done()
{
workDone = 0;
BeginTask(null, 0, false);
}
void UpdateTask()
{
int totalWork = this.totalWork;
dlg.taskLabel.Text = StringParser.Parse(taskName);
if (allowCancel) {
dlg.cancelButton.Visible = true;
dlg.progressBar.Width = dlg.cancelButton.Left - 8 - dlg.progressBar.Left;
} else {
dlg.cancelButton.Visible = false;
dlg.progressBar.Width = dlg.cancelButton.Right - dlg.progressBar.Left;
}
if (totalWork > 0) {
if (dlg.progressBar.Value > totalWork) {
dlg.progressBar.Value = 0;
}
dlg.progressBar.Maximum = totalWork + 1;
dlg.progressBar.Style = ProgressBarStyle.Continuous;
} else {
dlg.progressBar.Style = ProgressBarStyle.Marquee;
}
UpdateProgress();
}
void UpdateProgress()
{
int workDone = this.workDone;
if (workDone < 0) workDone = 0;
if (workDone > dlg.progressBar.Maximum)
workDone = dlg.progressBar.Maximum;
dlg.progressBar.Value = workDone;
}
bool showingDialog;
public bool ShowingDialog {
get { return showingDialog; }
set {
if (showingDialog != value) {
showingDialog = value;
lock (lockObject) {
if (dlg != null && disposed == false) {
if (value) {
dlg.BeginInvoke(new MethodInvoker(dlg.Hide));
} else {
dlg.BeginInvoke(new MethodInvoker(delegate {
Thread.Sleep(100);
if (showingDialog) {
dlg.Show();
}
}));
}
}
}
}
}
}
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;
}
}