GUI/MainForm.cs
author paulwerelds
Tue, 05 Oct 2010 19:34:59 +0000
changeset 213 d93c927e4fd6
parent 212 7e98c9e1a4f4
child 214 9ddbb54998ac
permissions -rw-r--r--
Fixed Issue 123.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.ComponentModel;
    41 using System.Configuration;
    42 using System.Drawing;
    43 using System.IO;
    44 using System.Text;
    45 using System.Windows.Forms;
    46 using Aga.Controls.Tree;
    47 using Aga.Controls.Tree.NodeControls;
    48 using OpenHardwareMonitor.Hardware;
    49 using OpenHardwareMonitor.Utilities;
    50 
    51 namespace OpenHardwareMonitor.GUI {
    52   public partial class MainForm : Form {
    53 
    54     private PersistentSettings settings;
    55     private UnitManager unitManager;
    56     private Computer computer;
    57     private Node root;
    58     private TreeModel treeModel;
    59     private IDictionary<ISensor, Color> sensorPlotColors = 
    60       new Dictionary<ISensor, Color>();
    61     private Color[] plotColorPalette;
    62     private SystemTray systemTray;    
    63     private StartupManager startupManager = new StartupManager();
    64     private UpdateVisitor updateVisitor = new UpdateVisitor();
    65     private SensorGadget gadget;
    66 
    67     private UserOption showHiddenSensors;
    68     private UserOption showPlot;
    69     private UserOption showValue;
    70     private UserOption showMin;
    71     private UserOption showMax;
    72     private UserOption startMinimized;
    73     private UserOption minimizeToTray;
    74     private UserOption minimizeOnClose;
    75     private UserOption autoStart;
    76     private UserOption readHddSensors;
    77     private UserOption showGadget;
    78 
    79     public MainForm() {      
    80       InitializeComponent();
    81 
    82       this.settings = new PersistentSettings();      
    83       this.settings.Load(Path.ChangeExtension(
    84         Application.ExecutablePath, ".config"));
    85 
    86       this.unitManager = new UnitManager(settings);
    87 
    88       // set the DockStyle here, to avoid conflicts with the MainMenu
    89       this.splitContainer.Dock = DockStyle.Fill;
    90             
    91       this.Font = SystemFonts.MessageBoxFont;
    92       treeView.Font = SystemFonts.MessageBoxFont;
    93       plotPanel.Font = SystemFonts.MessageBoxFont;
    94       
    95       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
    96       nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
    97       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
    98       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
    99       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   100       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   101       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   102 
   103       Rectangle newBounds = new Rectangle {
   104         X = settings.GetValue("mainForm.Location.X", Location.X),
   105         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   106         Width = settings.GetValue("mainForm.Width", 470),
   107         Height = settings.GetValue("mainForm.Height", 640)
   108       };
   109 
   110       Screen[] screens = Screen.AllScreens;
   111       Rectangle totalWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   112         int.MinValue, int.MinValue);
   113 
   114       foreach(Screen screen in screens)
   115         totalWorkingArea = Rectangle.Union(totalWorkingArea, screen.Bounds);
   116 
   117       this.Bounds = newBounds;
   118 
   119       if (!totalWorkingArea.Contains(newBounds) ||
   120         !settings.Contains("mainForm.Location.X"))
   121         this.StartPosition = FormStartPosition.CenterScreen;
   122 
   123       foreach (TreeColumn column in treeView.Columns) 
   124         column.Width = Math.Max(20, Math.Min(400,
   125           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   126           column.Width)));
   127 
   128       treeModel = new TreeModel();
   129       root = new Node(System.Environment.MachineName);
   130       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   131       
   132       treeModel.Nodes.Add(root);
   133       treeView.Model = treeModel;
   134 
   135       this.computer = new Computer(settings);
   136 
   137       systemTray = new SystemTray(computer, settings);
   138       systemTray.HideShowCommand += hideShowClick;
   139       systemTray.ExitCommand += exitClick;
   140 
   141       int p = (int)Environment.OSVersion.Platform;
   142       if ((p == 4) || (p == 128)) { // Unix
   143         splitContainer.BorderStyle = BorderStyle.None;
   144         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   145         splitContainer.SplitterWidth = 4;
   146         treeView.BorderStyle = BorderStyle.Fixed3D;
   147         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   148         gadgetMenuItem.Visible = false;
   149         minCloseMenuItem.Visible = false;
   150       } else { // Windows
   151         gadget = new SensorGadget(computer, settings, unitManager);
   152       }          
   153 
   154       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   155       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
   156       computer.Open();
   157 
   158       timer.Enabled = true;
   159 
   160       plotColorPalette = new Color[13];
   161       plotColorPalette[0] = Color.Blue;
   162       plotColorPalette[1] = Color.OrangeRed;
   163       plotColorPalette[2] = Color.Green;
   164       plotColorPalette[3] = Color.LightSeaGreen;
   165       plotColorPalette[4] = Color.Goldenrod;
   166       plotColorPalette[5] = Color.DarkViolet;
   167       plotColorPalette[6] = Color.YellowGreen;
   168       plotColorPalette[7] = Color.SaddleBrown;
   169       plotColorPalette[8] = Color.RoyalBlue;
   170       plotColorPalette[9] = Color.DeepPink;
   171       plotColorPalette[10] = Color.MediumSeaGreen;
   172       plotColorPalette[11] = Color.Olive;
   173       plotColorPalette[12] = Color.Firebrick;
   174 
   175       showHiddenSensors = new UserOption("hiddenMenuItem", false, hiddenMenuItem, settings);
   176       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   177         treeModel.ForceVisible = showHiddenSensors.Value;
   178       };
   179 
   180       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   181       showPlot.Changed += delegate(object sender, EventArgs e) {
   182         splitContainer.Panel2Collapsed = !showPlot.Value;
   183         treeView.Invalidate();
   184       };
   185 
   186       showValue = new UserOption("valueMenuItem", true, valueMenuItem, settings);
   187       showValue.Changed += delegate(object sender, EventArgs e) {
   188         treeView.Columns[1].IsVisible = showValue.Value;
   189       };
   190 
   191       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   192       showMin.Changed += delegate(object sender, EventArgs e) {
   193         treeView.Columns[2].IsVisible = showMin.Value;
   194       };
   195 
   196       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   197       showMax.Changed += delegate(object sender, EventArgs e) {
   198         treeView.Columns[3].IsVisible = showMax.Value;
   199       };
   200 
   201       startMinimized = new UserOption("startMinMenuItem", false, startMinMenuItem, settings);
   202 
   203       minimizeToTray = new UserOption("minTrayMenuItem", true, minTrayMenuItem, settings);
   204       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   205         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   206       };
   207 
   208       minimizeOnClose = new UserOption("minCloseMenuItem", false, minCloseMenuItem, settings);
   209 
   210       autoStart = new UserOption(null, startupManager.Startup, startupMenuItem, settings);
   211       autoStart.Changed += delegate(object sender, EventArgs e) {
   212         try {
   213           startupManager.Startup = autoStart.Value;
   214         } catch (InvalidOperationException) {
   215           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   216             MessageBoxButtons.OK, MessageBoxIcon.Error);
   217           autoStart.Value = startupManager.Startup;
   218         }
   219       };
   220 
   221       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem, settings);
   222       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   223         computer.HDDEnabled = readHddSensors.Value;
   224         UpdatePlotSelection(null, null);
   225       };
   226 
   227       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem, settings);
   228       showGadget.Changed += delegate(object sender, EventArgs e) {
   229         if (gadget != null) 
   230           gadget.Visible = showGadget.Value;
   231       };
   232 
   233       celciusMenuItem.Checked = 
   234         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   235       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   236 
   237       startupMenuItem.Visible = startupManager.IsAvailable;
   238       
   239       if (startMinMenuItem.Checked) {
   240         if (!minTrayMenuItem.Checked) {
   241           WindowState = FormWindowState.Minimized;
   242           Show();
   243         }
   244       } else {
   245         Show();
   246       }
   247 
   248       // Create a handle, otherwise calling Close() does not fire FormClosed     
   249       IntPtr handle = Handle;
   250 
   251       // Make sure the settings are saved when the user logs off
   252       Microsoft.Win32.SystemEvents.SessionEnded +=
   253         delegate(object sender, Microsoft.Win32.SessionEndedEventArgs e) {
   254           SaveConfiguration();
   255         };  
   256     }
   257     
   258     private void SubHardwareAdded(IHardware hardware, Node node) {
   259       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   260       node.Nodes.Add(hardwareNode);
   261       foreach (IHardware subHardware in hardware.SubHardware)
   262         SubHardwareAdded(subHardware, hardwareNode);  
   263     }
   264 
   265     private void HardwareAdded(IHardware hardware) {
   266       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   267       root.Nodes.Add(hardwareNode);
   268       foreach (IHardware subHardware in hardware.SubHardware)
   269         SubHardwareAdded(subHardware, hardwareNode);     
   270     }
   271 
   272     private void HardwareRemoved(IHardware hardware) {      
   273       List<Node> nodesToRemove = new List<Node>();
   274       foreach (Node node in root.Nodes) {
   275         HardwareNode hardwareNode = node as HardwareNode;
   276         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   277           nodesToRemove.Add(node);
   278       }
   279       foreach (Node node in nodesToRemove)
   280         root.Nodes.Remove(node);
   281     }
   282 
   283     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   284       Node node = e.Node.Tag as Node;
   285       if (node != null) {
   286         Color color;
   287         if (node.IsVisible) {
   288           SensorNode sensorNode = node as SensorNode;
   289           if (plotMenuItem.Checked && sensorNode != null &&
   290             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   291             e.TextColor = color;
   292         } else {
   293           e.TextColor = Color.DarkGray;
   294         }
   295       }
   296     }
   297 
   298     private void UpdatePlotSelection(object sender, 
   299       TreePathEventArgs e) 
   300     {
   301       List<ISensor> selected = new List<ISensor>();
   302       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   303       int colorIndex = 0;
   304       foreach (TreeNodeAdv node in treeView.AllNodes) {
   305         SensorNode sensorNode = node.Tag as SensorNode;
   306         if (sensorNode != null && 
   307           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   308           if (sensorNode.Plot) {
   309             colors.Add(sensorNode.Sensor,
   310               plotColorPalette[colorIndex % plotColorPalette.Length]);
   311             selected.Add(sensorNode.Sensor);
   312           }
   313           colorIndex++;
   314         }
   315       }
   316       sensorPlotColors = colors;
   317       plotPanel.SetSensors(selected, colors);
   318     }
   319 
   320     private void nodeTextBoxText_EditorShowing(object sender, CancelEventArgs e) 
   321     {
   322       e.Cancel = !(treeView.CurrentNode != null &&
   323         treeView.CurrentNode.Tag is SensorNode);
   324     }
   325 
   326     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   327       NodeControlValueEventArgs e) {
   328       SensorNode node = e.Node.Tag as SensorNode;
   329       e.Value = (node != null) && 
   330         (node.Sensor.SensorType == SensorType.Temperature) && 
   331         plotMenuItem.Checked;
   332     }
   333 
   334     private void exitClick(object sender, EventArgs e) {
   335       Close();
   336     }
   337 
   338     private void timer_Tick(object sender, EventArgs e) {
   339       computer.Accept(updateVisitor);
   340       treeView.Invalidate();
   341       plotPanel.Invalidate();
   342       systemTray.Redraw(); 
   343       if (gadget != null)
   344         gadget.Redraw();
   345     }
   346 
   347     private void SaveConfiguration() {
   348       if (WindowState != FormWindowState.Minimized) {
   349         settings.SetValue("mainForm.Location.X", Location.X);
   350         settings.SetValue("mainForm.Location.Y", Location.Y);
   351         settings.SetValue("mainForm.Width", ClientSize.Width);
   352         settings.SetValue("mainForm.Height", ClientSize.Height);
   353       }
   354 
   355       foreach (TreeColumn column in treeView.Columns)
   356         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   357           column.Width);
   358 
   359       string fileName = Path.ChangeExtension(
   360           System.Windows.Forms.Application.ExecutablePath, ".config");
   361       try {
   362         settings.Save(fileName);
   363       } catch (UnauthorizedAccessException) {
   364         MessageBox.Show("Access to the path '" + fileName + "' is denied. " + 
   365           "The current seetings could not be saved.", 
   366           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   367       }
   368     }
   369 
   370    private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   371       Visible = false;
   372       SaveConfiguration();
   373 
   374       timer.Enabled = false;
   375       systemTray.Dispose();      
   376       computer.Close();
   377     }
   378 
   379     private void aboutMenuItem_Click(object sender, EventArgs e) {
   380       new AboutBox().ShowDialog();
   381     }
   382 
   383     private void treeView_Click(object sender, EventArgs e) {
   384       
   385       MouseEventArgs m = e as MouseEventArgs;
   386       if (m == null || m.Button != MouseButtons.Right)
   387         return;
   388 
   389       NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y));
   390       treeView.SelectedNode = info.Node;
   391       if (info.Node != null) {
   392         SensorNode node = info.Node.Tag as SensorNode;
   393         if (node != null && node.Sensor != null) {
   394           sensorContextMenu.MenuItems.Clear();
   395           if (node.Sensor.Parameters.Length > 0) {
   396             MenuItem item = new MenuItem("Parameters...");
   397             item.Click += delegate(object obj, EventArgs args) {
   398               ShowParameterForm(node.Sensor);
   399             };
   400             sensorContextMenu.MenuItems.Add(item);
   401           }
   402           if (nodeTextBoxText.EditEnabled) {
   403             MenuItem item = new MenuItem("Rename");
   404             item.Click += delegate(object obj, EventArgs args) {
   405               nodeTextBoxText.BeginEdit();
   406             };
   407             sensorContextMenu.MenuItems.Add(item);
   408           }
   409           if (node.IsVisible) {
   410             MenuItem item = new MenuItem("Hide");
   411             item.Click += delegate(object obj, EventArgs args) {
   412               node.IsVisible = false;
   413             };
   414             sensorContextMenu.MenuItems.Add(item);
   415           } else {
   416             MenuItem item = new MenuItem("Unhide");
   417             item.Click += delegate(object obj, EventArgs args) {
   418               node.IsVisible = true;
   419             };
   420             sensorContextMenu.MenuItems.Add(item);
   421           }
   422           sensorContextMenu.MenuItems.Add(new MenuItem("-"));
   423           {
   424             MenuItem item = new MenuItem("Show in Tray");
   425             item.Checked = systemTray.Contains(node.Sensor);
   426             item.Click += delegate(object obj, EventArgs args) {
   427               if (item.Checked)
   428                 systemTray.Remove(node.Sensor);
   429               else
   430                 systemTray.Add(node.Sensor, true);
   431             };
   432             sensorContextMenu.MenuItems.Add(item);
   433           }
   434           if (gadget != null) {
   435             MenuItem item = new MenuItem("Show in Gadget");
   436             item.Checked = gadget.Contains(node.Sensor);
   437             item.Click += delegate(object obj, EventArgs args) {
   438               if (item.Checked) {
   439                 gadget.Remove(node.Sensor);
   440               } else {
   441                 gadget.Add(node.Sensor);
   442               }
   443             };
   444             sensorContextMenu.MenuItems.Add(item);
   445           }
   446 
   447           sensorContextMenu.Show(treeView, new Point(m.X, m.Y));
   448         }
   449       }
   450     }
   451 
   452     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   453       string report = computer.GetReport();
   454       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   455         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   456           w.Write(report);
   457         }
   458       }
   459     }
   460 
   461     private void SysTrayHideShow() {
   462       Visible = !Visible;
   463       if (Visible)
   464         Activate();    
   465     }
   466 
   467     protected override void WndProc(ref Message m) {
   468       const int WM_SYSCOMMAND = 0x112;
   469       const int SC_MINIMIZE = 0xF020;
   470       const int SC_CLOSE = 0xF060;
   471 
   472       if (minimizeToTray.Value && 
   473         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   474         SysTrayHideShow();
   475       } else if(minimizeOnClose.Value && 
   476         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   477         /*
   478          * Apparently the user wants to minimize rather than close
   479          * Now we still need to check if we're going to the tray or not
   480          * 
   481          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   482          * but since the code here is so simple,
   483          * that would just be a waste of time.
   484          */
   485         if (minimizeToTray.Value)
   486           SysTrayHideShow();
   487         else
   488           WindowState = FormWindowState.Minimized;
   489       } else {      
   490         base.WndProc(ref m);
   491       }
   492     }
   493 
   494     private void hideShowClick(object sender, EventArgs e) {
   495       SysTrayHideShow();
   496     }
   497 
   498     private void ShowParameterForm(ISensor sensor) {
   499       ParameterForm form = new ParameterForm();
   500       form.Parameters = sensor.Parameters;
   501       form.captionLabel.Text = sensor.Name;
   502       form.ShowDialog();
   503     }
   504 
   505     private void treeView_NodeMouseDoubleClick(object sender, 
   506       TreeNodeAdvMouseEventArgs e) {
   507       SensorNode node = e.Node.Tag as SensorNode;
   508       if (node != null && node.Sensor != null && 
   509         node.Sensor.Parameters.Length > 0) {
   510         ShowParameterForm(node.Sensor);
   511       }
   512     }
   513 
   514     private void celciusMenuItem_Click(object sender, EventArgs e) {
   515       celciusMenuItem.Checked = true;
   516       fahrenheitMenuItem.Checked = false;
   517       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   518     }
   519 
   520     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   521       celciusMenuItem.Checked = false;
   522       fahrenheitMenuItem.Checked = true;
   523       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   524     }
   525 
   526     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   527     {
   528       ReportForm form = new ReportForm();
   529       form.Report = computer.GetReport();
   530       form.ShowDialog();      
   531     }
   532 
   533     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   534       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   535         sensor.ResetMin();
   536         sensor.ResetMax();
   537       }));
   538     }
   539   }
   540 }