GUI/MainForm.cs
author moel.mich
Sun, 22 May 2011 19:15:27 +0000
changeset 295 a1c06df9928d
parent 291 61c3d984fb2d
child 297 21504f47aedf
permissions -rw-r--r--
Added an option to show the plot in a separate window or on the right of the tree-view.
     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       plotForm.Closing += delegate(object sender, CancelEventArgs e) {
   319         if (plotLocation.Value == 0) {
   320           showPlot.Value = false;
   321         }
   322         e.Cancel = true;
   323       };
   324       EventHandler moveOrResizePlotForm = delegate(object sender, EventArgs e) {
   325         if (plotForm.WindowState != FormWindowState.Minimized) {
   326           settings.SetValue("plotForm.Location.X", plotForm.Bounds.X);
   327           settings.SetValue("plotForm.Location.Y", plotForm.Bounds.Y);
   328           settings.SetValue("plotForm.Width", plotForm.Bounds.Width);
   329           settings.SetValue("plotForm.Height", plotForm.Bounds.Height);
   330         }
   331       };
   332       plotForm.Move += moveOrResizePlotForm;
   333       plotForm.Resize += moveOrResizePlotForm;
   334 
   335       plotForm.VisibleChanged += delegate(object sender, EventArgs e) {
   336         Rectangle bounds = new Rectangle(plotForm.Location, plotForm.Size);
   337         Screen screen = Screen.FromRectangle(bounds);
   338         Rectangle intersection =
   339           Rectangle.Intersect(screen.WorkingArea, bounds);
   340         if (intersection.Width < Math.Min(16, bounds.Width) ||
   341             intersection.Height < Math.Min(16, bounds.Height)) {
   342           plotForm.Location = new Point(
   343             screen.WorkingArea.Width / 2 - bounds.Width / 2,
   344             screen.WorkingArea.Height / 2 - bounds.Height / 2);
   345         }
   346       };
   347 
   348       this.VisibleChanged += delegate(object sender, EventArgs e) {
   349         if (this.Visible && showPlot.Value && plotLocation.Value == 0)
   350           plotForm.Show();
   351         else
   352           plotForm.Hide();
   353       };
   354     }
   355     
   356     private void SubHardwareAdded(IHardware hardware, Node node) {
   357       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   358       node.Nodes.Add(hardwareNode);
   359       foreach (IHardware subHardware in hardware.SubHardware)
   360         SubHardwareAdded(subHardware, hardwareNode);  
   361     }
   362 
   363     private void HardwareAdded(IHardware hardware) {
   364       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   365       root.Nodes.Add(hardwareNode);
   366       foreach (IHardware subHardware in hardware.SubHardware)
   367         SubHardwareAdded(subHardware, hardwareNode);     
   368     }
   369 
   370     private void HardwareRemoved(IHardware hardware) {      
   371       List<Node> nodesToRemove = new List<Node>();
   372       foreach (Node node in root.Nodes) {
   373         HardwareNode hardwareNode = node as HardwareNode;
   374         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   375           nodesToRemove.Add(node);
   376       }
   377       foreach (Node node in nodesToRemove)
   378         root.Nodes.Remove(node);
   379     }
   380 
   381     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   382       Node node = e.Node.Tag as Node;
   383       if (node != null) {
   384         Color color;
   385         if (node.IsVisible) {
   386           SensorNode sensorNode = node as SensorNode;
   387           if (plotMenuItem.Checked && sensorNode != null &&
   388             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   389             e.TextColor = color;
   390         } else {
   391           e.TextColor = Color.DarkGray;
   392         }
   393       }
   394     }
   395 
   396     private void UpdatePlotSelection(object sender, 
   397       TreePathEventArgs e) 
   398     {
   399       List<ISensor> selected = new List<ISensor>();
   400       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   401       int colorIndex = 0;
   402       foreach (TreeNodeAdv node in treeView.AllNodes) {
   403         SensorNode sensorNode = node.Tag as SensorNode;
   404         if (sensorNode != null && 
   405           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   406           if (sensorNode.Plot) {
   407             colors.Add(sensorNode.Sensor,
   408               plotColorPalette[colorIndex % plotColorPalette.Length]);
   409             selected.Add(sensorNode.Sensor);
   410           }
   411           colorIndex++;
   412         }
   413       }
   414       sensorPlotColors = colors;
   415       plotPanel.SetSensors(selected, colors);
   416     }
   417 
   418     private void nodeTextBoxText_EditorShowing(object sender,
   419       CancelEventArgs e) 
   420     {
   421       e.Cancel = !(treeView.CurrentNode != null &&
   422         (treeView.CurrentNode.Tag is SensorNode || 
   423          treeView.CurrentNode.Tag is HardwareNode));
   424     }
   425 
   426     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   427       NodeControlValueEventArgs e) {
   428       SensorNode node = e.Node.Tag as SensorNode;
   429       e.Value = (node != null) && 
   430         (node.Sensor.SensorType == SensorType.Temperature) && 
   431         plotMenuItem.Checked;
   432     }
   433 
   434     private void exitClick(object sender, EventArgs e) {
   435       Close();
   436     }
   437 
   438     private void timer_Tick(object sender, EventArgs e) {
   439       computer.Accept(updateVisitor);
   440       treeView.Invalidate();
   441       plotPanel.Invalidate();
   442       systemTray.Redraw();
   443       if (gadget != null)
   444         gadget.Redraw();
   445 
   446       if (wmiProvider != null)
   447         wmiProvider.Update();
   448     }
   449 
   450     private void SaveConfiguration() {
   451       foreach (TreeColumn column in treeView.Columns)
   452         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   453           column.Width);
   454 
   455       string fileName = Path.ChangeExtension(
   456           System.Windows.Forms.Application.ExecutablePath, ".config");
   457       try {
   458         settings.Save(fileName);
   459       } catch (UnauthorizedAccessException) {
   460         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
   461           "The current settings could not be saved.",
   462           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   463       } catch (IOException) {
   464         MessageBox.Show("The path '" + fileName + "' is not writeable. " +
   465           "The current settings could not be saved.",
   466           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   467       }
   468     }
   469 
   470     private void MainForm_Load(object sender, EventArgs e) {
   471       Rectangle newBounds = new Rectangle {
   472         X = settings.GetValue("mainForm.Location.X", Location.X),
   473         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   474         Width = settings.GetValue("mainForm.Width", 470),
   475         Height = settings.GetValue("mainForm.Height", 640)
   476       };
   477 
   478       Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   479         int.MinValue, int.MinValue);
   480 
   481       foreach (Screen screen in Screen.AllScreens)
   482         fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
   483 
   484       Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
   485       if (intersection.Width < 20 || intersection.Height < 20 ||
   486         !settings.Contains("mainForm.Location.X")
   487       ) {
   488         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
   489                       (newBounds.Width/2);
   490 
   491         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
   492                       (newBounds.Height / 2);
   493       }
   494 
   495       this.Bounds = newBounds;
   496     }
   497     
   498     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   499       Visible = false;
   500       SaveConfiguration();
   501 
   502       systemTray.IsMainIconEnabled = false;
   503       timer.Enabled = false;            
   504       computer.Close();
   505       systemTray.Dispose();
   506     }
   507 
   508     private void aboutMenuItem_Click(object sender, EventArgs e) {
   509       new AboutBox().ShowDialog();
   510     }
   511 
   512     private void treeView_Click(object sender, EventArgs e) {
   513 
   514       MouseEventArgs m = e as MouseEventArgs;
   515       if (m == null || m.Button != MouseButtons.Right)
   516         return;
   517 
   518       NodeControlInfo info = treeView.GetNodeControlInfoAt(
   519         new Point(m.X, m.Y)
   520       );
   521       treeView.SelectedNode = info.Node;
   522       if (info.Node != null) {
   523         SensorNode node = info.Node.Tag as SensorNode;
   524         if (node != null && node.Sensor != null) {
   525           treeContextMenu.MenuItems.Clear();
   526           if (node.Sensor.Parameters.Length > 0) {
   527             MenuItem item = new MenuItem("Parameters...");
   528             item.Click += delegate(object obj, EventArgs args) {
   529               ShowParameterForm(node.Sensor);
   530             };
   531             treeContextMenu.MenuItems.Add(item);
   532           }
   533           if (nodeTextBoxText.EditEnabled) {
   534             MenuItem item = new MenuItem("Rename");
   535             item.Click += delegate(object obj, EventArgs args) {
   536               nodeTextBoxText.BeginEdit();
   537             };
   538             treeContextMenu.MenuItems.Add(item);
   539           }
   540           if (node.IsVisible) {
   541             MenuItem item = new MenuItem("Hide");
   542             item.Click += delegate(object obj, EventArgs args) {
   543               node.IsVisible = false;
   544             };
   545             treeContextMenu.MenuItems.Add(item);
   546           } else {
   547             MenuItem item = new MenuItem("Unhide");
   548             item.Click += delegate(object obj, EventArgs args) {
   549               node.IsVisible = true;
   550             };
   551             treeContextMenu.MenuItems.Add(item);
   552           }
   553           treeContextMenu.MenuItems.Add(new MenuItem("-"));
   554           {
   555             MenuItem item = new MenuItem("Show in Tray");
   556             item.Checked = systemTray.Contains(node.Sensor);
   557             item.Click += delegate(object obj, EventArgs args) {
   558               if (item.Checked)
   559                 systemTray.Remove(node.Sensor);
   560               else
   561                 systemTray.Add(node.Sensor, true);
   562             };
   563             treeContextMenu.MenuItems.Add(item);
   564           }
   565           if (gadget != null) {
   566             MenuItem item = new MenuItem("Show in Gadget");
   567             item.Checked = gadget.Contains(node.Sensor);
   568             item.Click += delegate(object obj, EventArgs args) {
   569               if (item.Checked) {
   570                 gadget.Remove(node.Sensor);
   571               } else {
   572                 gadget.Add(node.Sensor);
   573               }
   574             };
   575             treeContextMenu.MenuItems.Add(item);
   576           }
   577           if (node.Sensor.Control != null) {
   578             treeContextMenu.MenuItems.Add(new MenuItem("-"));
   579             IControl control = node.Sensor.Control;
   580             MenuItem controlItem = new MenuItem("Control");
   581             MenuItem defaultItem = new MenuItem("Default");
   582             defaultItem.Checked = control.ControlMode == ControlMode.Default;
   583             controlItem.MenuItems.Add(defaultItem);
   584             defaultItem.Click += delegate(object obj, EventArgs args) {
   585               control.SetDefault();
   586             };
   587             MenuItem manualItem = new MenuItem("Manual");
   588             controlItem.MenuItems.Add(manualItem);
   589             manualItem.Checked = control.ControlMode == ControlMode.Software;
   590             for (int i = 0; i <= 100; i += 5) {
   591               if (i <= control.MaxSoftwareValue &&
   592                   i >= control.MinSoftwareValue) {
   593                 MenuItem item = new MenuItem(i + " %");
   594                 manualItem.MenuItems.Add(item);
   595                 item.Checked = control.ControlMode == ControlMode.Software &&
   596                   Math.Round(control.SoftwareValue) == i;
   597                 int softwareValue = i;
   598                 item.Click += delegate(object obj, EventArgs args) {
   599                   control.SetSoftware(softwareValue);
   600                 };
   601               }
   602             }
   603             treeContextMenu.MenuItems.Add(controlItem);
   604           }
   605 
   606           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   607         }
   608 
   609         HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
   610         if (hardwareNode != null && hardwareNode.Hardware != null) {
   611           treeContextMenu.MenuItems.Clear();
   612 
   613           if (nodeTextBoxText.EditEnabled) {
   614             MenuItem item = new MenuItem("Rename");
   615             item.Click += delegate(object obj, EventArgs args) {
   616               nodeTextBoxText.BeginEdit();
   617             };
   618             treeContextMenu.MenuItems.Add(item);
   619           }
   620 
   621           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   622         }
   623       }
   624     }
   625 
   626     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   627       string report = computer.GetReport();
   628       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   629         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   630           w.Write(report);
   631         }
   632       }
   633     }
   634 
   635     private void SysTrayHideShow() {
   636       Visible = !Visible;
   637       if (Visible)
   638         Activate();    
   639     }
   640 
   641     protected override void WndProc(ref Message m) {
   642       const int WM_SYSCOMMAND = 0x112;
   643       const int SC_MINIMIZE = 0xF020;
   644       const int SC_CLOSE = 0xF060;
   645 
   646       if (minimizeToTray.Value && 
   647         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   648         SysTrayHideShow();
   649       } else if(minimizeOnClose.Value && 
   650         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   651         /*
   652          * Apparently the user wants to minimize rather than close
   653          * Now we still need to check if we're going to the tray or not
   654          * 
   655          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   656          * but since the code here is so simple,
   657          * that would just be a waste of time.
   658          */
   659         if (minimizeToTray.Value)
   660           SysTrayHideShow();
   661         else
   662           WindowState = FormWindowState.Minimized;
   663       } else {      
   664         base.WndProc(ref m);
   665       }
   666     }
   667 
   668     private void hideShowClick(object sender, EventArgs e) {
   669       SysTrayHideShow();
   670     }
   671 
   672     private void ShowParameterForm(ISensor sensor) {
   673       ParameterForm form = new ParameterForm();
   674       form.Parameters = sensor.Parameters;
   675       form.captionLabel.Text = sensor.Name;
   676       form.ShowDialog();
   677     }
   678 
   679     private void treeView_NodeMouseDoubleClick(object sender, 
   680       TreeNodeAdvMouseEventArgs e) {
   681       SensorNode node = e.Node.Tag as SensorNode;
   682       if (node != null && node.Sensor != null && 
   683         node.Sensor.Parameters.Length > 0) {
   684         ShowParameterForm(node.Sensor);
   685       }
   686     }
   687 
   688     private void celciusMenuItem_Click(object sender, EventArgs e) {
   689       celciusMenuItem.Checked = true;
   690       fahrenheitMenuItem.Checked = false;
   691       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   692     }
   693 
   694     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   695       celciusMenuItem.Checked = false;
   696       fahrenheitMenuItem.Checked = true;
   697       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   698     }
   699 
   700     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   701     {
   702       ReportForm form = new ReportForm();
   703       form.Report = computer.GetReport();
   704       form.ShowDialog();      
   705     }
   706 
   707     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   708       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   709         sensor.ResetMin();
   710         sensor.ResetMax();
   711       }));
   712     }
   713 
   714     private void MainForm_MoveOrResize(object sender, EventArgs e) {
   715       if (WindowState != FormWindowState.Minimized) {
   716         settings.SetValue("mainForm.Location.X", Bounds.X);
   717         settings.SetValue("mainForm.Location.Y", Bounds.Y);
   718         settings.SetValue("mainForm.Width", Bounds.Width);
   719         settings.SetValue("mainForm.Height", Bounds.Height);
   720       }
   721     }
   722 
   723     private void resetClick(object sender, EventArgs e) {
   724       // disable the fallback MainIcon during reset, otherwise icon visibility
   725       // might be lost 
   726       systemTray.IsMainIconEnabled = false;
   727       computer.Close();
   728       computer.Open();
   729       // restore the MainIcon setting
   730       systemTray.IsMainIconEnabled = minimizeToTray.Value;
   731     }
   732 
   733     private void treeView_MouseMove(object sender, MouseEventArgs e) {
   734       selectionDragging = selectionDragging &
   735         (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0; 
   736 
   737       if (selectionDragging)
   738         treeView.SelectedNode = treeView.GetNodeAt(e.Location);     
   739     }
   740 
   741     private void treeView_MouseDown(object sender, MouseEventArgs e) {
   742       selectionDragging = true;
   743     }
   744 
   745     private void treeView_MouseUp(object sender, MouseEventArgs e) {
   746       selectionDragging = false;
   747     }
   748   }
   749 }