GUI/MainForm.cs
author moel.mich
Tue, 14 Feb 2012 23:07:55 +0000
changeset 340 600962f8a298
parent 327 e837e1e4b282
child 344 3145aadca3d2
permissions -rw-r--r--
Added a new sensor type "Factor" for dimensionless values (and similar) that are not to be shown as percent ("Level" type). Changed the write amplification sensor to use the new "Factor" sensor type. Added the temperature SMART attribute for Sandforce SSDs as hidden sensor (as it may show fake results on some hardware).
     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-2012
    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       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
   120       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
   121       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   122       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   123       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   124 
   125       foreach (TreeColumn column in treeView.Columns) 
   126         column.Width = Math.Max(20, Math.Min(400,
   127           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   128           column.Width)));
   129 
   130       treeModel = new TreeModel();
   131       root = new Node(System.Environment.MachineName);
   132       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   133       
   134       treeModel.Nodes.Add(root);
   135       treeView.Model = treeModel;
   136 
   137       this.computer = new Computer(settings);
   138 
   139       systemTray = new SystemTray(computer, settings);
   140       systemTray.HideShowCommand += hideShowClick;
   141       systemTray.ExitCommand += exitClick;
   142 
   143       int p = (int)Environment.OSVersion.Platform;
   144       if ((p == 4) || (p == 128)) { // Unix
   145         treeView.RowHeight = Math.Max(treeView.RowHeight, 18); 
   146         splitContainer.BorderStyle = BorderStyle.None;
   147         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   148         splitContainer.SplitterWidth = 4;
   149         treeView.BorderStyle = BorderStyle.Fixed3D;
   150         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   151         gadgetMenuItem.Visible = false;
   152         minCloseMenuItem.Visible = false;
   153         minTrayMenuItem.Visible = false;
   154         startMinMenuItem.Visible = false;
   155       } else { // Windows
   156         treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18); 
   157 
   158         gadget = new SensorGadget(computer, settings, unitManager);
   159         gadget.HideShowCommand += hideShowClick;
   160 
   161         wmiProvider = new WmiProvider(computer);
   162       }
   163 
   164       plotColorPalette = new Color[13];
   165       plotColorPalette[0] = Color.Blue;
   166       plotColorPalette[1] = Color.OrangeRed;
   167       plotColorPalette[2] = Color.Green;
   168       plotColorPalette[3] = Color.LightSeaGreen;
   169       plotColorPalette[4] = Color.Goldenrod;
   170       plotColorPalette[5] = Color.DarkViolet;
   171       plotColorPalette[6] = Color.YellowGreen;
   172       plotColorPalette[7] = Color.SaddleBrown;
   173       plotColorPalette[8] = Color.RoyalBlue;
   174       plotColorPalette[9] = Color.DeepPink;
   175       plotColorPalette[10] = Color.MediumSeaGreen;
   176       plotColorPalette[11] = Color.Olive;
   177       plotColorPalette[12] = Color.Firebrick;
   178       
   179       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   180       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);        
   181 
   182       computer.Open();
   183 
   184       timer.Enabled = true;
   185 
   186       showHiddenSensors = new UserOption("hiddenMenuItem", false,
   187         hiddenMenuItem, settings);
   188       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   189         treeModel.ForceVisible = showHiddenSensors.Value;
   190       };
   191 
   192       showValue = new UserOption("valueMenuItem", true, valueMenuItem,
   193         settings);
   194       showValue.Changed += delegate(object sender, EventArgs e) {
   195         treeView.Columns[1].IsVisible = showValue.Value;
   196       };
   197 
   198       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   199       showMin.Changed += delegate(object sender, EventArgs e) {
   200         treeView.Columns[2].IsVisible = showMin.Value;
   201       };
   202 
   203       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   204       showMax.Changed += delegate(object sender, EventArgs e) {
   205         treeView.Columns[3].IsVisible = showMax.Value;
   206       };
   207 
   208       startMinimized = new UserOption("startMinMenuItem", false,
   209         startMinMenuItem, settings);
   210 
   211       minimizeToTray = new UserOption("minTrayMenuItem", true,
   212         minTrayMenuItem, settings);
   213       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   214         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   215       };
   216 
   217       minimizeOnClose = new UserOption("minCloseMenuItem", false,
   218         minCloseMenuItem, settings);
   219 
   220       autoStart = new UserOption(null, startupManager.Startup,
   221         startupMenuItem, settings);
   222       autoStart.Changed += delegate(object sender, EventArgs e) {
   223         try {
   224           startupManager.Startup = autoStart.Value;
   225         } catch (InvalidOperationException) {
   226           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   227             MessageBoxButtons.OK, MessageBoxIcon.Error);
   228           autoStart.Value = startupManager.Startup;
   229         }
   230       };
   231 
   232       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
   233         settings);
   234       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   235         computer.HDDEnabled = readHddSensors.Value;
   236       };
   237 
   238       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
   239         settings);
   240       showGadget.Changed += delegate(object sender, EventArgs e) {
   241         if (gadget != null) 
   242           gadget.Visible = showGadget.Value;
   243       };
   244 
   245       celsiusMenuItem.Checked = 
   246         unitManager.TemperatureUnit == TemperatureUnit.Celsius;
   247       fahrenheitMenuItem.Checked = !celsiusMenuItem.Checked;
   248 
   249       InitializePlotForm();
   250 
   251       startupMenuItem.Visible = startupManager.IsAvailable;
   252       
   253       if (startMinMenuItem.Checked) {
   254         if (!minTrayMenuItem.Checked) {
   255           WindowState = FormWindowState.Minimized;
   256           Show();
   257         }
   258       } else {
   259         Show();
   260       }
   261 
   262       // Create a handle, otherwise calling Close() does not fire FormClosed     
   263       IntPtr handle = Handle;
   264 
   265       // Make sure the settings are saved when the user logs off
   266       Microsoft.Win32.SystemEvents.SessionEnded += delegate {
   267         SaveConfiguration();
   268       };
   269     }
   270 
   271     private void InitializePlotForm() {
   272       plotForm = new Form();
   273       plotForm.FormBorderStyle = FormBorderStyle.SizableToolWindow;
   274       plotForm.ShowInTaskbar = false;
   275       plotForm.StartPosition = FormStartPosition.Manual;
   276       this.AddOwnedForm(plotForm);
   277       plotForm.Bounds = new Rectangle {
   278         X = settings.GetValue("plotForm.Location.X", -100000),
   279         Y = settings.GetValue("plotForm.Location.Y", 100),
   280         Width = settings.GetValue("plotForm.Width", 600),
   281         Height = settings.GetValue("plotForm.Height", 400)
   282       };
   283 
   284       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   285       plotLocation = new UserRadioGroup("plotLocation", 0,
   286         new[] { plotWindowMenuItem, plotBottomMenuItem, plotRightMenuItem },
   287         settings);
   288 
   289       showPlot.Changed += delegate(object sender, EventArgs e) {
   290         if (plotLocation.Value == 0) {
   291           if (showPlot.Value && this.Visible)
   292             plotForm.Show();
   293           else
   294             plotForm.Hide();
   295         } else {
   296           splitContainer.Panel2Collapsed = !showPlot.Value;
   297         }
   298         treeView.Invalidate();
   299       };
   300       plotLocation.Changed += delegate(object sender, EventArgs e) {
   301         switch (plotLocation.Value) {
   302           case 0:
   303             splitContainer.Panel2.Controls.Clear();
   304             splitContainer.Panel2Collapsed = true;
   305             plotForm.Controls.Add(plotPanel);
   306             if (showPlot.Value && this.Visible)
   307               plotForm.Show();
   308             break;
   309           case 1:
   310             plotForm.Controls.Clear();
   311             plotForm.Hide();
   312             splitContainer.Orientation = Orientation.Horizontal;
   313             splitContainer.Panel2.Controls.Add(plotPanel);
   314             splitContainer.Panel2Collapsed = !showPlot.Value;
   315             break;
   316           case 2:
   317             plotForm.Controls.Clear();
   318             plotForm.Hide();
   319             splitContainer.Orientation = Orientation.Vertical;
   320             splitContainer.Panel2.Controls.Add(plotPanel);
   321             splitContainer.Panel2Collapsed = !showPlot.Value;
   322             break;
   323         }
   324       };
   325 
   326       plotForm.FormClosing += delegate(object sender, FormClosingEventArgs e) {
   327         if (e.CloseReason == CloseReason.UserClosing) {
   328           // just switch off the plotting when the user closes the form
   329           if (plotLocation.Value == 0) {
   330             showPlot.Value = false;
   331           }
   332           e.Cancel = true;
   333         }
   334       };
   335 
   336       EventHandler moveOrResizePlotForm = delegate(object sender, EventArgs e) {
   337         if (plotForm.WindowState != FormWindowState.Minimized) {
   338           settings.SetValue("plotForm.Location.X", plotForm.Bounds.X);
   339           settings.SetValue("plotForm.Location.Y", plotForm.Bounds.Y);
   340           settings.SetValue("plotForm.Width", plotForm.Bounds.Width);
   341           settings.SetValue("plotForm.Height", plotForm.Bounds.Height);
   342         }
   343       };
   344       plotForm.Move += moveOrResizePlotForm;
   345       plotForm.Resize += moveOrResizePlotForm;
   346 
   347       plotForm.VisibleChanged += delegate(object sender, EventArgs e) {
   348         Rectangle bounds = new Rectangle(plotForm.Location, plotForm.Size);
   349         Screen screen = Screen.FromRectangle(bounds);
   350         Rectangle intersection =
   351           Rectangle.Intersect(screen.WorkingArea, bounds);
   352         if (intersection.Width < Math.Min(16, bounds.Width) ||
   353             intersection.Height < Math.Min(16, bounds.Height)) {
   354           plotForm.Location = new Point(
   355             screen.WorkingArea.Width / 2 - bounds.Width / 2,
   356             screen.WorkingArea.Height / 2 - bounds.Height / 2);
   357         }
   358       };
   359 
   360       this.VisibleChanged += delegate(object sender, EventArgs e) {
   361         if (this.Visible && showPlot.Value && plotLocation.Value == 0)
   362           plotForm.Show();
   363         else
   364           plotForm.Hide();
   365       };
   366     }
   367     
   368     private void SubHardwareAdded(IHardware hardware, Node node) {
   369       HardwareNode hardwareNode = 
   370         new HardwareNode(hardware, settings, unitManager);
   371       hardwareNode.PlotSelectionChanged += PlotSelectionChanged;
   372 
   373       node.Nodes.Add(hardwareNode);
   374       foreach (IHardware subHardware in hardware.SubHardware)
   375         SubHardwareAdded(subHardware, hardwareNode);  
   376     }
   377 
   378     private void HardwareAdded(IHardware hardware) {      
   379       SubHardwareAdded(hardware, root);
   380       PlotSelectionChanged(this, null);
   381     }
   382 
   383     private void HardwareRemoved(IHardware hardware) {
   384       List<HardwareNode> nodesToRemove = new List<HardwareNode>();
   385       foreach (Node node in root.Nodes) {
   386         HardwareNode hardwareNode = node as HardwareNode;
   387         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   388           nodesToRemove.Add(hardwareNode);
   389       }
   390       foreach (HardwareNode hardwareNode in nodesToRemove) {
   391         root.Nodes.Remove(hardwareNode);
   392         hardwareNode.PlotSelectionChanged -= PlotSelectionChanged;
   393       }
   394       PlotSelectionChanged(this, null);
   395     }
   396 
   397     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   398       Node node = e.Node.Tag as Node;
   399       if (node != null) {
   400         Color color;
   401         if (node.IsVisible) {
   402           SensorNode sensorNode = node as SensorNode;
   403           if (plotMenuItem.Checked && sensorNode != null &&
   404             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   405             e.TextColor = color;
   406         } else {
   407           e.TextColor = Color.DarkGray;
   408         }
   409       }
   410     }
   411 
   412     private void PlotSelectionChanged(object sender, EventArgs e) {
   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.ToInt64() == SC_MINIMIZE) {
   661         SysTrayHideShow();
   662       } else if (minimizeOnClose.Value &&
   663         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == 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 }