ardupilot/Tools/ArdupilotMegaPlanner/Controls/ProgressReporterDialogue.cs
Michael Oborne 8001515b7e Mission Planner 1.2.1
add enable/disable to mavlinkcheckbox
modify my button to curved
add delay to progress reporter dialog. to ensure correct parent
Fix Mount screen for AP
Fix Hardware screen Text
display roi difrently
modify HIL/Quad Hil
update dataflashlog format (thanks randy)
update mavcmd format for roi
2012-07-30 07:23:42 +08:00

253 lines
9.1 KiB
C#

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace ArdupilotMega.Controls
{
/// <summary>
/// Form that is shown to the user during a background operation
/// </summary>
/// <remarks>
/// Performs operation excplicitely on a threadpool thread due to
/// Mono not playing nice with the BackgroundWorker
/// </remarks>
public partial class ProgressReporterDialogue : Form
{
private Exception workerException;
public ProgressWorkerEventArgs doWorkArgs;
internal int _progress = -1;
internal string _status = "";
public delegate void DoWorkEventHandler(object sender, ProgressWorkerEventArgs e);
// This is the event that will be raised on the BG thread
public event DoWorkEventHandler DoWork;
public ProgressReporterDialogue()
{
InitializeComponent();
doWorkArgs = new ProgressWorkerEventArgs();
this.btnClose.Visible = false;
}
/// <summary>
/// Called at setup - will kick off the background process on a thread pool thread
/// </summary>
public void RunBackgroundOperationAsync()
{
ThreadPool.QueueUserWorkItem(RunBackgroundOperation);
this.ShowDialog();
}
private void RunBackgroundOperation(object o)
{
try
{
Thread.CurrentThread.Name = "ProgressReporterDialogue Background thread";
}
catch { } // ok on windows - fails on mono
// mono fix - ensure the dialog is running
while (this.IsHandleCreated == false)
System.Threading.Thread.Sleep(1);
this.Invoke((MethodInvoker)delegate
{
// if this windows isnt the current active windows, popups inherit the wrong parent.
this.Focus();
Application.DoEvents();
});
try
{
if (this.DoWork != null) this.DoWork(this, doWorkArgs);
}
catch(Exception e)
{
// The background operation thew an exception.
// Examine the work args, if there is an error, then display that and the exception details
// Otherwise display 'Unexpected error' and exception details
timer1.Stop();
ShowDoneWithError(e, doWorkArgs.ErrorMessage);
return;
}
// stop the timer
timer1.Stop();
// run once more to do final message and progressbar
this.Invoke((MethodInvoker)delegate
{
timer1_Tick(null, null);
});
if (doWorkArgs.CancelRequested && doWorkArgs.CancelAcknowledged)
{
ShowDoneCancelled();
return;
}
if (!string.IsNullOrEmpty(doWorkArgs.ErrorMessage))
{
ShowDoneWithError(null, doWorkArgs.ErrorMessage);
return;
}
if (doWorkArgs.CancelRequested)
{
ShowDoneWithError(null, "Operation could not cancel");
return;
}
ShowDone();
}
// Called as a possible last operation of the bg thread that was cancelled
// - Hide progress bar
// - Set label text
private void ShowDoneCancelled()
{
this.Invoke((MethodInvoker)delegate
{
this.progressBar1.Visible = false;
this.lblProgressMessage.Text = "Cancelled";
this.btnClose.Visible = true;
});
}
// Called as a possible last operation of the bg thread
// - Set progress bar to 100%
// - Wait a little bit to allow the Aero progress animatiom to catch up
// - Signal that we can close
private void ShowDone()
{
this.Invoke((MethodInvoker) delegate
{
this.progressBar1.Style = ProgressBarStyle.Continuous;
this.progressBar1.Value = 100;
this.btnCancel.Visible = false;
this.btnClose.Visible = false;
});
Thread.Sleep(1000);
this.BeginInvoke((MethodInvoker) this.Close);
}
// Called as a possible last operation of the bg thread
// There was an exception on the worker event, so:
// - Show the error message supplied by the worker, or a default message
// - Make visible the error icon
// - Make the progress bar invisible to make room for:
// - Add the exception details and stack trace in an expansion panel
// - Change the Cancel button to 'Close', so that the user can look at the exception message a bit
private void ShowDoneWithError(Exception exception, string doWorkArgs)
{
var errMessage = doWorkArgs ?? "There was an unexpected error";
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker) delegate
{
this.Text = "Error";
this.lblProgressMessage.Left = 65;
this.lblProgressMessage.Text = errMessage;
this.imgWarning.Visible = true;
this.progressBar1.Visible = false;
this.btnCancel.Visible = false;
this.btnClose.Visible = true;
this.linkLabel1.Visible = exception != null;
this.workerException = exception;
});
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
// User wants to cancel -
// * Set the text of the Cancel button to 'Close'
// * Set the cancel button to disabled, will enable it and let the user dismiss the dialogue
// when the async operation is complete
// * Set the status text to 'Cancelling...'
// * Set the progress bar to marquee, we don't know how long the worker will take to cancel
// * Signal the worker.
this.btnCancel.Visible = false;
this.lblProgressMessage.Text = "Cancelling...";
this.progressBar1.Style = ProgressBarStyle.Marquee;
doWorkArgs.CancelRequested = true;
}
private void btn_Close_Click(object sender, EventArgs e)
{
// we have already cancelled, and this now a 'close' button
this.Close();
}
/// <summary>
/// Called from the BG thread
/// </summary>
/// <param name="progress">progress in %, -1 means inderteminate</param>
/// <param name="status"></param>
public void UpdateProgressAndStatus(int progress, string status)
{
// we don't let the worker update progress when a cancel has been
// requested, unless the cancel has been acknowleged, so we know that
// this progress update pertains to the cancellation cleanup
if (doWorkArgs.CancelRequested && !doWorkArgs.CancelAcknowledged)
return;
_progress = progress;
_status = status;
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var message = this.workerException.Message
+ Environment.NewLine + Environment.NewLine
+ this.workerException.StackTrace;
CustomMessageBox.Show(message,"Exception Details",MessageBoxButtons.OK,MessageBoxIcon.Information);
}
/// <summary>
/// prevent using invokes on main update status call "UpdateProgressAndStatus", as this is slow on mono
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timer1_Tick(object sender, EventArgs e)
{
// this value is being currupted - not thread safe
int pgv = _progress;
lblProgressMessage.Text = _status;
if (pgv == -1)
{
this.progressBar1.Style = ProgressBarStyle.Marquee;
}
else
{
this.progressBar1.Style = ProgressBarStyle.Continuous;
try
{
this.progressBar1.Value = pgv;
}
catch { } // clean fail. and ignore, chances are we will hit this again in the next 100 ms
}
}
}
public class ProgressWorkerEventArgs : EventArgs
{
public string ErrorMessage;
public volatile bool CancelRequested;
public volatile bool CancelAcknowledged;
}
}