GUI/MainForm.cs
author moel.mich
Sun, 15 May 2011 17:21:27 +0000
changeset 286 48d7e8d6c0db
parent 275 35788ddd1825
child 287 1f5cf5d533e6
permissions -rw-r--r--
Fixed Issue 204.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2011
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s): Paul Werelds
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.ComponentModel;
    41 using System.Drawing;
    42 using System.IO;
    43 using System.Windows.Forms;
    44 using Aga.Controls.Tree;
    45 using Aga.Controls.Tree.NodeControls;
    46 using OpenHardwareMonitor.Hardware;
    47 using OpenHardwareMonitor.WMI;
    48 
    49 namespace OpenHardwareMonitor.GUI {
    50   public partial class MainForm : Form {
    51 
    52     private PersistentSettings settings;
    53     private UnitManager unitManager;
    54     private Computer computer;
    55     private Node root;
    56     private TreeModel treeModel;
    57     private IDictionary<ISensor, Color> sensorPlotColors = 
    58       new Dictionary<ISensor, Color>();
    59     private Color[] plotColorPalette;
    60     private SystemTray systemTray;    
    61     private StartupManager startupManager = new StartupManager();
    62     private UpdateVisitor updateVisitor = new UpdateVisitor();
    63     private SensorGadget gadget;
    64 
    65     private UserOption showHiddenSensors;
    66     private UserOption showPlot;
    67     private UserOption showValue;
    68     private UserOption showMin;
    69     private UserOption showMax;
    70     private UserOption startMinimized;
    71     private UserOption minimizeToTray;
    72     private UserOption minimizeOnClose;
    73     private UserOption autoStart;
    74     private UserOption readHddSensors;
    75     private UserOption showGadget;
    76 
    77     private WmiProvider wmiProvider;
    78 
    79     public MainForm() {      
    80       InitializeComponent();
    81 
    82       this.settings = new PersistentSettings();      
    83       this.settings.Load(Path.ChangeExtension(
    84         Application.ExecutablePath, ".config"));
    85 
    86       this.unitManager = new UnitManager(settings);
    87 
    88       // set the DockStyle here, to avoid conflicts with the MainMenu
    89       this.splitContainer.Dock = DockStyle.Fill;
    90             
    91       this.Font = SystemFonts.MessageBoxFont;
    92       treeView.Font = SystemFonts.MessageBoxFont;
    93       plotPanel.Font = SystemFonts.MessageBoxFont;           
    94       
    95       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
    96       nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
    97       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
    98       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
    99       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   100       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   101       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   102 
   103       foreach (TreeColumn column in treeView.Columns) 
   104         column.Width = Math.Max(20, Math.Min(400,
   105           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   106           column.Width)));
   107 
   108       treeModel = new TreeModel();
   109       root = new Node(System.Environment.MachineName);
   110       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   111       
   112       treeModel.Nodes.Add(root);
   113       treeView.Model = treeModel;
   114 
   115       this.computer = new Computer(settings);
   116 
   117       systemTray = new SystemTray(computer, settings);
   118       systemTray.HideShowCommand += hideShowClick;
   119       systemTray.ExitCommand += exitClick;
   120 
   121       int p = (int)Environment.OSVersion.Platform;
   122       if ((p == 4) || (p == 128)) { // Unix
   123         treeView.RowHeight = Math.Max(treeView.RowHeight, 17); 
   124         splitContainer.BorderStyle = BorderStyle.None;
   125         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   126         splitContainer.SplitterWidth = 4;
   127         treeView.BorderStyle = BorderStyle.Fixed3D;
   128         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   129         gadgetMenuItem.Visible = false;
   130         minCloseMenuItem.Visible = false;
   131         minTrayMenuItem.Visible = false;
   132         startMinMenuItem.Visible = false;
   133       } else { // Windows
   134         treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 17); 
   135 
   136         gadget = new SensorGadget(computer, settings, unitManager);
   137         gadget.HideShowCommand += hideShowClick;
   138 
   139         wmiProvider = new WmiProvider(computer);
   140       }          
   141 
   142       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   143       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);        
   144 
   145       computer.Open();
   146 
   147       timer.Enabled = true;
   148 
   149       plotColorPalette = new Color[13];
   150       plotColorPalette[0] = Color.Blue;
   151       plotColorPalette[1] = Color.OrangeRed;
   152       plotColorPalette[2] = Color.Green;
   153       plotColorPalette[3] = Color.LightSeaGreen;
   154       plotColorPalette[4] = Color.Goldenrod;
   155       plotColorPalette[5] = Color.DarkViolet;
   156       plotColorPalette[6] = Color.YellowGreen;
   157       plotColorPalette[7] = Color.SaddleBrown;
   158       plotColorPalette[8] = Color.RoyalBlue;
   159       plotColorPalette[9] = Color.DeepPink;
   160       plotColorPalette[10] = Color.MediumSeaGreen;
   161       plotColorPalette[11] = Color.Olive;
   162       plotColorPalette[12] = Color.Firebrick;
   163 
   164       showHiddenSensors = new UserOption("hiddenMenuItem", false,
   165         hiddenMenuItem, settings);
   166       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   167         treeModel.ForceVisible = showHiddenSensors.Value;
   168       };
   169 
   170       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   171       showPlot.Changed += delegate(object sender, EventArgs e) {
   172         splitContainer.Panel2Collapsed = !showPlot.Value;
   173         treeView.Invalidate();
   174       };
   175 
   176       showValue = new UserOption("valueMenuItem", true, valueMenuItem,
   177         settings);
   178       showValue.Changed += delegate(object sender, EventArgs e) {
   179         treeView.Columns[1].IsVisible = showValue.Value;
   180       };
   181 
   182       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   183       showMin.Changed += delegate(object sender, EventArgs e) {
   184         treeView.Columns[2].IsVisible = showMin.Value;
   185       };
   186 
   187       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   188       showMax.Changed += delegate(object sender, EventArgs e) {
   189         treeView.Columns[3].IsVisible = showMax.Value;
   190       };
   191 
   192       startMinimized = new UserOption("startMinMenuItem", false,
   193         startMinMenuItem, settings);
   194 
   195       minimizeToTray = new UserOption("minTrayMenuItem", true,
   196         minTrayMenuItem, settings);
   197       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   198         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   199       };
   200 
   201       minimizeOnClose = new UserOption("minCloseMenuItem", false,
   202         minCloseMenuItem, settings);
   203 
   204       autoStart = new UserOption(null, startupManager.Startup,
   205         startupMenuItem, settings);
   206       autoStart.Changed += delegate(object sender, EventArgs e) {
   207         try {
   208           startupManager.Startup = autoStart.Value;
   209         } catch (InvalidOperationException) {
   210           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   211             MessageBoxButtons.OK, MessageBoxIcon.Error);
   212           autoStart.Value = startupManager.Startup;
   213         }
   214       };
   215 
   216       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
   217         settings);
   218       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   219         computer.HDDEnabled = readHddSensors.Value;
   220         UpdatePlotSelection(null, null);
   221       };
   222 
   223       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
   224         settings);
   225       showGadget.Changed += delegate(object sender, EventArgs e) {
   226         if (gadget != null) 
   227           gadget.Visible = showGadget.Value;
   228       };
   229 
   230       celciusMenuItem.Checked = 
   231         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   232       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   233 
   234       startupMenuItem.Visible = startupManager.IsAvailable;
   235       
   236       if (startMinMenuItem.Checked) {
   237         if (!minTrayMenuItem.Checked) {
   238           WindowState = FormWindowState.Minimized;
   239           Show();
   240         }
   241       } else {
   242         Show();
   243       }
   244 
   245       // Create a handle, otherwise calling Close() does not fire FormClosed     
   246       IntPtr handle = Handle;
   247 
   248       // Make sure the settings are saved when the user logs off
   249       Microsoft.Win32.SystemEvents.SessionEnded += delegate {
   250         SaveConfiguration();
   251       };  
   252     }
   253     
   254     private void SubHardwareAdded(IHardware hardware, Node node) {
   255       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   256       node.Nodes.Add(hardwareNode);
   257       foreach (IHardware subHardware in hardware.SubHardware)
   258         SubHardwareAdded(subHardware, hardwareNode);  
   259     }
   260 
   261     private void HardwareAdded(IHardware hardware) {
   262       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   263       root.Nodes.Add(hardwareNode);
   264       foreach (IHardware subHardware in hardware.SubHardware)
   265         SubHardwareAdded(subHardware, hardwareNode);     
   266     }
   267 
   268     private void HardwareRemoved(IHardware hardware) {      
   269       List<Node> nodesToRemove = new List<Node>();
   270       foreach (Node node in root.Nodes) {
   271         HardwareNode hardwareNode = node as HardwareNode;
   272         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   273           nodesToRemove.Add(node);
   274       }
   275       foreach (Node node in nodesToRemove)
   276         root.Nodes.Remove(node);
   277     }
   278 
   279     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   280       Node node = e.Node.Tag as Node;
   281       if (node != null) {
   282         Color color;
   283         if (node.IsVisible) {
   284           SensorNode sensorNode = node as SensorNode;
   285           if (plotMenuItem.Checked && sensorNode != null &&
   286             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   287             e.TextColor = color;
   288         } else {
   289           e.TextColor = Color.DarkGray;
   290         }
   291       }
   292     }
   293 
   294     private void UpdatePlotSelection(object sender, 
   295       TreePathEventArgs e) 
   296     {
   297       List<ISensor> selected = new List<ISensor>();
   298       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   299       int colorIndex = 0;
   300       foreach (TreeNodeAdv node in treeView.AllNodes) {
   301         SensorNode sensorNode = node.Tag as SensorNode;
   302         if (sensorNode != null && 
   303           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   304           if (sensorNode.Plot) {
   305             colors.Add(sensorNode.Sensor,
   306               plotColorPalette[colorIndex % plotColorPalette.Length]);
   307             selected.Add(sensorNode.Sensor);
   308           }
   309           colorIndex++;
   310         }
   311       }
   312       sensorPlotColors = colors;
   313       plotPanel.SetSensors(selected, colors);
   314     }
   315 
   316     private void nodeTextBoxText_EditorShowing(object sender,
   317       CancelEventArgs e) 
   318     {
   319       e.Cancel = !(treeView.CurrentNode != null &&
   320         (treeView.CurrentNode.Tag is SensorNode || 
   321          treeView.CurrentNode.Tag is HardwareNode));
   322     }
   323 
   324     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   325       NodeControlValueEventArgs e) {
   326       SensorNode node = e.Node.Tag as SensorNode;
   327       e.Value = (node != null) && 
   328         (node.Sensor.SensorType == SensorType.Temperature) && 
   329         plotMenuItem.Checked;
   330     }
   331 
   332     private void exitClick(object sender, EventArgs e) {
   333       Close();
   334     }
   335 
   336     private void timer_Tick(object sender, EventArgs e) {
   337       computer.Accept(updateVisitor);
   338       treeView.Invalidate();
   339       plotPanel.Invalidate();
   340       systemTray.Redraw();
   341       if (gadget != null)
   342         gadget.Redraw();
   343 
   344       if (wmiProvider != null)
   345         wmiProvider.Update();
   346     }
   347 
   348     private void SaveConfiguration() {
   349       foreach (TreeColumn column in treeView.Columns)
   350         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   351           column.Width);
   352 
   353       string fileName = Path.ChangeExtension(
   354           System.Windows.Forms.Application.ExecutablePath, ".config");
   355       try {
   356         settings.Save(fileName);
   357       } catch (UnauthorizedAccessException) {
   358         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
   359           "The current settings could not be saved.",
   360           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   361       } catch (IOException) {
   362         MessageBox.Show("The path '" + fileName + "' is not writeable. " +
   363           "The current settings could not be saved.",
   364           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   365       }
   366     }
   367 
   368     private void MainForm_Load(object sender, EventArgs e) {
   369       Rectangle newBounds = new Rectangle {
   370         X = settings.GetValue("mainForm.Location.X", Location.X),
   371         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   372         Width = settings.GetValue("mainForm.Width", 470),
   373         Height = settings.GetValue("mainForm.Height", 640)
   374       };
   375 
   376       Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   377         int.MinValue, int.MinValue);
   378 
   379       foreach (Screen screen in Screen.AllScreens)
   380         fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
   381 
   382       Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
   383       if (intersection.Width < 20 || intersection.Height < 20 ||
   384         !settings.Contains("mainForm.Location.X")
   385       ) {
   386         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
   387                       (newBounds.Width/2);
   388 
   389         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
   390                       (newBounds.Height / 2);
   391       }
   392 
   393       this.Bounds = newBounds;
   394     }
   395     
   396     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   397       Visible = false;
   398       SaveConfiguration();
   399 
   400       systemTray.IsMainIconEnabled = false;
   401       timer.Enabled = false;            
   402       computer.Close();
   403       systemTray.Dispose();
   404     }
   405 
   406     private void aboutMenuItem_Click(object sender, EventArgs e) {
   407       new AboutBox().ShowDialog();
   408     }
   409 
   410     private void treeView_Click(object sender, EventArgs e) {
   411 
   412       MouseEventArgs m = e as MouseEventArgs;
   413       if (m == null || m.Button != MouseButtons.Right)
   414         return;
   415 
   416       NodeControlInfo info = treeView.GetNodeControlInfoAt(
   417         new Point(m.X, m.Y)
   418       );
   419       treeView.SelectedNode = info.Node;
   420       if (info.Node != null) {
   421         SensorNode node = info.Node.Tag as SensorNode;
   422         if (node != null && node.Sensor != null) {
   423           treeContextMenu.MenuItems.Clear();
   424           if (node.Sensor.Parameters.Length > 0) {
   425             MenuItem item = new MenuItem("Parameters...");
   426             item.Click += delegate(object obj, EventArgs args) {
   427               ShowParameterForm(node.Sensor);
   428             };
   429             treeContextMenu.MenuItems.Add(item);
   430           }
   431           if (nodeTextBoxText.EditEnabled) {
   432             MenuItem item = new MenuItem("Rename");
   433             item.Click += delegate(object obj, EventArgs args) {
   434               nodeTextBoxText.BeginEdit();
   435             };
   436             treeContextMenu.MenuItems.Add(item);
   437           }
   438           if (node.IsVisible) {
   439             MenuItem item = new MenuItem("Hide");
   440             item.Click += delegate(object obj, EventArgs args) {
   441               node.IsVisible = false;
   442             };
   443             treeContextMenu.MenuItems.Add(item);
   444           } else {
   445             MenuItem item = new MenuItem("Unhide");
   446             item.Click += delegate(object obj, EventArgs args) {
   447               node.IsVisible = true;
   448             };
   449             treeContextMenu.MenuItems.Add(item);
   450           }
   451           treeContextMenu.MenuItems.Add(new MenuItem("-"));
   452           {
   453             MenuItem item = new MenuItem("Show in Tray");
   454             item.Checked = systemTray.Contains(node.Sensor);
   455             item.Click += delegate(object obj, EventArgs args) {
   456               if (item.Checked)
   457                 systemTray.Remove(node.Sensor);
   458               else
   459                 systemTray.Add(node.Sensor, true);
   460             };
   461             treeContextMenu.MenuItems.Add(item);
   462           }
   463           if (gadget != null) {
   464             MenuItem item = new MenuItem("Show in Gadget");
   465             item.Checked = gadget.Contains(node.Sensor);
   466             item.Click += delegate(object obj, EventArgs args) {
   467               if (item.Checked) {
   468                 gadget.Remove(node.Sensor);
   469               } else {
   470                 gadget.Add(node.Sensor);
   471               }
   472             };
   473             treeContextMenu.MenuItems.Add(item);
   474           }
   475           if (node.Sensor.Control != null) {
   476             treeContextMenu.MenuItems.Add(new MenuItem("-"));
   477             IControl control = node.Sensor.Control;
   478             MenuItem controlItem = new MenuItem("Control");
   479             MenuItem defaultItem = new MenuItem("Default");
   480             defaultItem.Checked = control.ControlMode == ControlMode.Default;
   481             controlItem.MenuItems.Add(defaultItem);
   482             defaultItem.Click += delegate(object obj, EventArgs args) {
   483               control.SetDefault();
   484             };
   485             MenuItem manualItem = new MenuItem("Manual");
   486             controlItem.MenuItems.Add(manualItem);
   487             manualItem.Checked = control.ControlMode == ControlMode.Software;
   488             for (int i = 0; i <= 100; i += 5) {
   489               if (i <= control.MaxSoftwareValue &&
   490                   i >= control.MinSoftwareValue) {
   491                 MenuItem item = new MenuItem(i + " %");
   492                 manualItem.MenuItems.Add(item);
   493                 item.Checked = control.ControlMode == ControlMode.Software &&
   494                   Math.Round(control.SoftwareValue) == i;
   495                 int softwareValue = i;
   496                 item.Click += delegate(object obj, EventArgs args) {
   497                   control.SetSoftware(softwareValue);
   498                 };
   499               }
   500             }
   501             treeContextMenu.MenuItems.Add(controlItem);
   502           }
   503 
   504           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   505         }
   506 
   507         HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
   508         if (hardwareNode != null && hardwareNode.Hardware != null) {
   509           treeContextMenu.MenuItems.Clear();
   510 
   511           if (nodeTextBoxText.EditEnabled) {
   512             MenuItem item = new MenuItem("Rename");
   513             item.Click += delegate(object obj, EventArgs args) {
   514               nodeTextBoxText.BeginEdit();
   515             };
   516             treeContextMenu.MenuItems.Add(item);
   517           }
   518 
   519           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
   520         }
   521       }
   522     }
   523 
   524     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   525       string report = computer.GetReport();
   526       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   527         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   528           w.Write(report);
   529         }
   530       }
   531     }
   532 
   533     private void SysTrayHideShow() {
   534       Visible = !Visible;
   535       if (Visible)
   536         Activate();    
   537     }
   538 
   539     protected override void WndProc(ref Message m) {
   540       const int WM_SYSCOMMAND = 0x112;
   541       const int SC_MINIMIZE = 0xF020;
   542       const int SC_CLOSE = 0xF060;
   543 
   544       if (minimizeToTray.Value && 
   545         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   546         SysTrayHideShow();
   547       } else if(minimizeOnClose.Value && 
   548         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   549         /*
   550          * Apparently the user wants to minimize rather than close
   551          * Now we still need to check if we're going to the tray or not
   552          * 
   553          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   554          * but since the code here is so simple,
   555          * that would just be a waste of time.
   556          */
   557         if (minimizeToTray.Value)
   558           SysTrayHideShow();
   559         else
   560           WindowState = FormWindowState.Minimized;
   561       } else {      
   562         base.WndProc(ref m);
   563       }
   564     }
   565 
   566     private void hideShowClick(object sender, EventArgs e) {
   567       SysTrayHideShow();
   568     }
   569 
   570     private void ShowParameterForm(ISensor sensor) {
   571       ParameterForm form = new ParameterForm();
   572       form.Parameters = sensor.Parameters;
   573       form.captionLabel.Text = sensor.Name;
   574       form.ShowDialog();
   575     }
   576 
   577     private void treeView_NodeMouseDoubleClick(object sender, 
   578       TreeNodeAdvMouseEventArgs e) {
   579       SensorNode node = e.Node.Tag as SensorNode;
   580       if (node != null && node.Sensor != null && 
   581         node.Sensor.Parameters.Length > 0) {
   582         ShowParameterForm(node.Sensor);
   583       }
   584     }
   585 
   586     private void celciusMenuItem_Click(object sender, EventArgs e) {
   587       celciusMenuItem.Checked = true;
   588       fahrenheitMenuItem.Checked = false;
   589       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   590     }
   591 
   592     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   593       celciusMenuItem.Checked = false;
   594       fahrenheitMenuItem.Checked = true;
   595       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   596     }
   597 
   598     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   599     {
   600       ReportForm form = new ReportForm();
   601       form.Report = computer.GetReport();
   602       form.ShowDialog();      
   603     }
   604 
   605     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   606       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   607         sensor.ResetMin();
   608         sensor.ResetMax();
   609       }));
   610     }
   611 
   612     private void MainForm_MoveOrResize(object sender, EventArgs e) {
   613       if (WindowState != FormWindowState.Minimized) {
   614         settings.SetValue("mainForm.Location.X", Bounds.X);
   615         settings.SetValue("mainForm.Location.Y", Bounds.Y);
   616         settings.SetValue("mainForm.Width", Bounds.Width);
   617         settings.SetValue("mainForm.Height", Bounds.Height);
   618       }
   619     }
   620 
   621     private void resetClick(object sender, EventArgs e) {
   622       // disable the fallback MainIcon during reset, otherwise icon visibility
   623       // might be lost 
   624       systemTray.IsMainIconEnabled = false;
   625       computer.Close();
   626       computer.Open();
   627       // restore the MainIcon setting
   628       systemTray.IsMainIconEnabled = minimizeToTray.Value;
   629     }
   630   }
   631 }