/// <summary>
        /// Executes a HistoryFunction in the context of this DocumentWorkspace.
        /// </summary>
        /// <param name="function">The HistoryFunction to execute.</param>
        /// <remarks>
        /// Depending on the HistoryFunction, the currently active tool may be refreshed.
        /// </remarks>
        public HistoryFunctionResult ExecuteFunction(HistoryFunction function)
        {
            HistoryFunctionResult result;

            bool nullTool = false;

            if ((function.ActionFlags & ActionFlags.KeepToolActive) != ActionFlags.KeepToolActive)
            {
                PushNullTool();
                Update();
                nullTool = true;
            }

            try
            {
                using (new WaitCursorChanger(this))
                {
                    HistoryMemento hm = null;
                    string errorText;

                    try
                    {
                        bool cancelled = false;

                        if ((function.ActionFlags & ActionFlags.ReportsProgress) != ActionFlags.ReportsProgress)
                        {
                            hm = function.Execute(this);
                        }
                        else
                        {
                            ProgressDialog pd = new ProgressDialog();
                            bool pdLoaded = false;
                            bool closeAtLoad = false;

                            EventHandler loadCallback =
                                delegate(object sender, EventArgs e)
                                {
                                    pdLoaded = true;

                                    if (closeAtLoad)
                                    {
                                        pd.Close();
                                    }
                                };

                            ProgressEventHandler progressCallback =
                                delegate(object sender, ProgressEventArgs e)
                                {
                                    if (pdLoaded)
                                    {
                                        double newValue = Utility.Clamp(e.Percent, 0.0, 100.0);
                                        pd.Value = newValue;
                                    }
                                };

                            EventHandler<EventArgs<HistoryMemento>> finishedCallback =
                                delegate(object sender, EventArgs<HistoryMemento> e)
                                {
                                    hm = e.Data;

                                    if (pdLoaded)
                                    {
                                        // TODO: fix ProgressDialog's very weird interface
                                        pd.ExternalFinish();
                                        pd.Close();
                                    }
                                    else
                                    {
                                        closeAtLoad = true;
                                    }
                                };

                            EventHandler cancelClickCallback =
                                delegate(object sender, EventArgs e)
                                {
                                    cancelled = true;
                                    function.RequestCancel();
                                    //pd.Cancellable = false;
                                };

                            pd.Text = PdnInfo.GetBareProductName();
                            pd.Description = PdnResources.GetString("ExecuteFunction.ProgressDialog.Description.Text");
                            pd.Load += loadCallback;
                            pd.Cancellable = false; //function.Cancellable;
                            pd.CancelClick += cancelClickCallback;
                            function.Progress += progressCallback;
                            function.BeginExecute(this, this, finishedCallback);
                            pd.ShowDialog(this);
                            pd.Dispose();
                        }

                        if (hm == null && !cancelled)
                        {
                            result = HistoryFunctionResult.SuccessNoOp;
                        }
                        else if (hm == null && cancelled)
                        {
                            result = HistoryFunctionResult.Cancelled;
                        }
                        else
                        {
                            result = HistoryFunctionResult.Success;
                        }

                        errorText = null;
                    }

                    catch (HistoryFunctionNonFatalException hfnfex)
                    {
                        if (hfnfex.InnerException is OutOfMemoryException)
                        {
                            result = HistoryFunctionResult.OutOfMemory;
                        }
                        else
                        {
                            result = HistoryFunctionResult.NonFatalError;
                        }

                        if (hfnfex.LocalizedErrorText != null)
                        {
                            errorText = hfnfex.LocalizedErrorText;
                        }
                        else
                        {
                            if (hfnfex.InnerException is OutOfMemoryException)
                            {
                                errorText = PdnResources.GetString("ExecuteFunction.GenericOutOfMemory");
                            }
                            else
                            {
                                errorText = PdnResources.GetString("ExecuteFunction.GenericError");
                            }
                        }
                    }

                    if (errorText != null)
                    {
                        Utility.ErrorBox(this, errorText);
                    }

                    if (hm != null)
                    {
                        History.PushNewMemento(hm);
                    }
                }
            }

            finally
            {
                if (nullTool)
                {
                    PopNullTool();
                }
            }

            return result;
        }
        protected DialogResult ShowDialog(bool cancellable, bool marqueeProgress, ThreadStart callback)
        {
            this.threadCallback = callback;
            DialogResult dr = DialogResult.Cancel;

            using (this.dialog = new ProgressDialog())
            {
                dialog.Text = dialogTitle;
                dialog.Description = dialogDescription;

                if (marqueeProgress)
                {
                    dialog.PercentTextVisible = false;
                    dialog.MarqueeMode = true;
                }

                if (icon != null)
                {
                    dialog.Icon = icon;
                }

                EventHandler leh = new EventHandler(dialog_Load);
                dialog.Load += leh;
                dialog.Cancellable = cancellable;

                if (cancellable)
                {
                    dialog.CancelClick += new EventHandler(dialog_CancelClick);
                }

                thread = new Thread(new ThreadStart(BackgroundCallback));
                this.Progress = 0;

                if (setStartPos)
                {
                    dialog.Location = new Point(StartPos.X - (dialog.Width / 2), StartPos.Y);;
                    dialog.StartPosition = FormStartPosition.Manual;
                }
                else
                {
                    dialog.StartPosition = FormStartPosition.CenterParent;
                }

                dr = dialog.ShowDialog(owner);
                dialog.Load -= leh;

                if (cancellable)
                {
                    this.cancelled = dialog.Cancelled;
                    dialog.CancelClick -= new EventHandler(dialog_CancelClick);
                }

                if (exception != null)
                {
                    throw new WorkerThreadException("Worker thread threw an exception", exception);
                }
            }

            return dr;
        }