source: trunk/eraser/Eraser/MainForm.cs @ 2960

Revision 2958, 15.6 KB checked in by gtrant, 2 months ago (diff)

Updated Copyright to 2014
Updated versions to 6.2
Fix for date stamp on erased artefacts

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2014 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.Drawing.Drawing2D;
28using System.Text;
29using System.Windows.Forms;
30
31using System.IO;
32using System.Diagnostics;
33using System.Reflection;
34using System.Runtime.Serialization;
35
36using Eraser.Util;
37using Eraser.Manager;
38using Eraser.Plugins;
39using Eraser.Plugins.Registrars;
40using Eraser.Plugins.ExtensionPoints;
41using Eraser.Properties;
42
43namespace Eraser
44{
45    public partial class MainForm : Form, INotificationSink
46    {
47        private BasePanel CurrPage;
48        private SchedulerPanel SchedulerPage;
49        private SettingsPanel SettingsPage;
50
51        public MainForm()
52        {
53            InitializeComponent();
54            SettingsPage = new SettingsPanel();
55            SchedulerPage = new SchedulerPanel();
56            contentPanel.Controls.Add(SchedulerPage);
57            contentPanel.Controls.Add(SettingsPage);
58            if (!IsHandleCreated)
59                CreateHandle();
60
61            Theming.ApplyTheme(this);
62            Theming.ApplyTheme(notificationMenu);
63
64            //We need to see if there are any tools to display
65            foreach (IClientTool tool in Host.Instance.ClientTools)
66                tool.RegisterTool(tbToolsMenu);
67            if (tbToolsMenu.Items.Count == 0)
68            {
69                //There are none, hide the menu
70                tbTools.Visible = false;
71                tbToolsDropDown.Visible = false;
72            }
73
74            //We also need to see if we have any notifier classes we need to register.
75            foreach (INotifier notifier in Host.Instance.Notifiers)
76                notifier.Sink = this;
77            Host.Instance.Notifiers.Registered += Notifier_Registered;
78
79            //For every task we need to register the Task Started and Task Finished
80            //event handlers for progress notifications
81            foreach (Task task in Program.eraserClient.Tasks)
82                OnTaskAdded(this, new TaskEventArgs(task));
83            Program.eraserClient.TaskAdded += OnTaskAdded;
84            Program.eraserClient.TaskDeleted += OnTaskDeleted;
85
86            //Check if we have tasks running already.
87            foreach (Task task in Program.eraserClient.Tasks)
88                if (task.Executing)
89                {
90                    OnTaskProcessing(task, EventArgs.Empty);
91                    break;
92                }
93
94            //Check the notification area context menu's minimise to tray item.
95            hideWhenMinimisedToolStripMenuItem.Checked = EraserSettings.Get().HideWhenMinimised;
96
97            //Set the docking style for each of the pages
98            SchedulerPage.Dock = DockStyle.Fill;
99            SettingsPage.Visible = false;
100
101            //Show the default page.
102            ChangePage(MainFormPage.Scheduler);
103        }
104
105        #region Notifications handling code
106        /// <summary>
107        /// Stores information about pending notifications.
108        /// </summary>
109        private struct NotificationInfo
110        {
111            public INotifier Source;
112            public int Timeout;
113            public ToolTipIcon Icon;
114            public string Title;
115            public string Message;
116        }
117
118        /// <summary>
119        /// Diplays the given title, message and icon as a system notification area balloon.
120        /// </summary>
121        /// <param name="title">The title of the balloon.</param>
122        /// <param name="message">The message to display.</param>
123        /// <param name="icon">The icon to show.</param>
124        public void ShowNotificationBalloon(string title, string message, ToolTipIcon icon)
125        {
126            NotificationInfo info;
127            info.Source = null;
128            info.Timeout = 0;
129            info.Icon = icon;
130            info.Title = title;
131            info.Message = message;
132
133            NotificationsQueue.Add(info);
134
135            //Can we show the notification immediately?
136            if (NotificationsQueue.Count == 1)
137                ShowNextNotification();
138        }
139
140        public void ShowNotification(INotifier source, int timeout, ToolTipIcon icon,
141            string title, string message)
142        {
143            NotificationInfo info;
144            info.Source = source;
145            info.Timeout = timeout;
146            info.Icon = icon;
147            info.Title = title;
148            info.Message = message;
149
150            NotificationsQueue.Add(info);
151
152            //Can we show the notification immediately?
153            if (NotificationsQueue.Count == 1)
154                ShowNextNotification();
155        }
156
157        private void Notifier_Registered(object sender, EventArgs e)
158        {
159            ((INotifier)sender).Sink = this;
160        }
161
162        private void ShowNextNotification()
163        {
164            Debug.Assert(NotificationsQueue.Count != 0);
165            NotificationInfo info = NotificationsQueue[0];
166            notificationIcon.ShowBalloonTip(info.Timeout, info.Title, info.Message, info.Icon);
167        }
168
169        private void notificationIcon_BalloonTipShown(object sender, EventArgs e)
170        {
171            Debug.Assert(NotificationsQueue.Count != 0);
172            if (NotificationsQueue[0].Source != null)
173                NotificationsQueue[0].Source.Shown(sender, e);
174        }
175
176        private void notificationIcon_BalloonTipClosed(object sender, EventArgs e)
177        {
178            Debug.Assert(NotificationsQueue.Count != 0);
179
180            if (NotificationsQueue[0].Source != null)
181                NotificationsQueue[0].Source.Closed(sender, e);
182            NotificationsQueue.RemoveAt(0);
183
184            if (NotificationsQueue.Count > 0)
185                ShowNextNotification();
186        }
187
188        private void notificationIcon_BalloonTipClicked(object sender, EventArgs e)
189        {
190            Debug.Assert(NotificationsQueue.Count != 0);
191            if (NotificationsQueue[0].Source != null)
192                NotificationsQueue[0].Source.Clicked(sender, e);
193        }
194
195        /// <summary>
196        /// The queue holding the list of notifications to be displayed sequentially.
197        /// The notification being displayed is the first item in the list.
198        /// </summary>
199        private List<NotificationInfo> NotificationsQueue = new List<NotificationInfo>();
200        #endregion
201
202        /// <summary>
203        /// Changes the active page displayed in the form.
204        /// </summary>
205        /// <param name="page">The new page to change to. No action is done when the
206        /// current page is the same as the new page requested</param>
207        public void ChangePage(MainFormPage page)
208        {
209            BasePanel oldPage = CurrPage;
210            switch (page)
211            {
212                case MainFormPage.Scheduler:
213                    CurrPage = SchedulerPage;
214                    break;
215                case MainFormPage.Settings:
216                    CurrPage = SettingsPage;
217                    break;
218            }
219
220            if (oldPage != CurrPage)
221            {
222                contentPanel.SuspendLayout();
223
224                //Hide the old page before showing the new one
225                if (oldPage != null)
226                    oldPage.Visible = false;
227
228                //If the page is not set to dock, we need to specify the dimensions of the page
229                //so it fits properly.
230                if (CurrPage.Dock == DockStyle.None)
231                {
232                    CurrPage.Anchor = AnchorStyles.Left | AnchorStyles.Right |
233                        AnchorStyles.Top;
234                    CurrPage.Left = 0;
235                    CurrPage.Top = 0;
236                    CurrPage.Width = contentPanel.Width;
237                }
238
239                //Show the new page then bring it to the top of the z-order.
240                CurrPage.Visible = true;
241                CurrPage.BringToFront();
242                contentPanel.ResumeLayout();
243            }
244        }
245
246        private static GraphicsPath CreateRoundRect(float X, float Y, float width,
247            float height, float radius)
248        {
249            GraphicsPath result = new GraphicsPath();
250
251            //Top line.
252            result.AddLine(X + radius, Y, X + width - 2 * radius, Y);
253
254            //Top-right corner
255            result.AddArc(X + width - 2 * radius, Y, 2 * radius, 2 * radius, 270, 90);
256
257            //Right line.
258            result.AddLine(X + width, Y + radius, X + width, Y + height - 2 * radius);
259
260            //Bottom-right corner
261            result.AddArc(X + width - 2 * radius, Y + height - 2 * radius, 2 * radius, 2 * radius, 0, 90);
262
263            //Bottom line.
264            result.AddLine(X + width - 2 * radius, Y + height, X + radius, Y + height);
265
266            //Bottom-left corner
267            result.AddArc(X, Y + height - 2 *radius, 2 * radius, 2 * radius, 90, 90);
268
269            //Left line
270            result.AddLine(X, Y + height - 2 * radius, X, Y + radius);
271
272            //Top-left corner
273            result.AddArc(X, Y, 2 * radius, 2 * radius, 180, 90);
274            result.CloseFigure();
275
276            return result;
277        }
278
279        private void DrawBackground(Graphics dc)
280        {
281            //Draw the base background
282            dc.FillRectangle(new SolidBrush(Color.FromArgb(unchecked((int)0xFF292929))),
283                new Rectangle(new Point(0, 0), Size));
284
285            //Then the side gradient
286            dc.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, 338, Math.Max(1, ClientSize.Height)),
287                    Color.FromArgb(unchecked((int)0xFF363636)),
288                    Color.FromArgb(unchecked((int)0xFF292929)), 0.0),
289                0, 0, 338, ClientSize.Height);
290
291            //Draw the top background
292            dc.FillRectangle(new SolidBrush(Color.FromArgb(unchecked((int)0xFF414141))),
293                new Rectangle(0, 0, ClientSize.Width, 32));
294
295            //The top gradient
296            dc.DrawImage(Properties.Resources.BackgroundGradient, new Point(0, 0));
297
298            dc.SmoothingMode = SmoothingMode.AntiAlias;
299            dc.FillPath(Brushes.White, CreateRoundRect(11, 74, contentPanel.Width + 8, ClientSize.Height - 85, 3));
300        }
301
302        private void MainForm_Paint(object sender, PaintEventArgs e)
303        {
304            e.Graphics.SetClip(new Rectangle(0, 0, Width, Height), CombineMode.Intersect);
305            DrawBackground(e.Graphics);
306        }
307
308        private void MainForm_Resize(object sender, EventArgs e)
309        {
310            if (WindowState != FormWindowState.Minimized)
311            {
312                Bitmap bmp = new Bitmap(Width, Height);
313                Graphics dc = Graphics.FromImage(bmp);
314                DrawBackground(dc);
315
316                CreateGraphics().DrawImage(bmp, new Point(0, 0));
317            }
318            else if (EraserSettings.Get().HideWhenMinimised)
319            {
320                Visible = false;
321            }
322        }
323
324        private void tbSchedule_Click(object sender, EventArgs e)
325        {
326            ChangePage(MainFormPage.Scheduler);
327        }
328
329        private void tbSettings_Click(object sender, EventArgs e)
330        {
331            ChangePage(MainFormPage.Settings);
332        }
333
334        private void newTaskToolStripMenuItem_Click(object sender, EventArgs e)
335        {
336            using (TaskPropertiesForm form = new TaskPropertiesForm())
337            {
338                if (form.ShowDialog() == DialogResult.OK)
339                {
340                    Task task = form.Task;
341                    Program.eraserClient.Tasks.Add(task);
342                }
343            }
344        }
345
346        private void exportTaskListToolStripMenuItem_Click(object sender, EventArgs e)
347        {
348            using (SaveFileDialog dialog = new SaveFileDialog())
349            {
350                dialog.Filter = "Eraser 6 task lists (*.ersy)|*.ersy";
351                dialog.DefaultExt = "ersy";
352                dialog.OverwritePrompt = true;
353
354                if (dialog.ShowDialog() == DialogResult.OK)
355                {
356                    using (FileStream stream = new FileStream(dialog.FileName,
357                        FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
358                    {
359                        Program.eraserClient.Tasks.SaveToStream(stream);
360                    }
361                }
362            }
363        }
364
365        private void importTaskListToolStripMenuItem_Click(object sender, EventArgs e)
366        {
367            using (OpenFileDialog dialog = new OpenFileDialog())
368            {
369                dialog.Filter = "Eraser 6 XML task lists (*.ersy)|*.ersy";
370                dialog.DefaultExt = "ersy";
371
372                if (dialog.ShowDialog() == DialogResult.OK)
373                {
374                    using (FileStream stream = new FileStream(dialog.FileName,
375                        FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
376                    {
377                        try
378                        {
379                            Program.eraserClient.Tasks.LoadFromStream(stream);
380                        }
381                        catch (InvalidDataException ex)
382                        {
383                            MessageBox.Show(S._("The task list could not be imported. The error " +
384                                "returned was: {0}", ex.Message), S._("Eraser"),
385                                MessageBoxButtons.OK, MessageBoxIcon.Error,
386                                MessageBoxDefaultButton.Button1,
387                                Localisation.IsRightToLeft(this) ?
388                                    MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
389                        }
390                    }
391                }
392            }
393        }
394
395        private void tbHelp_Click(object sender, EventArgs e)
396        {
397            try
398            {
399                Process.Start(Path.Combine(Path.GetDirectoryName(
400                        Assembly.GetEntryAssembly().Location),
401                    "Eraser Documentation.pdf"));
402            }
403            catch (Win32Exception ex)
404            {
405                MessageBox.Show(this, S._("The Eraser documentation file could not be " +
406                    "opened. Check that Adobe Reader installed and that your Eraser " +
407                    "install is not corrupt.\n\nThe error returned was: {0}", ex.Message),
408                    S._("Eraser"), MessageBoxButtons.OK, MessageBoxIcon.Error,
409                    MessageBoxDefaultButton.Button1, Localisation.IsRightToLeft(this) ?
410                        MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
411            }
412        }
413
414        private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
415        {
416            using (UpdateForm form = new UpdateForm())
417            {
418                form.ShowDialog();
419            }
420        }
421
422        private void aboutEraserToolStripMenuItem_Click(object sender, EventArgs e)
423        {
424            using (AboutForm form = new AboutForm(this))
425            {
426                form.ShowDialog();
427            }
428        }
429
430        private void eraserLogo_Click(object sender, EventArgs e)
431        {
432            try
433            {
434                Process.Start("http://eraser.heidi.ie/");
435            }
436            catch (Win32Exception ex)
437            {
438                //We've got an error executing the the browser to pass the links: show an error
439                //to the user.
440                MessageBox.Show(S._("Could not open the required web page. The error returned " +
441                    "was: {0}", ex.Message), S._("Eraser"), MessageBoxButtons.OK,
442                    MessageBoxIcon.Error, MessageBoxDefaultButton.Button1,
443                    Localisation.IsRightToLeft(this) ?
444                        MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
445            }
446        }
447
448        #region Task processing code (for notification area animation)
449        void OnTaskAdded(object sender, TaskEventArgs e)
450        {
451            e.Task.TaskStarted += OnTaskProcessing;
452            e.Task.TaskFinished += OnTaskProcessed;
453        }
454
455        void OnTaskDeleted(object sender, TaskEventArgs e)
456        {
457            e.Task.TaskStarted -= OnTaskProcessing;
458            e.Task.TaskFinished -= OnTaskProcessed;
459        }
460
461        void OnTaskProcessing(object sender, EventArgs e)
462        {
463            if (InvokeRequired)
464            {
465                Invoke((EventHandler)OnTaskProcessing, sender, e);
466                return;
467            }
468
469            Task task = (Task)sender;
470            string iconText = S._("Eraser") + " - " + S._("Processing:") + ' ' + task.ToString();
471            if (iconText.Length >= 64)
472                iconText = iconText.Remove(60) + "...";
473
474            ProcessingAnimationFrame = 0;
475            notificationIcon.Text = iconText;
476            notificationIconTimer.Enabled = true;
477        }
478
479        void OnTaskProcessed(object sender, EventArgs e)
480        {
481            if (InvokeRequired)
482            {
483                Invoke((EventHandler)OnTaskProcessed, sender, e);
484                return;
485            }
486
487            //Reset the notification area icon.
488            notificationIconTimer.Enabled = false;
489            if (notificationIcon.Icon != null)
490            {
491                ComponentResourceManager resources = new ComponentResourceManager(typeof(MainForm));
492                resources.ApplyResources(notificationIcon, "notificationIcon");
493            }
494        }
495
496        private void notificationIconTimer_Tick(object sender, EventArgs e)
497        {
498            notificationIcon.Icon = ProcessingAnimationFrames[ProcessingAnimationFrame++];
499            if (ProcessingAnimationFrame == ProcessingAnimationFrames.Length)
500                ProcessingAnimationFrame = 0;
501        }
502
503        private int ProcessingAnimationFrame;
504        private Icon[] ProcessingAnimationFrames = new Icon[] {
505            Resources.NotifyBusy1,
506            Resources.NotifyBusy2,
507            Resources.NotifyBusy3,
508            Resources.NotifyBusy4,
509            Resources.NotifyBusy5,
510            Resources.NotifyBusy4,
511            Resources.NotifyBusy3,
512            Resources.NotifyBusy2,
513            Resources.NotifyBusy1
514        };
515        #endregion
516
517        #region Minimise to tray code
518        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
519        {
520            if (EraserSettings.Get().HideWhenMinimised && e.CloseReason == CloseReason.UserClosing)
521            {
522                e.Cancel = true;
523                Visible = false;
524            }
525        }
526
527        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
528        {
529            Application.Exit();
530        }
531
532        private void MainForm_VisibleChanged(object sender, EventArgs e)
533        {
534            if (Visible)
535            {
536                WindowState = FormWindowState.Normal;
537                Activate();
538            }
539        }
540
541        private void openToolStripMenuItem_Click(object sender, EventArgs e)
542        {
543            Visible = true;
544        }
545
546        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
547        {
548            Application.Exit();
549        }
550
551        private void hideWhenMinimiseToolStripMenuItem_Click(object sender, EventArgs e)
552        {
553            EraserSettings.Get().HideWhenMinimised =
554                hideWhenMinimisedToolStripMenuItem.Checked;
555        }
556        #endregion
557    }
558
559    public enum MainFormPage
560    {
561        Scheduler = 0,
562        Settings
563    }
564}
Note: See TracBrowser for help on using the repository browser.