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

Revision 2141, 23.5 KB checked in by lowjoel, 4 years ago (diff)

Final fix to r2133, r2129, r2117, r1969 to fix #271.

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