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