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