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