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