source: branches/eraser6/pluginsRewrite/Eraser/SchedulerPanel.cs @ 2485

Revision 2485, 20.8 KB checked in by lowjoel, 3 years ago (diff)

Replace the UIText property with ToString?(). Fix the resulting compile errors, too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Drawing;
26using System.Text;
27using System.Windows.Forms;
28
29using System.Globalization;
30using System.IO;
31using System.ComponentModel;
32
33using Eraser.Manager;
34using Eraser.Util;
35using Eraser.Plugins;
36using Eraser.Plugins.ExtensionPoints;
37using Microsoft.Samples;
38
39using ProgressChangedEventArgs = Eraser.Plugins.ProgressChangedEventArgs;
40
41namespace Eraser
42{
43    internal partial class SchedulerPanel : Eraser.BasePanel
44    {
45        public SchedulerPanel()
46        {
47            InitializeComponent();
48            Theming.ApplyTheme(schedulerDefaultMenu);
49            if (!IsHandleCreated)
50                CreateHandle();
51
52            //Populate the scheduler list-view with the current task list
53            ExecutorTasksCollection tasks = Program.eraserClient.Tasks;
54            foreach (Task task in tasks)
55                CreateTask(task);
56
57            //Hook the event machinery to our class. Handle the task Added and Removed
58            //events.
59            Program.eraserClient.TaskAdded += TaskAdded;
60            Program.eraserClient.TaskDeleted += TaskDeleted;
61        }
62
63        #region List-View Task Management
64        private void CreateTask(Task task)
65        {
66            //Add the item to the list view
67            ListViewItem item = scheduler.Items.Add(task.ToString());
68            item.SubItems.Add(string.Empty);
69            item.SubItems.Add(string.Empty);
70
71            //Set the tag of the item so we know which task on the list-view
72            //corresponds to the physical task object.
73            item.Tag = task;
74
75            //Add our event handlers to the task
76            task.TaskStarted += TaskStarted;
77            task.ProgressChanged += TaskProgressChanged;
78            task.TaskFinished += TaskFinished;
79
80            //Show the fields on the list view
81            UpdateTask(item);
82
83            //If the task is set to Run Immediately, then show that status.
84            if (task.Schedule == Schedule.RunNow)
85                item.SubItems[1].Text = S._("Queued for execution");
86        }
87
88        private void UpdateTask(ListViewItem item)
89        {
90            //Get the task object
91            Task task = (Task)item.Tag;
92
93            //Set the task name
94            item.Text = task.ToString();
95
96            //Set the next run time of the task
97            if (task.Queued)
98                item.SubItems[1].Text = S._("Queued for execution");
99            else if (task.Executing)
100                TaskStarted(task, new TaskEventArgs(task));
101            else if (task.Schedule is RecurringSchedule)
102                item.SubItems[1].Text = ((task.Schedule as RecurringSchedule).NextRun.
103                    ToString("f", CultureInfo.CurrentCulture));
104            else if (task.Schedule == Schedule.RunManually || task.Schedule == Schedule.RunNow)
105                item.SubItems[1].Text = S._("Not queued");
106            else
107                item.SubItems[1].Text = task.Schedule.UIText;
108
109            //Set the group of the task.
110            CategorizeTask(task, item);
111        }
112
113        private void CategorizeTask(Task task)
114        {
115            CategorizeTask(task, GetTaskItem(task));
116        }
117
118        private void CategorizeTask(Task task, ListViewItem item)
119        {
120            if (task.Schedule == Schedule.RunNow || task.Schedule == Schedule.RunManually)
121                item.Group = scheduler.Groups["manual"];
122            else if (task.Schedule == Schedule.RunOnRestart)
123                item.Group = scheduler.Groups["restart"];
124            else
125                item.Group = scheduler.Groups["recurring"];
126        }
127        #endregion
128
129        #region Task Event handlers
130        /// <summary>
131        /// Handles the Task Added event.
132        /// </summary>
133        private void TaskAdded(object sender, TaskEventArgs e)
134        {
135            if (InvokeRequired)
136            {
137                Invoke((EventHandler<TaskEventArgs>)TaskAdded, sender, e);
138                return;
139            }
140
141            //Display a balloon notification if the parent frame has been minimised.
142            MainForm parent = (MainForm)FindForm();
143            if (parent != null && (parent.WindowState == FormWindowState.Minimized || !parent.Visible))
144            {
145                parent.ShowNotificationBalloon(S._("New task added"), S._("{0} " +
146                    "has just been added to the list of tasks.", e.Task.ToString()),
147                    ToolTipIcon.Info);
148            }
149
150            CreateTask(e.Task);
151        }
152
153        private void DeleteSelectedTasks()
154        {
155            if (MessageBox.Show(this, S._("Are you sure you want to delete the selected tasks?"),
156                    S._("Eraser"), MessageBoxButtons.YesNo, MessageBoxIcon.Question,
157                    MessageBoxDefaultButton.Button1, Localisation.IsRightToLeft(this) ?
158                        MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0
159                ) != DialogResult.Yes)
160            {
161                return;
162            }
163
164            foreach (ListViewItem item in scheduler.SelectedItems)
165            {
166                Task task = (Task)item.Tag;
167                if (!task.Executing)
168                    Program.eraserClient.Tasks.Remove(task);
169            }
170        }
171
172        /// <summary>
173        /// Handles the task deleted event.
174        /// </summary>
175        private void TaskDeleted(object sender, TaskEventArgs e)
176        {
177            if (InvokeRequired)
178            {
179                Invoke((EventHandler<TaskEventArgs>)TaskDeleted, sender, e);
180                return;
181            }
182
183            foreach (ListViewItem item in scheduler.Items)
184                if (((Task)item.Tag) == e.Task)
185                {
186                    scheduler.Items.Remove(item);
187                    break;
188                }
189
190            PositionProgressBar();
191        }
192
193        /// <summary>
194        /// Handles the task start event.
195        /// </summary>
196        /// <param name="e">The task event object.</param>
197        void TaskStarted(object sender, EventArgs e)
198        {
199            if (InvokeRequired)
200            {
201                Invoke((EventHandler)TaskStarted, sender, e);
202                return;
203            }
204
205            //Get the list view item
206            Task task = (Task)sender;
207            ListViewItem item = GetTaskItem(task);
208
209            //Update the status.
210            item.SubItems[1].Text = S._("Running...");
211
212            //Show the progress bar
213            schedulerProgress.Tag = item;
214            schedulerProgress.Visible = true;
215            schedulerProgress.Value = 0;
216            PositionProgressBar();
217        }
218
219        /// <summary>
220        /// Handles the progress event by the task.
221        /// </summary>
222        void TaskProgressChanged(object sender, ProgressChangedEventArgs e)
223        {
224            //Make sure we handle the event in the main thread as this requires
225            //GUI calls.
226            if (InvokeRequired)
227            {
228                Invoke((EventHandler<ProgressChangedEventArgs>)TaskProgressChanged, sender, e);
229                return;
230            }
231
232            //Update the progress bar
233            IErasureTarget target = (IErasureTarget)sender;
234            SteppedProgressManager progress = target.Task.Progress;
235            schedulerProgress.Style = progress.ProgressIndeterminate ?
236                ProgressBarStyle.Marquee : ProgressBarStyle.Continuous;
237           
238            if (!progress.ProgressIndeterminate)
239                schedulerProgress.Value = (int)(progress.Progress * 1000.0);
240        }
241
242        /// <summary>
243        /// Handles the task completion event.
244        /// </summary>
245        void TaskFinished(object sender, EventArgs e)
246        {
247            if (InvokeRequired)
248            {
249                Invoke((EventHandler)TaskFinished, sender, e);
250                return;
251            }
252
253            //Get the list view item
254            Task task = (Task)sender;
255            ListViewItem item = GetTaskItem(task);
256            if (item == null)
257                return;
258
259            //Hide the progress bar
260            if (schedulerProgress.Tag != null && schedulerProgress.Tag == item)
261            {
262                schedulerProgress.Tag = null;
263                schedulerProgress.Visible = false;
264            }
265
266            //Get the exit status of the task.
267            LogLevel highestLevel = task.Log.Last().Highest;
268
269            //Show a balloon to inform the user
270            MainForm parent = (MainForm)FindForm();
271            if (parent.WindowState == FormWindowState.Minimized || !parent.Visible)
272            {
273                string message = null;
274                ToolTipIcon icon = ToolTipIcon.None;
275
276                switch (highestLevel)
277                {
278                    case LogLevel.Warning:
279                        message = S._("The task {0} has completed with warnings.", task);
280                        icon = ToolTipIcon.Warning;
281                        break;
282                    case LogLevel.Error:
283                        message = S._("The task {0} has completed with errors.", task);
284                        icon = ToolTipIcon.Error;
285                        break;
286                    case LogLevel.Fatal:
287                        message = S._("The task {0} did not complete.", task);
288                        icon = ToolTipIcon.Error;
289                        break;
290                    default:
291                        message = S._("The task {0} has completed.", task);
292                        icon = ToolTipIcon.Info;
293                        break;
294                }
295
296                parent.ShowNotificationBalloon(S._("Task completed"), message,
297                    icon);
298            }
299
300            //If the user requested us to remove completed one-time tasks, do so.
301            if (EraserSettings.Get().ClearCompletedTasks &&
302                (task.Schedule == Schedule.RunNow) && highestLevel < LogLevel.Warning)
303            {
304                Program.eraserClient.Tasks.Remove(task);
305            }
306
307            //Otherwise update the UI
308            else
309            {
310                switch (highestLevel)
311                {
312                    case LogLevel.Warning:
313                        item.SubItems[2].Text = S._("Completed with warnings");
314                        break;
315                    case LogLevel.Error:
316                        item.SubItems[2].Text = S._("Completed with errors");
317                        break;
318                    case LogLevel.Fatal:
319                        item.SubItems[2].Text = S._("Not completed");
320                        break;
321                    default:
322                        item.SubItems[2].Text = S._("Completed");
323                        break;
324                }
325
326                //Recategorize the task. Do not assume the task has maintained the
327                //category since run-on-restart tasks will be changed to immediately
328                //run tasks.
329                CategorizeTask(task, item);
330
331                //Update the status of the task.
332                UpdateTask(item);
333            }
334        }
335        #endregion
336
337        #region List-View Event handlers
338        /// <summary>
339        /// Occurs when the user presses a key on the list view.
340        /// </summary>
341        /// <param name="sender">The list view which triggered the event.</param>
342        /// <param name="e">Event argument.</param>
343        private void scheduler_KeyDown(object sender, KeyEventArgs e)
344        {
345            if (e.KeyCode == Keys.Delete)
346                DeleteSelectedTasks();
347        }
348
349        /// <summary>
350        /// Occurs when the user double-clicks a scheduler item. This will result
351        /// in the log viewer being called, or the progress dialog to be displayed.
352        /// </summary>
353        /// <param name="sender">The list view which triggered the event.</param>
354        /// <param name="e">Event argument.</param>
355        private void scheduler_ItemActivate(object sender, EventArgs e)
356        {
357            if (scheduler.SelectedItems.Count == 0)
358                return;
359
360            ListViewItem item = scheduler.SelectedItems[0];
361            if (((Task)item.Tag).Executing)
362                using (ProgressForm form = new ProgressForm((Task)item.Tag))
363                    form.ShowDialog();
364            else
365                editTaskToolStripMenuItem_Click(sender, e);
366        }
367
368        /// <summary>
369        /// Occurs when the user drags a file over the scheduler
370        /// </summary>
371        private void scheduler_DragEnter(object sender, DragEventArgs e)
372        {
373            //Get the list of files.
374            bool recycleBin = false;
375            List<string> paths = new List<string>(TaskDragDropHelper.GetFiles(e, out recycleBin));
376
377            //We also need to determine if we are importing task lists.
378            bool isTaskList = !recycleBin;
379
380            for (int i = 0; i < paths.Count; ++i)
381            {
382                //Does this item exclude a task list import?
383                if (isTaskList && Path.GetExtension(paths[i]) != ".ersx")
384                    isTaskList = false;
385
386                //Just use the file name/directory name.
387                paths[i] = Path.GetFileName(paths[i]);
388            }
389
390            //Add the recycle bin if it was dropped.
391            if (recycleBin)
392                paths.Add(S._("Recycle Bin"));
393
394            string description = null;
395            if (paths.Count == 0)
396            {
397                e.Effect = DragDropEffects.None;
398                description = S._("Cannot erase the selected items");
399            }
400            else if (isTaskList)
401            {
402                e.Effect = DragDropEffects.Copy;
403                description = S._("Import tasks from {0}");
404            }
405            else
406            {
407                e.Effect = DragDropEffects.Move;
408                description = S._("Erase {0}");
409            }
410
411            TaskDragDropHelper.OnDragEnter(this, e, description, paths);
412        }
413
414        private void scheduler_DragLeave(object sender, EventArgs e)
415        {
416            DropTargetHelper.DragLeave(this);
417        }
418
419        private void scheduler_DragOver(object sender, DragEventArgs e)
420        {
421            DropTargetHelper.DragOver(new Point(e.X, e.Y), e.Effect);
422        }
423
424        /// <summary>
425        /// Occurs when the user drops a file into the scheduler.
426        /// </summary>
427        private void scheduler_DragDrop(object sender, DragEventArgs e)
428        {
429            TaskDragDropHelper.OnDrop(e);
430            if (e.Effect == DragDropEffects.None)
431                return;
432
433            //Determine our action.
434            bool recycleBin = false;
435            List<string> paths = new List<string>(TaskDragDropHelper.GetFiles(e, out recycleBin));
436            bool isTaskList = !recycleBin;
437
438            foreach (string path in paths)
439            {
440                //Does this item exclude a task list import?
441                if (isTaskList && Path.GetExtension(path) != ".ersx")
442                {
443                    isTaskList = false;
444                    break;
445                }
446            }
447
448            if (isTaskList)
449            {
450                foreach (string file in paths)
451                    using (FileStream stream = new FileStream(file, FileMode.Open,
452                        FileAccess.Read, FileShare.Read))
453                    {
454                        try
455                        {
456                            Program.eraserClient.Tasks.LoadFromStream(stream);
457                        }
458                        catch (InvalidDataException ex)
459                        {
460                            MessageBox.Show(S._("Could not import task list from {0}. The " +
461                                "error returned was: {1}", file, ex.Message), S._("Eraser"),
462                                MessageBoxButtons.OK, MessageBoxIcon.Error,
463                                MessageBoxDefaultButton.Button1,
464                                Localisation.IsRightToLeft(this) ?
465                                    MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
466                        }
467                    }
468            }
469            else
470            {
471                //Create a task with the default settings
472                Task task = new Task();
473                foreach (IErasureTarget target in TaskDragDropHelper.GetTargets(e))
474                    task.Targets.Add(target);
475
476                //If the task has no targets, we should not go on.
477                if (task.Targets.Count == 0)
478                    return;
479
480                //Schedule the task dialog to be shown (to get to the event loop so that
481                //ComCtl32.dll v6 is used.)
482                BeginInvoke((Action<Task>)scheduler_DragDropConfirm, task);
483            }
484        }
485
486        /// <summary>
487        /// Called when a set of files are dropped into Eraser and to let the user
488        /// decide what to do with the collection.
489        /// </summary>
490        /// <param name="task">The task which requires confirmation.</param>
491        private void scheduler_DragDropConfirm(Task task)
492        {
493            //Add the task, asking the user for his intent.
494            DialogResult action = DialogResult.No;
495            if (TaskDialog.IsAvailableOnThisOS)
496            {
497                TaskDialog dialog = new TaskDialog();
498                dialog.WindowTitle = S._("Eraser");
499                dialog.MainIcon = TaskDialogIcon.Information;
500                dialog.MainInstruction = S._("You have dropped a set of files and folders into Eraser. What do you want to do with them?");
501                dialog.AllowDialogCancellation = true;
502                dialog.Buttons = new TaskDialogButton[] {
503                    new TaskDialogButton((int)DialogResult.Yes, S._("Erase the selected items\nSchedules the selected items for immediate erasure.")),
504                    new TaskDialogButton((int)DialogResult.OK, S._("Create a new Task\nA task will be created containing the selected items.")),
505                    new TaskDialogButton((int)DialogResult.No, S._("Cancel the drag-and-drop operation"))
506                };
507                dialog.RightToLeftLayout = Localisation.IsRightToLeft(this);
508                dialog.UseCommandLinks = true;
509                action = (DialogResult)dialog.Show(this);
510            }
511            else
512            {
513                action = MessageBox.Show(S._("Are you sure you wish to erase the selected "
514                    + "items?"), S._("Eraser"), MessageBoxButtons.YesNo,
515                    MessageBoxIcon.Question, MessageBoxDefaultButton.Button2,
516                    Localisation.IsRightToLeft(this) ?
517                        MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
518            }
519
520            switch (action)
521            {
522                case DialogResult.OK:
523                    task.Schedule = Schedule.RunManually;
524                    goto case DialogResult.Yes;
525
526                case DialogResult.Yes:
527                    Program.eraserClient.Tasks.Add(task);
528                    break;
529            }
530        }
531
532        /// <summary>
533        /// Occurs when the user right-clicks the list view.
534        /// </summary>
535        /// <param name="sender">The list view which generated this event.</param>
536        /// <param name="e">Event argument.</param>
537        private void schedulerMenu_Opening(object sender, CancelEventArgs e)
538        {
539            //If nothing's selected, show the Scheduler menu which just allows users to
540            //create new tasks (like from the toolbar)
541            if (scheduler.SelectedItems.Count == 0)
542            {
543                schedulerDefaultMenu.Show(schedulerMenu.Left, schedulerMenu.Top);
544                e.Cancel = true;
545                return;
546            }
547
548            bool aTaskNotQueued = false;
549            bool aTaskExecuting = false;
550            foreach (ListViewItem item in scheduler.SelectedItems)
551            {
552                Task task = (Task)item.Tag;
553                aTaskNotQueued = aTaskNotQueued || (!task.Queued && !task.Executing);
554                aTaskExecuting = aTaskExecuting || task.Executing;
555            }
556
557            runNowToolStripMenuItem.Enabled = aTaskNotQueued;
558            cancelTaskToolStripMenuItem.Enabled = aTaskExecuting;
559
560            editTaskToolStripMenuItem.Enabled = scheduler.SelectedItems.Count == 1 &&
561                !((Task)scheduler.SelectedItems[0].Tag).Executing &&
562                !((Task)scheduler.SelectedItems[0].Tag).Queued;
563            deleteTaskToolStripMenuItem.Enabled = !aTaskExecuting;
564        }
565
566        /// <summary>
567        /// Occurs when the user selects the New Task context menu item.
568        /// </summary>
569        /// <param name="sender">The menu which generated this event.</param>
570        /// <param name="e">Event argument.</param>
571        private void newTaskToolStripMenuItem_Click(object sender, EventArgs e)
572        {
573            using (TaskPropertiesForm form = new TaskPropertiesForm())
574            {
575                if (form.ShowDialog() == DialogResult.OK)
576                {
577                    Task task = form.Task;
578                    Program.eraserClient.Tasks.Add(task);
579                }
580            }
581        }
582
583        /// <summary>
584        /// Occurs whent the user selects the Run Now context menu item.
585        /// </summary>
586        /// <param name="sender">The menu which generated this event.</param>
587        /// <param name="e">Event argument.</param>
588        private void runNowToolStripMenuItem_Click(object sender, EventArgs e)
589        {
590            foreach (ListViewItem item in scheduler.SelectedItems)
591            {
592                //Queue the task
593                Task task = (Task)item.Tag;
594                if (!task.Executing && !task.Queued)
595                {
596                    Program.eraserClient.QueueTask(task);
597
598                    //Update the UI
599                    item.SubItems[1].Text = S._("Queued for execution");
600                }
601            }
602        }
603
604        /// <summary>
605        /// Occurs whent the user selects the Cancel Task context menu item.
606        /// </summary>
607        /// <param name="sender">The menu which generated this event.</param>
608        /// <param name="e">Event argument.</param>
609        private void cancelTaskToolStripMenuItem_Click(object sender, EventArgs e)
610        {
611            foreach (ListViewItem item in scheduler.SelectedItems)
612            {
613                //Queue the task
614                Task task = (Task)item.Tag;
615                if (task.Executing || task.Queued)
616                {
617                    task.Cancel();
618
619                    //Update the UI
620                    item.SubItems[1].Text = string.Empty;
621                }
622            }
623        }
624
625        /// <summary>
626        /// Occurs when the user selects the View Task Log context menu item.
627        /// </summary>
628        /// <param name="sender">The menu item which generated this event.</param>
629        /// <param name="e">Event argument.</param>
630        private void viewTaskLogToolStripMenuItem_Click(object sender, EventArgs e)
631        {
632            if (scheduler.SelectedItems.Count != 1)
633                return;
634
635            ListViewItem item = scheduler.SelectedItems[0];
636            using (LogForm form = new LogForm((Task)item.Tag))
637                form.ShowDialog();
638        }
639
640        /// <summary>
641        /// Occurs when the user selects the Edit Task context menu item.
642        /// </summary>
643        /// <param name="sender">The menu item which generated this event.</param>
644        /// <param name="e">Event argument.</param>
645        private void editTaskToolStripMenuItem_Click(object sender, EventArgs e)
646        {
647            if (scheduler.SelectedItems.Count != 1 ||
648                ((Task)scheduler.SelectedItems[0].Tag).Executing ||
649                ((Task)scheduler.SelectedItems[0].Tag).Queued)
650            {
651                return;
652            }
653
654            //Make sure that the task is not being executed, or else. This can
655            //be done in the Client library, but there will be no effect on the
656            //currently running task.
657            ListViewItem item = scheduler.SelectedItems[0];
658            Task task = (Task)item.Tag;
659            if (task.Executing)
660                return;
661
662            //Edit the task.
663            using (TaskPropertiesForm form = new TaskPropertiesForm())
664            {
665                form.Task = task;
666                if (form.ShowDialog() == DialogResult.OK)
667                {
668                    task = form.Task;
669
670                    //Update the list view
671                    UpdateTask(item);
672                }
673            }
674        }
675
676        /// <summary>
677        /// Occurs when the user selects the Delete Task context menu item.
678        /// </summary>
679        /// <param name="sender">The menu item which generated this event.</param>
680        /// <param name="e">Event argument.</param>
681        private void deleteTaskToolStripMenuItem_Click(object sender, EventArgs e)
682        {
683            DeleteSelectedTasks();
684        }
685        #endregion
686
687        #region Item management
688        /// <summary>
689        /// Retrieves the ListViewItem for the given task.
690        /// </summary>
691        /// <param name="task">The task object whose list view entry is being sought.</param>
692        /// <returns>A ListViewItem for the given task object.</returns>
693        private ListViewItem GetTaskItem(Task task)
694        {
695            foreach (ListViewItem item in scheduler.Items)
696                if (item.Tag == task)
697                    return item;
698
699            return null;
700        }
701
702        /// <summary>
703        /// Maintains the position of the progress bar.
704        /// </summary>
705        private void PositionProgressBar()
706        {
707            if (schedulerProgress.Tag == null)
708                return;
709
710            Rectangle rect = ((ListViewItem)schedulerProgress.Tag).SubItems[2].Bounds;
711            rect.Offset(2, 2);
712            schedulerProgress.Location = rect.Location;
713            schedulerProgress.Size = rect.Size;
714        }
715
716        private void scheduler_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
717        {
718            e.DrawDefault = true;
719            if (schedulerProgress.Tag != null)
720                PositionProgressBar();
721        }
722
723        private void scheduler_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
724        {
725            e.DrawDefault = true;
726        }
727        #endregion
728    }
729}
Note: See TracBrowser for help on using the repository browser.