source: trunk/eraser6/Eraser/SchedulerPanel.cs @ 1243

Revision 1243, 19.1 KB checked in by lowjoel, 5 years ago (diff)

Implemented the delete key as suggested by Xanashi. Fixes #238.

  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 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.ComponentModel;
25using System.Data;
26using System.Drawing;
27using System.Text;
28using System.Windows.Forms;
29
30using Eraser.Manager;
31using Eraser.Util;
32using System.Globalization;
33using System.Runtime.InteropServices;
34using System.Diagnostics;
35using System.IO;
36using System.Runtime.Serialization;
37
38namespace Eraser
39{
40    internal partial class SchedulerPanel : Eraser.BasePanel
41    {
42        public SchedulerPanel()
43        {
44            InitializeComponent();
45            UXThemeApi.UpdateControlTheme(this);
46            UXThemeApi.UpdateControlTheme(schedulerDefaultMenu);
47
48            //Populate the scheduler list-view with the current task list
49            ExecutorTasksCollection tasks = Program.eraserClient.Tasks;
50            foreach (Task task in tasks)
51                DisplayTask(task);
52
53            //Hook the event machinery to our class. Handle the task Added and Removed
54            //events.
55            Program.eraserClient.TaskAdded += TaskAdded;
56            Program.eraserClient.TaskDeleted += TaskDeleted;
57        }
58
59        private void DisplayTask(Task task)
60        {
61            //Add the item to the list view
62            ListViewItem item = scheduler.Items.Add(task.UIText);
63            item.SubItems.Add(string.Empty);
64            item.SubItems.Add(string.Empty);
65
66            //Set the tag of the item so we know which task on the LV corresponds
67            //to the physical task object.
68            item.Tag = task;
69
70            //Add our event handlers to the task
71            task.TaskStarted += task_TaskStarted;
72            task.ProgressChanged += task_ProgressChanged;
73            task.TaskFinished += task_TaskFinished;
74
75            //Show the fields on the list view
76            UpdateTask(item);
77        }
78
79        private void UpdateTask(ListViewItem item)
80        {
81            //Get the task object
82            Task task = (Task)item.Tag;
83
84            //Set the task name
85            item.Text = task.UIText;
86
87            //Set the next run time of the task
88            if (task.Queued)
89            {
90                item.SubItems[1].Text = S._("Queued for execution");
91                item.SubItems[2].Text = string.Empty;
92            }
93            else if (task.Schedule is RecurringSchedule)
94                item.SubItems[1].Text = ((task.Schedule as RecurringSchedule).NextRun.
95                    ToString("F", CultureInfo.CurrentCulture));
96            else if (task.Schedule == Schedule.RunNow || task.Schedule == Schedule.RunManually)
97                item.SubItems[1].Text = S._("Not queued");
98            else
99                item.SubItems[1].Text = task.Schedule.UIText;
100
101            //Set the group of the task.
102            CategorizeTask(task, item);
103        }
104
105        private void CategorizeTask(Task task)
106        {
107            CategorizeTask(task, GetTaskItem(task));
108        }
109
110        private void CategorizeTask(Task task, ListViewItem item)
111        {
112            if (task.Schedule == Schedule.RunNow || task.Schedule == Schedule.RunManually)
113                item.Group = scheduler.Groups["manual"];
114            else if (task.Schedule == Schedule.RunOnRestart)
115                item.Group = scheduler.Groups["restart"];
116            else
117                item.Group = scheduler.Groups["recurring"];
118        }
119
120        /// <summary>
121        /// Handles the Task Added event.
122        /// </summary>
123        private void TaskAdded(object sender, TaskEventArgs e)
124        {
125            if (InvokeRequired)
126            {
127                Invoke(new EventHandler<TaskEventArgs>(TaskAdded), sender, e);
128                return;
129            }
130
131            //Display a balloon notification if the parent frame has been minimised.
132            MainForm parent = (MainForm)FindForm();
133            if (parent != null && (parent.WindowState == FormWindowState.Minimized || !parent.Visible))
134            {
135                parent.ShowNotificationBalloon(S._("New task added"), S._("{0} " +
136                    "has just been added to the list of tasks.", e.Task.UIText),
137                    ToolTipIcon.Info);
138            }
139
140            DisplayTask(e.Task);
141        }
142
143        private void DeleteSelectedTasks()
144        {
145            if (MessageBox.Show(this, S._("Are you sure you want to delete the selected tasks?"),
146                   S._("Eraser"), MessageBoxButtons.YesNo, MessageBoxIcon.Question,
147                   MessageBoxDefaultButton.Button1,
148                   S.IsRightToLeft(this) ? MessageBoxOptions.RtlReading : 0) != DialogResult.Yes)
149            {
150                return;
151            }
152
153            foreach (ListViewItem item in scheduler.SelectedItems)
154            {
155                Task task = (Task)item.Tag;
156                if (!task.Executing)
157                    Program.eraserClient.Tasks.Remove(task);
158            }
159        }
160
161        /// <summary>
162        /// Handles the task deleted event.
163        /// </summary>
164        private void TaskDeleted(object sender, TaskEventArgs e)
165        {
166            if (InvokeRequired)
167            {
168                Invoke(new EventHandler<TaskEventArgs>(TaskDeleted), sender, e);
169                return;
170            }
171
172            foreach (ListViewItem item in scheduler.Items)
173                if (((Task)item.Tag) == e.Task)
174                {
175                    scheduler.Items.Remove(item);
176                    break;
177                }
178
179            PositionProgressBar();
180        }
181
182        /// <summary>
183        /// Handles the task start event.
184        /// </summary>
185        /// <param name="e">The task event object.</param>
186        void task_TaskStarted(object sender, TaskEventArgs e)
187        {
188            if (scheduler.InvokeRequired)
189            {
190                Invoke(new EventHandler<TaskEventArgs>(task_TaskStarted), sender, e);
191                return;
192            }
193
194            //Get the list view item
195            ListViewItem item = GetTaskItem(e.Task);
196
197            //Update the status.
198            item.SubItems[1].Text = S._("Running...");
199
200            //Show the progress bar
201            schedulerProgress.Tag = item;
202            schedulerProgress.Visible = true;
203            schedulerProgress.Value = 0;
204            PositionProgressBar();
205        }
206
207        /// <summary>
208        /// Handles the progress event by the task.
209        /// </summary>
210        void task_ProgressChanged(object sender, TaskProgressEventArgs e)
211        {
212            //Make sure we handle the event in the main thread as this requires
213            //GUI calls.
214            if (scheduler.InvokeRequired)
215            {
216                Invoke(new EventHandler<TaskProgressEventArgs>(task_ProgressChanged), sender, e);
217                return;
218            }
219
220            //Update the progress bar
221            schedulerProgress.Value = (int)(e.OverallProgress * 1000.0);
222        }
223
224        /// <summary>
225        /// Handles the task completion event.
226        /// </summary>
227        void task_TaskFinished(object sender, TaskEventArgs e)
228        {
229            if (InvokeRequired)
230            {
231                Invoke(new EventHandler<TaskEventArgs>(task_TaskFinished), sender, e);
232                return;
233            }
234
235            //Get the list view item
236            ListViewItem item = GetTaskItem(e.Task);
237            if (item == null)
238                return;
239
240            //Hide the progress bar
241            if (schedulerProgress.Tag != null && schedulerProgress.Tag == item)
242            {
243                schedulerProgress.Tag = null;
244                schedulerProgress.Visible = false;
245            }
246
247            //Get the exit status of the task.
248            LogLevel highestLevel = LogLevel.Information;
249            LogEntryCollection logs = e.Task.Log.LastSessionEntries;
250            foreach (LogEntry log in logs)
251                if (log.Level > highestLevel)
252                    highestLevel = log.Level;
253
254            //Show a balloon to inform the user
255            MainForm parent = (MainForm)FindForm();
256            if (parent != null && parent.WindowState == FormWindowState.Minimized || !parent.Visible)
257            {
258                string message = null;
259                ToolTipIcon icon = ToolTipIcon.None;
260
261                switch (highestLevel)
262                {
263                    case LogLevel.Warning:
264                        message = S._("The task {0} has completed with warnings.", e.Task.UIText);
265                        icon = ToolTipIcon.Warning;
266                        break;
267                    case LogLevel.Error:
268                        message = S._("The task {0} has completed with errors.", e.Task.UIText);
269                        icon = ToolTipIcon.Error;
270                        break;
271                    case LogLevel.Fatal:
272                        message = S._("The task {0} did not complete.", e.Task.UIText);
273                        icon = ToolTipIcon.Error;
274                        break;
275                    default:
276                        message = S._("The task {0} has completed.", e.Task.UIText);
277                        icon = ToolTipIcon.Info;
278                        break;
279                }
280
281                parent.ShowNotificationBalloon(S._("Task executed"), message,
282                    icon);
283            }
284
285            //If the user requested us to remove completed one-time tasks, do so.
286            if (EraserSettings.Get().ClearCompletedTasks &&
287                (e.Task.Schedule == Schedule.RunNow) && highestLevel < LogLevel.Warning)
288            {
289                Program.eraserClient.Tasks.Remove(e.Task);
290            }
291
292            //Otherwise update the UI
293            else
294            {
295                switch (highestLevel)
296                {
297                    case LogLevel.Warning:
298                        item.SubItems[2].Text = S._("Completed with warnings");
299                        break;
300                    case LogLevel.Error:
301                        item.SubItems[2].Text = S._("Completed with errors");
302                        break;
303                    case LogLevel.Fatal:
304                        item.SubItems[2].Text = S._("Not completed");
305                        break;
306                    default:
307                        item.SubItems[2].Text = S._("Completed");
308                        break;
309                }
310
311                //Recategorize the task. Do not assume the task has maintained the
312                //category since run-on-restart tasks will be changed to immediately
313                //run tasks.
314                CategorizeTask(e.Task, item);
315
316                //Update the status of the task.
317                UpdateTask(item);
318            }
319        }
320
321        /// <summary>
322        /// Occurs when the user presses a key on the list view.
323        /// </summary>
324        /// <param name="sender">The list view which triggered the event.</param>
325        /// <param name="e">Event argument.</param>
326        private void scheduler_KeyDown(object sender, KeyEventArgs e)
327        {
328            if (e.KeyCode == Keys.Delete)
329                DeleteSelectedTasks();
330        }
331
332        /// <summary>
333        /// Occurs when the user double-clicks a scheduler item. This will result
334        /// in the log viewer being called, or the progress dialog to be displayed.
335        /// </summary>
336        /// <param name="sender">The list view which triggered the event.</param>
337        /// <param name="e">Event argument.</param>
338        private void scheduler_ItemActivate(object sender, EventArgs e)
339        {
340            if (scheduler.SelectedItems.Count == 0)
341                return;
342
343            ListViewItem item = scheduler.SelectedItems[0];
344            if (((Task)item.Tag).Executing)
345                using (ProgressForm form = new ProgressForm((Task)item.Tag))
346                    form.ShowDialog();
347            else
348                editTaskToolStripMenuItem_Click(sender, e);
349        }
350
351        /// <summary>
352        /// Occurs when the user drags a file over the scheduler
353        /// </summary>
354        private void scheduler_DragEnter(object sender, DragEventArgs e)
355        {
356            string descriptionMessage = string.Empty;
357            string descriptionInsert = string.Empty;
358            const string descrptionPlaceholder = "%1";
359            if (!e.Data.GetDataPresent(DataFormats.FileDrop))
360                e.Effect = DragDropEffects.None;
361            else
362            {
363                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
364                bool isTaskList = true;
365                foreach (string file in files)
366                {
367                    descriptionInsert += string.Format(CultureInfo.InvariantCulture, "{0}, ",
368                        Path.GetFileNameWithoutExtension(file));
369                    if (Path.GetExtension(file) != ".ersx")
370                        isTaskList = false;
371                }
372                descriptionInsert = descriptionInsert.Remove(descriptionInsert.Length - 2);
373
374                if (isTaskList)
375                {
376                    e.Effect = DragDropEffects.Copy;
377                    descriptionMessage = S._("Import tasks from {0}", descrptionPlaceholder);
378                }
379                else
380                {
381                    e.Effect = DragDropEffects.Move;
382                    descriptionMessage = S._("Erase {0}", descrptionPlaceholder);
383                }
384            }
385
386            DropTargetHelper.DragEnter(this, e.Data, new Point(e.X, e.Y), e.Effect,
387                descriptionMessage, descriptionInsert);
388        }
389
390        private void scheduler_DragLeave(object sender, EventArgs e)
391        {
392            DropTargetHelper.DragLeave(this);
393        }
394
395        private void scheduler_DragOver(object sender, DragEventArgs e)
396        {
397            DropTargetHelper.DragOver(new Point(e.X, e.Y), e.Effect);
398        }
399
400        /// <summary>
401        /// Occurs when the user drops a file into the scheduler.
402        /// </summary>
403        private void scheduler_DragDrop(object sender, DragEventArgs e)
404        {
405            if (!e.Data.GetDataPresent(DataFormats.FileDrop))
406                e.Effect = DragDropEffects.None;
407            else
408            {
409                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
410
411                //Determine whether we are importing a task list or dragging files for
412                //erasure.
413                if (e.Effect == DragDropEffects.Copy)
414                {
415                    foreach (string file in files)
416                        using (FileStream stream = new FileStream(file, FileMode.Open,
417                            FileAccess.Read, FileShare.Read))
418                        {
419                            try
420                            {
421                                Program.eraserClient.Tasks.LoadFromStream(stream);
422                            }
423                            catch (SerializationException ex)
424                            {
425                                MessageBox.Show(S._("Could not import task list from {0}. The error " +
426                                    "returned was: {1}", file, ex.Message), S._("Eraser"),
427                                    MessageBoxButtons.OK, MessageBoxIcon.Error,
428                                    MessageBoxDefaultButton.Button1,
429                                    S.IsRightToLeft(null) ? MessageBoxOptions.RtlReading : 0);
430                            }
431                        }
432                }
433                else if (e.Effect == DragDropEffects.Move)
434                {
435                    //Create a task with the default settings
436                    Task task = new Task();
437                    foreach (string file in files)
438                    {
439                        FileSystemObjectTarget target;
440                        if (Directory.Exists(file))
441                            target = new FolderTarget();
442                        else
443                            target = new FileTarget();
444                        target.Path = file;
445
446                        task.Targets.Add(target);
447                    }
448
449                    //Add the task.
450                    Program.eraserClient.Tasks.Add(task);
451                }
452            }
453
454            DropTargetHelper.Drop(e.Data, new Point(e.X, e.Y), e.Effect);
455        }
456
457        /// <summary>
458        /// Occurs when the user right-clicks the list view.
459        /// </summary>
460        /// <param name="sender">The list view which generated this event.</param>
461        /// <param name="e">Event argument.</param>
462        private void schedulerMenu_Opening(object sender, CancelEventArgs e)
463        {
464            //If nothing's selected, show the Scheduler menu which just allows users to
465            //create new tasks (like from the toolbar)
466            if (scheduler.SelectedItems.Count == 0)
467            {
468                schedulerDefaultMenu.Show(schedulerMenu.Left, schedulerMenu.Top);
469                e.Cancel = true;
470                return;
471            }
472
473            bool aTaskNotQueued = false;
474            bool aTaskExecuting = false;
475            foreach (ListViewItem item in scheduler.SelectedItems)
476            {
477                Task task = (Task)item.Tag;
478                aTaskNotQueued = aTaskNotQueued || (!task.Queued && !task.Executing);
479                aTaskExecuting = aTaskExecuting || task.Executing;
480            }
481
482            runNowToolStripMenuItem.Enabled = aTaskNotQueued;
483            cancelTaskToolStripMenuItem.Enabled = aTaskExecuting;
484
485            editTaskToolStripMenuItem.Enabled = scheduler.SelectedItems.Count == 1 &&
486                !((Task)scheduler.SelectedItems[0].Tag).Executing &&
487                !((Task)scheduler.SelectedItems[0].Tag).Queued;
488            deleteTaskToolStripMenuItem.Enabled = !aTaskExecuting;
489        }
490
491        /// <summary>
492        /// Occurs when the user selects the New Task context menu item.
493        /// </summary>
494        /// <param name="sender">The menu which generated this event.</param>
495        /// <param name="e">Event argument.</param>
496        private void newTaskToolStripMenuItem_Click(object sender, EventArgs e)
497        {
498            using (TaskPropertiesForm form = new TaskPropertiesForm())
499            {
500                if (form.ShowDialog() == DialogResult.OK)
501                {
502                    Task task = form.Task;
503                    Program.eraserClient.Tasks.Add(task);
504                }
505            }
506        }
507
508        /// <summary>
509        /// Occurs whent the user selects the Run Now context menu item.
510        /// </summary>
511        /// <param name="sender">The menu which generated this event.</param>
512        /// <param name="e">Event argument.</param>
513        private void runNowToolStripMenuItem_Click(object sender, EventArgs e)
514        {
515            foreach (ListViewItem item in scheduler.SelectedItems)
516            {
517                //Queue the task
518                Task task = (Task)item.Tag;
519                if (!task.Executing && !task.Queued)
520                {
521                    Program.eraserClient.QueueTask(task);
522
523                    //Update the UI
524                    item.SubItems[1].Text = S._("Queued for execution");
525                }
526            }
527        }
528
529        /// <summary>
530        /// Occurs whent the user selects the Cancel Task context menu item.
531        /// </summary>
532        /// <param name="sender">The menu which generated this event.</param>
533        /// <param name="e">Event argument.</param>
534        private void cancelTaskToolStripMenuItem_Click(object sender, EventArgs e)
535        {
536            foreach (ListViewItem item in scheduler.SelectedItems)
537            {
538                //Queue the task
539                Task task = (Task)item.Tag;
540                if (task.Executing || task.Queued)
541                {
542                    task.Cancel();
543
544                    //Update the UI
545                    item.SubItems[1].Text = string.Empty;
546                }
547            }
548        }
549
550        /// <summary>
551        /// Occurs when the user selects the View Task Log context menu item.
552        /// </summary>
553        /// <param name="sender">The menu item which generated this event.</param>
554        /// <param name="e">Event argument.</param>
555        private void viewTaskLogToolStripMenuItem_Click(object sender, EventArgs e)
556        {
557            if (scheduler.SelectedItems.Count != 1)
558                return;
559
560            ListViewItem item = scheduler.SelectedItems[0];
561            using (LogForm form = new LogForm((Task)item.Tag))
562                form.ShowDialog();
563        }
564
565        /// <summary>
566        /// Occurs when the user selects the Edit Task context menu item.
567        /// </summary>
568        /// <param name="sender">The menu item which generated this event.</param>
569        /// <param name="e">Event argument.</param>
570        private void editTaskToolStripMenuItem_Click(object sender, EventArgs e)
571        {
572            if (scheduler.SelectedItems.Count != 1 ||
573                ((Task)scheduler.SelectedItems[0].Tag).Executing ||
574                ((Task)scheduler.SelectedItems[0].Tag).Queued)
575            {
576                return;
577            }
578
579            //Make sure that the task is not being executed, or else. This can
580            //be done in the Client library, but there will be no effect on the
581            //currently running task.
582            ListViewItem item = scheduler.SelectedItems[0];
583            Task task = (Task)item.Tag;
584            if (task.Executing)
585                return;
586
587            //Edit the task.
588            using (TaskPropertiesForm form = new TaskPropertiesForm())
589            {
590                form.Task = task;
591                if (form.ShowDialog() == DialogResult.OK)
592                {
593                    task = form.Task;
594
595                    //Update the list view
596                    UpdateTask(item);
597                }
598            }
599        }
600
601        /// <summary>
602        /// Occurs when the user selects the Delete Task context menu item.
603        /// </summary>
604        /// <param name="sender">The menu item which generated this event.</param>
605        /// <param name="e">Event argument.</param>
606        private void deleteTaskToolStripMenuItem_Click(object sender, EventArgs e)
607        {
608            DeleteSelectedTasks();
609        }
610
611        #region Item management
612        /// <summary>
613        /// Retrieves the ListViewItem for the given task.
614        /// </summary>
615        /// <param name="task">The task object whose list view entry is being sought.</param>
616        /// <returns>A ListViewItem for the given task object.</returns>
617        private ListViewItem GetTaskItem(Task task)
618        {
619            foreach (ListViewItem item in scheduler.Items)
620                if (item.Tag == task)
621                    return item;
622
623            return null;
624        }
625
626        /// <summary>
627        /// Maintains the position of the progress bar.
628        /// </summary>
629        private void PositionProgressBar()
630        {
631            if (schedulerProgress.Tag == null)
632                return;
633
634            Rectangle rect = ((ListViewItem)schedulerProgress.Tag).SubItems[2].Bounds;
635            schedulerProgress.Location = rect.Location;
636            schedulerProgress.Size = rect.Size;
637        }
638
639        private void scheduler_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
640        {
641            e.DrawDefault = true;
642            if (schedulerProgress.Tag != null)
643                PositionProgressBar();
644        }
645
646        private void scheduler_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
647        {
648            e.DrawDefault = true;
649        }
650        #endregion
651    }
652}
Note: See TracBrowser for help on using the repository browser.