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