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