source: branches/eraser6/6.0/Eraser/SchedulerPanel.cs @ 1633

Revision 1633, 18.8 KB checked in by lowjoel, 5 years ago (diff)

Fixed regression introduced in r1490 where CreateControl? was called in MainForm?. CreateControl? however does not create handles when the control is not visible (delayed creation.) Since only SchedulerPanel? needs to have a handle created, we'll force creation of the handle there. In addition, remove an unnecessary call to UXThemeApi.UpdateControlTheme?.

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