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