source: trunk/eraser/Eraser/SchedulerPanel.cs @ 2275

Revision 2275, 23.8 KB checked in by lowjoel, 4 years ago (diff)

Fixed crash at task finish (error introduced in r2268)

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