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