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