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