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