GUI/MainForm.cs
author moel.mich
Sun, 19 Jun 2011 12:41:18 +0000
changeset 298 96263190189a
parent 297 21504f47aedf
child 299 072989c22a87
permissions -rw-r--r--
Added support for saving and restoring the sensor history for the last 24h. The sensor history is now saved in a reduced format (duplicate values are removed, gaps are marked with a NAN sensor value.
     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-2011
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s): Paul Werelds
    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.Drawing;
    42 using System.IO;
    43 using System.Reflection;
    44 using System.Windows.Forms;
    45 using Aga.Controls.Tree;
    46 using Aga.Controls.Tree.NodeControls;
    47 using OpenHardwareMonitor.Hardware;
    48 using OpenHardwareMonitor.WMI;
    49 
    50 namespace OpenHardwareMonitor.GUI {
    51   public partial class MainForm : Form {
    52 
    53     private PersistentSettings settings;
    54     private UnitManager unitManager;
    55     private Computer computer;
    56     private Node root;
    57     private TreeModel treeModel;
    58     private IDictionary<ISensor, Color> sensorPlotColors = 
    59       new Dictionary<ISensor, Color>();
    60     private Color[] plotColorPalette;
    61     private SystemTray systemTray;    
    62     private StartupManager startupManager = new StartupManager();
    63     private UpdateVisitor updateVisitor = new UpdateVisitor();
    64     private SensorGadget gadget;
    65     private Form plotForm;
    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     private UserRadioGroup plotLocation;
    79 
    80     private WmiProvider wmiProvider;
    81 
    82     private bool selectionDragging = false;
    83 
    84     public MainForm() {      
    85       InitializeComponent();
    86 
    87       // check if the OpenHardwareMonitorLib assembly has the correct version
    88       if (Assembly.GetAssembly(typeof(Computer)).GetName().Version !=
    89         Assembly.GetExecutingAssembly().GetName().Version) {
    90         MessageBox.Show(
    91           "The version of the file OpenHardwareMonitorLib.dll is incompatible.",
    92           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    93         Environment.Exit(0);
    94       }
    95 
    96       this.settings = new PersistentSettings();      
    97       this.settings.Load(Path.ChangeExtension(
    98         Application.ExecutablePath, ".config"));
    99 
   100       this.unitManager = new UnitManager(settings);
   101 
   102       // set the DockStyle here, to avoid conflicts with the MainMenu
   103       this.splitContainer.Dock = DockStyle.Fill;
   104             
   105       this.Font = SystemFonts.MessageBoxFont;
   106       treeView.Font = SystemFonts.MessageBoxFont;
   107       plotPanel.Font = SystemFonts.MessageBoxFont;           
   108       
   109       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
   110       nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
   111       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
   112       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
   113       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   114       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   115       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   116 
   117       foreach (TreeColumn column in treeView.Columns) 
   118         column.Width = Math.Max(20, Math.Min(400,
   119           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   120           column.Width)));
   121 
   122       treeModel = new TreeModel();
   123       root = new Node(System.Environment.MachineName);
   124       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   125       
   126       treeModel.Nodes.Add(root);
   127       treeView.Model = treeModel;
   128 
   129       this.computer = new Computer(settings);
   130 
   131       systemTray = new SystemTray(computer, settings);
   132       systemTray.HideShowCommand += hideShowClick;
   133       systemTray.ExitCommand += exitClick;
   134 
   135       int p = (int)Environment.OSVersion.Platform;
   136       if ((p == 4) || (p == 128)) { // Unix
   137         treeView.RowHeight = Math.Max(treeView.RowHeight, 18); 
   138         splitContainer.BorderStyle = BorderStyle.None;
   139         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   140         splitContainer.SplitterWidth = 4;
   141         treeView.BorderStyle = BorderStyle.Fixed3D;
   142         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   143         gadgetMenuItem.Visible = false;
   144         minCloseMenuItem.Visible = false;
   145         minTrayMenuItem.Visible = false;
   146         startMinMenuItem.Visible = false;
   147       } else { // Windows
   148         treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18); 
   149 
   150         gadget = new SensorGadget(computer, settings, unitManager);
   151         gadget.HideShowCommand += hideShowClick;
   152 
   153         wmiProvider = new WmiProvider(computer);
   154       }    
   155       
   156       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   157       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);        
   158 
   159       computer.Open();
   160 
   161       timer.Enabled = true;
   162 
   163       plotColorPalette = new Color[13];
   164       plotColorPalette[0] = Color.Blue;
   165       plotColorPalette[1] = Color.OrangeRed;
   166       plotColorPalette[2] = Color.Green;
   167       plotColorPalette[3] = Color.LightSeaGreen;
   168       plotColorPalette[4] = Color.Goldenrod;
   169       plotColorPalette[5] = Color.DarkViolet;
   170       plotColorPalette[6] = Color.YellowGreen;
   171       plotColorPalette[7] = Color.SaddleBrown;
   172       plotColorPalette[8] = Color.RoyalBlue;
   173       plotColorPalette[9] = Color.DeepPink;
   174       plotColorPalette[10] = Color.MediumSeaGreen;
   175       plotColorPalette[11] = Color.Olive;
   176       plotColorPalette[12] = Color.Firebrick;
   177 
   178       showHiddenSensors = new UserOption("hiddenMenuItem", false,
   179         hiddenMenuItem, settings);
   180       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   181         treeModel.ForceVisible = showHiddenSensors.Value;
   182       };
   183 
   184       showValue = new UserOption("valueMenuItem", true, valueMenuItem,
   185         settings);
   186       showValue.Changed += delegate(object sender, EventArgs e) {
   187         treeView.Columns[1].IsVisible = showValue.Value;
   188       };
   189 
   190       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   191       showMin.Changed += delegate(object sender, EventArgs e) {
   192         treeView.Columns[2].IsVisible = showMin.Value;
   193       };
   194 
   195       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   196       showMax.Changed += delegate(object sender, EventArgs e) {
   197         treeView.Columns[3].IsVisible = showMax.Value;
   198       };
   199 
   200       startMinimized = new UserOption("startMinMenuItem", false,
   201         startMinMenuItem, settings);
   202 
   203       minimizeToTray = new UserOption("minTrayMenuItem", true,
   204         minTrayMenuItem, settings);
   205       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   206         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   207       };
   208 
   209       minimizeOnClose = new UserOption("minCloseMenuItem", false,
   210         minCloseMenuItem, settings);
   211 
   212       autoStart = new UserOption(null, startupManager.Startup,
   213         startupMenuItem, settings);
   214       autoStart.Changed += delegate(object sender, EventArgs e) {
   215         try {
   216           startupManager.Startup = autoStart.Value;
   217         } catch (InvalidOperationException) {
   218           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   219             MessageBoxButtons.OK, MessageBoxIcon.Error);
   220           autoStart.Value = startupManager.Startup;
   221         }
   222       };
   223 
   224       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
   225         settings);
   226       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   227         computer.HDDEnabled = readHddSensors.Value;
   228         UpdatePlotSelection(null, null);
   229       };
   230 
   231       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
   232         settings);
   233       showGadget.Changed += delegate(object sender, EventArgs e) {
   234         if (gadget != null) 
   235           gadget.Visible = showGadget.Value;
   236       };
   237 
   238       celciusMenuItem.Checked = 
   239         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   240       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   241 
   242       InitializePlotForm();
   243 
   244       startupMenuItem.Visible = startupManager.IsAvailable;
   245       
   246       if (startMinMenuItem.Checked) {
   247         if (!minTrayMenuItem.Checked) {
   248           WindowState = FormWindowState.Minimized;
   249           Show();
   250         }
   251       } else {
   252         Show();
   253       }
   254 
   255       // Create a handle, otherwise calling Close() does not fire FormClosed     
   256       IntPtr handle = Handle;
   257 
   258       // Make sure the settings are saved when the user logs off
   259       Microsoft.Win32.SystemEvents.SessionEnded += delegate {
   260         SaveConfiguration();
   261       };  
   262     }
   263 
   264     private void InitializePlotForm() {
   265       plotForm = new Form();
   266       plotForm.FormBorderStyle = FormBorderStyle.SizableToolWindow;
   267       plotForm.ShowInTaskbar = false;
   268       plotForm.StartPosition = FormStartPosition.Manual;
   269       this.AddOwnedForm(plotForm);
   270       plotForm.Bounds = new Rectangle {
   271         X = settings.GetValue("plotForm.Location.X", -100000),
   272         Y = settings.GetValue("plotForm.Location.Y", 100),
   273         Width = settings.GetValue("plotForm.Width", 600),
   274         Height = settings.GetValue("plotForm.Height", 400)
   275       };
   276 
   277       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   278       plotLocation = new UserRadioGroup("plotLocation", 0,
   279         new[] { plotWindowMenuItem, plotBottomMenuItem, plotRightMenuItem },
   280         settings);
   281 
   282       showPlot.Changed += delegate(object sender, EventArgs e) {
   283         if (plotLocation.Value == 0) {
   284           if (showPlot.Value && this.Visible)
   285             plotForm.Show();
   286           else
   287             plotForm.Hide();
   288         } else {
   289           splitContainer.Panel2Collapsed = !showPlot.Value;
   290         }
   291         treeView.Invalidate();
   292       };
   293       plotLocation.Changed += delegate(object sender, EventArgs e) {
   294         switch (plotLocation.Value) {
   295           case 0:
   296             splitContainer.Panel2.Controls.Clear();
   297             splitContainer.Panel2Collapsed = true;
   298             plotForm.Controls.Add(plotPanel);
   299             if (showPlot.Value && this.Visible)
   300               plotForm.Show();
   301             break;
   302           case 1:
   303             plotForm.Controls.Clear();
   304             plotForm.Hide();
   305             splitContainer.Orientation = Orientation.Horizontal;
   306             splitContainer.Panel2.Controls.Add(plotPanel);
   307             splitContainer.Panel2Collapsed = !showPlot.Value;
   308             break;
   309           case 2:
   310             plotForm.Controls.Clear();
   311             plotForm.Hide();
   312             splitContainer.Orientation = Orientation.Vertical;
   313             splitContainer.Panel2.Controls.Add(plotPanel);
   314             splitContainer.Panel2Collapsed = !showPlot.Value;
   315             break;
   316         }
   317       };
   318 
   319       plotForm.FormClosing += delegate(object sender, FormClosingEventArgs e) {
   320         if (e.CloseReason == CloseReason.UserClosing) {
   321           // just switch off the plotting when the user closes the form
   322           if (plotLocation.Value == 0) {
   323             showPlot.Value = false;
   324           }
   325           e.Cancel = true;
   326         }
   327       };
   328 
   329       EventHandler moveOrResizePlotForm = delegate(object sender, EventArgs e) {
   330         if (plotForm.WindowState != FormWindowState.Minimized) {
   331           settings.SetValue("plotForm.Location.X", plotForm.Bounds.X);
   332           settings.SetValue("plotForm.Location.Y", plotForm.Bounds.Y);
   333           settings.SetValue("plotForm.Width", plotForm.Bounds.Width);
   334           settings.SetValue("plotForm.Height", plotForm.Bounds.Height);
   335         }
   336       };
   337       plotForm.Move += moveOrResizePlotForm;
   338       plotForm.Resize += moveOrResizePlotForm;
   339 
   340       plotForm.VisibleChanged += delegate(object sender, EventArgs e) {
   341         Rectangle bounds = new Rectangle(plotForm.Location, plotForm.Size);
   342         Screen screen = Screen.FromRectangle(bounds);
   343         Rectangle intersection =
   344           Rectangle.Intersect(screen.WorkingArea, bounds);
   345         if (intersection.Width < Math.Min(16, bounds.Width) ||
   346             intersection.Height < Math.Min(16, bounds.Height)) {
   347           plotForm.Location = new Point(
   348             screen.WorkingArea.Width / 2 - bounds.Width / 2,
   349             screen.WorkingArea.Height / 2 - bounds.Height / 2);
   350         }
   351       };
   352 
   353       this.VisibleChanged += delegate(object sender, EventArgs e) {
   354         if (this.Visible && showPlot.Value && plotLocation.Value == 0)
   355           plotForm.Show();
   356         else
   357           plotForm.Hide();
   358       };
   359     }
   360     
   361     private void SubHardwareAdded(IHardware hardware, Node node) {
   362       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   363       node.Nodes.Add(hardwareNode);
   364       foreach (IHardware subHardware in hardware.SubHardware)
   365         SubHardwareAdded(subHardware, hardwareNode);  
   366     }
   367 
   368     private void HardwareAdded(IHardware hardware) {
   369       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   370       root.Nodes.Add(hardwareNode);
   371       foreach (IHardware subHardware in hardware.SubHardware)
   372         SubHardwareAdded(subHardware, hardwareNode);     
   373     }
   374 
   375     private void HardwareRemoved(IHardware hardware) {      
   376       List<Node> nodesToRemove = new List<Node>();
   377       foreach (Node node in root.Nodes) {
   378         HardwareNode hardwareNode = node as HardwareNode;
   379         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   380           nodesToRemove.Add(node);
   381       }
   382       foreach (Node node in nodesToRemove)
   383         root.Nodes.Remove(node);
   384     }
   385 
   386     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   387       Node node = e.Node.Tag as Node;
   388       if (node != null) {
   389         Color color;
   390         if (node.IsVisible) {
   391           SensorNode sensorNode = node as SensorNode;
   392           if (plotMenuItem.Checked && sensorNode != null &&
   393             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   394             e.TextColor = color;
   395         } else {
   396           e.TextColor = Color.DarkGray;
   397         }
   398       }
   399     }
   400 
   401     private void UpdatePlotSelection(object sender, 
   402       TreePathEventArgs e) 
   403     {
   404       List<ISensor> selected = new List<ISensor>();
   405       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   406       int colorIndex = 0;
   407       foreach (TreeNodeAdv node in treeView.AllNodes) {
   408         SensorNode sensorNode = node.Tag as SensorNode;
   409         if (sensorNode != null && 
   410           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   411           if (sensorNode.Plot) {
   412             colors.Add(sensorNode.Sensor,
   413               plotColorPalette[colorIndex % plotColorPalette.Length]);
   414             selected.Add(sensorNode.Sensor);
   415           }
   416           colorIndex++;
   417         }
   418       }
   419       sensorPlotColors = colors;
   420       plotPanel.SetSensors(selected, colors);
   421     }
   422 
   423     private void nodeTextBoxText_EditorShowing(object sender,
   424       CancelEventArgs e) 
   425     {
   426       e.Cancel = !(treeView.CurrentNode != null &&
   427         (treeView.CurrentNode.Tag is SensorNode || 
   428          treeView.CurrentNode.Tag is HardwareNode));
   429     }
   430 
   431     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   432       NodeControlValueEventArgs e) {
   433       SensorNode node = e.Node.Tag as SensorNode;
   434       e.Value = (node != null) && 
   435         (node.Sensor.SensorType == SensorType.Temperature) && 
   436         plotMenuItem.Checked;
   437     }
   438 
   439     private void exitClick(object sender, EventArgs e) {
   440       Close();
   441     }
   442 
   443     private void timer_Tick(object sender, EventArgs e) {
   444       computer.Accept(updateVisitor);
   445       treeView.Invalidate();
   446       plotPanel.Invalidate();
   447       systemTray.Redraw();
   448       if (gadget != null)
   449         gadget.Redraw();
   450 
   451       if (wmiProvider != null)
   452         wmiProvider.Update();
   453     }
   454 
   455     private void SaveConfiguration() {
   456       foreach (TreeColumn column in treeView.Columns)
   457         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   458           column.Width);
   459 
   460       string fileName = Path.ChangeExtension(
   461           System.Windows.Forms.Application.ExecutablePath, ".config");
   462       try {
   463         settings.Save(fileName);
   464       } catch (UnauthorizedAccessException) {
   465         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
   466           "The current settings could not be saved.",
   467           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   468       } catch (IOException) {
   469         MessageBox.Show("The path '" + fileName + "' is not writeable. " +
   470           "The current settings could not be saved.",
   471           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   472       }
   473     }
   474 
   475     private void MainForm_Load(object sender, EventArgs e) {
   476       Rectangle newBounds = new Rectangle {
   477         X = settings.GetValue("mainForm.Location.X", Location.X),
   478         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   479         Width = settings.GetValue("mainForm.Width", 470),
   480         Height = settings.GetValue("mainForm.Height", 640)
   481       };
   482 
   483       Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   484         int.MinValue, int.MinValue);
   485 
   486       foreach (Screen screen in Screen.AllScreens)
   487         fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
   488 
   489       Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
   490       if (intersection.Width < 20 || intersection.Height < 20 ||
   491         !settings.Contains("mainForm.Location.X")
   492       ) {
   493         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
   494                       (newBounds.Width/2);
   495 
   496         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
   497                       (newBounds.Height / 2);
   498       }
   499 
   500       this.Bounds = newBounds;
   501     }
   502     
   503     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   504       Visible = false;      
   505       systemTray.IsMainIconEnabled = false;
   506       timer.Enabled = false;            
   507       computer.Close();
   508       SaveConfiguration();
   509       systemTray.Dispose();
   510     }
   511 
   512     private void aboutMenuItem_Click(object sender, EventArgs e) {
   513       new AboutBox().ShowDialog();
   514     }
   515 
   516     private void treeView_Click(object sender, EventArgs e) {
   517 
   518       MouseEventArgs m = e as MouseEventArgs;
   519       if (m == null || m.Button != MouseButtons.Right)
   520         return;
   521 
   522       NodeControlInfo info = treeView.GetNodeControlInfoAt(
   523         new Point(m.X, m.Y)
   524       );
   525       treeView.SelectedNode = info.Node;
   526       if (info.Node != null) {
   527         SensorNode node = info.Node.Tag as SensorNode;
   528         if (node != null && node.Sensor != null) {
   529           treeContextMenu.MenuItems.Clear();
   530           if (node.Sensor.Parameters.Length > 0) {
   531             MenuItem item = new MenuItem("Parameters...");
   532             item.Click += delegate(object obj, EventArgs args) {
   533               ShowParameterForm(node.Sensor);
   534             };
   535             treeContextMenu.MenuItems.Add(item);
   536           }
   537           if (nodeTextBoxText.EditEnabled) {
   538             MenuItem item = new MenuItem("Rename");
   539             item.Click += delegate(object obj, EventArgs args) {
   540               nodeTextBoxText.BeginEdit();
   541             };
   542             treeContextMenu.MenuItems.Add(item);
   543           }
   544           if (node.IsVisible) {
   545             MenuItem item = new MenuItem("Hide");
   546             item.Click += delegate(object obj, EventArgs args) {
   547               node.IsVisible = false;
   548             };
   549             treeContextMenu.MenuItems.Add(item);
   550           } else {
   551             MenuItem item = new MenuItem("Unhide");
   552             item.Click += delegate(object obj, EventArgs args) {
   553               node.IsVisible = true;
   554             };
   555             treeContextMenu.MenuItems.Add(item);
   556           }
   557           treeContextMenu.MenuItems.Add(new MenuItem("-"));
   558           {
   559             MenuItem item = new MenuItem("Show in Tray");
   560             item.Checked = systemTray.Contains(node.Sensor);
   561             item.Click += delegate(object obj, EventArgs args) {
   562               if (item.Checked)
   563                 systemTray.Remove(node.Sensor);
   564               else
   565                 systemTray.Add(node.Sensor, true);
   566             };
   567             treeContextMenu.MenuItems.Add(item);
   568           }
   569           if (gadget != null) {
   570             MenuItem item = new MenuItem("Show in Gadget");
   571             item.Checked = gadget.Contains(node.Sensor);
   572             item.Click += delegate(object obj, EventArgs args) {
   573               if (item.Checked) {
   574                 gadget.Remove(node.Sensor);
   575               } else {
   576                 gadget.Add(node.Sensor);
   577               }
   578             };
   579             treeContextMenu.MenuItems.Add(item);
   580           }
   581           if (node.Sensor.Control != null) {
   582             treeContextMenu.MenuItems.Add(new MenuItem("-"));
   583             IControl control = node.Sensor.Control;
   584             MenuItem controlItem = new MenuItem("Control");
   585             MenuItem defaultItem = new MenuItem("Default");
   586             defaultItem.Checked = control.ControlMode == ControlMode.Default;
   587             controlItem.MenuItems.Add(defaultItem);
   588             defaultItem.Click += delegate(object obj, EventArgs args) {
   589               control.SetDefault();
   590             };
   591             MenuItem manualItem = new MenuItem("Manual");
   592             controlItem.MenuItems.Add(manualItem);
   593             manualItem.Checked = control.ControlMode == ControlMode.Software;
   594             for (int i = 0; i <= 100; i += 5) {
   595               if (i <= control.MaxSoftwareValue &&
   596                   i >= control.MinSoftwareValue) {
   597                 MenuItem item = new MenuItem(i + " %");
   598                 manualItem.MenuItems.Add(item);
   599                 item.Checked = control.ControlMode == ControlMode.Software &&
   600                   Math.Round(control.SoftwareValue) == i;
   601                 int softwareValue = i;
   602                 item.Click += delegate(object obj, EventArgs args) {
   603                   control.SetSoftware(softwareValue);
   604                 };
   605               }
   606             }
   607             treeContextMenu.MenuItems.Add(controlItem);
   608           }
   609 
   610           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   611         }
   612 
   613         HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
   614         if (hardwareNode != null && hardwareNode.Hardware != null) {
   615           treeContextMenu.MenuItems.Clear();
   616 
   617           if (nodeTextBoxText.EditEnabled) {
   618             MenuItem item = new MenuItem("Rename");
   619             item.Click += delegate(object obj, EventArgs args) {
   620               nodeTextBoxText.BeginEdit();
   621             };
   622             treeContextMenu.MenuItems.Add(item);
   623           }
   624 
   625           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   626         }
   627       }
   628     }
   629 
   630     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   631       string report = computer.GetReport();
   632       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   633         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   634           w.Write(report);
   635         }
   636       }
   637     }
   638 
   639     private void SysTrayHideShow() {
   640       Visible = !Visible;
   641       if (Visible)
   642         Activate();    
   643     }
   644 
   645     protected override void WndProc(ref Message m) {
   646       const int WM_SYSCOMMAND = 0x112;
   647       const int SC_MINIMIZE = 0xF020;
   648       const int SC_CLOSE = 0xF060;
   649 
   650       if (minimizeToTray.Value && 
   651         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   652         SysTrayHideShow();
   653       } else if(minimizeOnClose.Value && 
   654         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   655         /*
   656          * Apparently the user wants to minimize rather than close
   657          * Now we still need to check if we're going to the tray or not
   658          * 
   659          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   660          * but since the code here is so simple,
   661          * that would just be a waste of time.
   662          */
   663         if (minimizeToTray.Value)
   664           SysTrayHideShow();
   665         else
   666           WindowState = FormWindowState.Minimized;
   667       } else {      
   668         base.WndProc(ref m);
   669       }
   670     }
   671 
   672     private void hideShowClick(object sender, EventArgs e) {
   673       SysTrayHideShow();
   674     }
   675 
   676     private void ShowParameterForm(ISensor sensor) {
   677       ParameterForm form = new ParameterForm();
   678       form.Parameters = sensor.Parameters;
   679       form.captionLabel.Text = sensor.Name;
   680       form.ShowDialog();
   681     }
   682 
   683     private void treeView_NodeMouseDoubleClick(object sender, 
   684       TreeNodeAdvMouseEventArgs e) {
   685       SensorNode node = e.Node.Tag as SensorNode;
   686       if (node != null && node.Sensor != null && 
   687         node.Sensor.Parameters.Length > 0) {
   688         ShowParameterForm(node.Sensor);
   689       }
   690     }
   691 
   692     private void celciusMenuItem_Click(object sender, EventArgs e) {
   693       celciusMenuItem.Checked = true;
   694       fahrenheitMenuItem.Checked = false;
   695       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   696     }
   697 
   698     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   699       celciusMenuItem.Checked = false;
   700       fahrenheitMenuItem.Checked = true;
   701       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   702     }
   703 
   704     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   705     {
   706       ReportForm form = new ReportForm();
   707       form.Report = computer.GetReport();
   708       form.ShowDialog();      
   709     }
   710 
   711     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   712       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   713         sensor.ResetMin();
   714         sensor.ResetMax();
   715       }));
   716     }
   717 
   718     private void MainForm_MoveOrResize(object sender, EventArgs e) {
   719       if (WindowState != FormWindowState.Minimized) {
   720         settings.SetValue("mainForm.Location.X", Bounds.X);
   721         settings.SetValue("mainForm.Location.Y", Bounds.Y);
   722         settings.SetValue("mainForm.Width", Bounds.Width);
   723         settings.SetValue("mainForm.Height", Bounds.Height);
   724       }
   725     }
   726 
   727     private void resetClick(object sender, EventArgs e) {
   728       // disable the fallback MainIcon during reset, otherwise icon visibility
   729       // might be lost 
   730       systemTray.IsMainIconEnabled = false;
   731       computer.Close();
   732       computer.Open();
   733       // restore the MainIcon setting
   734       systemTray.IsMainIconEnabled = minimizeToTray.Value;
   735     }
   736 
   737     private void treeView_MouseMove(object sender, MouseEventArgs e) {
   738       selectionDragging = selectionDragging &
   739         (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0; 
   740 
   741       if (selectionDragging)
   742         treeView.SelectedNode = treeView.GetNodeAt(e.Location);     
   743     }
   744 
   745     private void treeView_MouseDown(object sender, MouseEventArgs e) {
   746       selectionDragging = true;
   747     }
   748 
   749     private void treeView_MouseUp(object sender, MouseEventArgs e) {
   750       selectionDragging = false;
   751     }
   752   }
   753 }