GUI/MainForm.cs
author moel.mich
Thu, 14 Oct 2010 17:30:51 +0000
changeset 222 ba64bb91ebe4
parent 213 d93c927e4fd6
child 223 39f73ac8c2f4
permissions -rw-r--r--
Improved the invariant TSC frequency estimation code to ignore readings with a large error.
     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-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    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.Configuration;
    42 using System.Drawing;
    43 using System.IO;
    44 using System.Text;
    45 using System.Windows.Forms;
    46 using Aga.Controls.Tree;
    47 using Aga.Controls.Tree.NodeControls;
    48 using OpenHardwareMonitor.Hardware;
    49 using OpenHardwareMonitor.Utilities;
    50 
    51 namespace OpenHardwareMonitor.GUI {
    52   public partial class MainForm : Form {
    53 
    54     private PersistentSettings settings;
    55     private UnitManager unitManager;
    56     private Computer computer;
    57     private Node root;
    58     private TreeModel treeModel;
    59     private IDictionary<ISensor, Color> sensorPlotColors = 
    60       new Dictionary<ISensor, Color>();
    61     private Color[] plotColorPalette;
    62     private SystemTray systemTray;    
    63     private StartupManager startupManager = new StartupManager();
    64     private UpdateVisitor updateVisitor = new UpdateVisitor();
    65     private SensorGadget gadget;
    66 
    67     private UserOption showHiddenSensors;
    68     private UserOption showPlot;
    69     private UserOption showValue;
    70     private UserOption showMin;
    71     private UserOption showMax;
    72     private UserOption startMinimized;
    73     private UserOption minimizeToTray;
    74     private UserOption minimizeOnClose;
    75     private UserOption autoStart;
    76     private UserOption readHddSensors;
    77     private UserOption showGadget;
    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         splitContainer.BorderStyle = BorderStyle.None;
   124         splitContainer.Border3DStyle = Border3DStyle.Adjust;
   125         splitContainer.SplitterWidth = 4;
   126         treeView.BorderStyle = BorderStyle.Fixed3D;
   127         plotPanel.BorderStyle = BorderStyle.Fixed3D;
   128         gadgetMenuItem.Visible = false;
   129         minCloseMenuItem.Visible = false;
   130       } else { // Windows
   131         gadget = new SensorGadget(computer, settings, unitManager);
   132       }          
   133 
   134       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   135       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
   136       computer.Open();
   137 
   138       timer.Enabled = true;
   139 
   140       plotColorPalette = new Color[13];
   141       plotColorPalette[0] = Color.Blue;
   142       plotColorPalette[1] = Color.OrangeRed;
   143       plotColorPalette[2] = Color.Green;
   144       plotColorPalette[3] = Color.LightSeaGreen;
   145       plotColorPalette[4] = Color.Goldenrod;
   146       plotColorPalette[5] = Color.DarkViolet;
   147       plotColorPalette[6] = Color.YellowGreen;
   148       plotColorPalette[7] = Color.SaddleBrown;
   149       plotColorPalette[8] = Color.RoyalBlue;
   150       plotColorPalette[9] = Color.DeepPink;
   151       plotColorPalette[10] = Color.MediumSeaGreen;
   152       plotColorPalette[11] = Color.Olive;
   153       plotColorPalette[12] = Color.Firebrick;
   154 
   155       showHiddenSensors = new UserOption("hiddenMenuItem", false, hiddenMenuItem, settings);
   156       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   157         treeModel.ForceVisible = showHiddenSensors.Value;
   158       };
   159 
   160       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   161       showPlot.Changed += delegate(object sender, EventArgs e) {
   162         splitContainer.Panel2Collapsed = !showPlot.Value;
   163         treeView.Invalidate();
   164       };
   165 
   166       showValue = new UserOption("valueMenuItem", true, valueMenuItem, settings);
   167       showValue.Changed += delegate(object sender, EventArgs e) {
   168         treeView.Columns[1].IsVisible = showValue.Value;
   169       };
   170 
   171       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   172       showMin.Changed += delegate(object sender, EventArgs e) {
   173         treeView.Columns[2].IsVisible = showMin.Value;
   174       };
   175 
   176       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   177       showMax.Changed += delegate(object sender, EventArgs e) {
   178         treeView.Columns[3].IsVisible = showMax.Value;
   179       };
   180 
   181       startMinimized = new UserOption("startMinMenuItem", false, startMinMenuItem, settings);
   182 
   183       minimizeToTray = new UserOption("minTrayMenuItem", true, minTrayMenuItem, settings);
   184       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   185         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   186       };
   187 
   188       minimizeOnClose = new UserOption("minCloseMenuItem", false, minCloseMenuItem, settings);
   189 
   190       autoStart = new UserOption(null, startupManager.Startup, startupMenuItem, settings);
   191       autoStart.Changed += delegate(object sender, EventArgs e) {
   192         try {
   193           startupManager.Startup = autoStart.Value;
   194         } catch (InvalidOperationException) {
   195           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   196             MessageBoxButtons.OK, MessageBoxIcon.Error);
   197           autoStart.Value = startupManager.Startup;
   198         }
   199       };
   200 
   201       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem, settings);
   202       readHddSensors.Changed += delegate(object sender, EventArgs e) {
   203         computer.HDDEnabled = readHddSensors.Value;
   204         UpdatePlotSelection(null, null);
   205       };
   206 
   207       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem, settings);
   208       showGadget.Changed += delegate(object sender, EventArgs e) {
   209         if (gadget != null) 
   210           gadget.Visible = showGadget.Value;
   211       };
   212 
   213       celciusMenuItem.Checked = 
   214         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   215       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   216 
   217       startupMenuItem.Visible = startupManager.IsAvailable;
   218       
   219       if (startMinMenuItem.Checked) {
   220         if (!minTrayMenuItem.Checked) {
   221           WindowState = FormWindowState.Minimized;
   222           Show();
   223         }
   224       } else {
   225         Show();
   226       }
   227 
   228       // Create a handle, otherwise calling Close() does not fire FormClosed     
   229       IntPtr handle = Handle;
   230 
   231       // Make sure the settings are saved when the user logs off
   232       Microsoft.Win32.SystemEvents.SessionEnded +=
   233         delegate(object sender, Microsoft.Win32.SessionEndedEventArgs e) {
   234           SaveConfiguration();
   235         };  
   236     }
   237     
   238     private void SubHardwareAdded(IHardware hardware, Node node) {
   239       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   240       node.Nodes.Add(hardwareNode);
   241       foreach (IHardware subHardware in hardware.SubHardware)
   242         SubHardwareAdded(subHardware, hardwareNode);  
   243     }
   244 
   245     private void HardwareAdded(IHardware hardware) {
   246       Node hardwareNode = new HardwareNode(hardware, settings, unitManager);
   247       root.Nodes.Add(hardwareNode);
   248       foreach (IHardware subHardware in hardware.SubHardware)
   249         SubHardwareAdded(subHardware, hardwareNode);     
   250     }
   251 
   252     private void HardwareRemoved(IHardware hardware) {      
   253       List<Node> nodesToRemove = new List<Node>();
   254       foreach (Node node in root.Nodes) {
   255         HardwareNode hardwareNode = node as HardwareNode;
   256         if (hardwareNode != null && hardwareNode.Hardware == hardware)
   257           nodesToRemove.Add(node);
   258       }
   259       foreach (Node node in nodesToRemove)
   260         root.Nodes.Remove(node);
   261     }
   262 
   263     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
   264       Node node = e.Node.Tag as Node;
   265       if (node != null) {
   266         Color color;
   267         if (node.IsVisible) {
   268           SensorNode sensorNode = node as SensorNode;
   269           if (plotMenuItem.Checked && sensorNode != null &&
   270             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
   271             e.TextColor = color;
   272         } else {
   273           e.TextColor = Color.DarkGray;
   274         }
   275       }
   276     }
   277 
   278     private void UpdatePlotSelection(object sender, 
   279       TreePathEventArgs e) 
   280     {
   281       List<ISensor> selected = new List<ISensor>();
   282       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
   283       int colorIndex = 0;
   284       foreach (TreeNodeAdv node in treeView.AllNodes) {
   285         SensorNode sensorNode = node.Tag as SensorNode;
   286         if (sensorNode != null && 
   287           sensorNode.Sensor.SensorType == SensorType.Temperature) {
   288           if (sensorNode.Plot) {
   289             colors.Add(sensorNode.Sensor,
   290               plotColorPalette[colorIndex % plotColorPalette.Length]);
   291             selected.Add(sensorNode.Sensor);
   292           }
   293           colorIndex++;
   294         }
   295       }
   296       sensorPlotColors = colors;
   297       plotPanel.SetSensors(selected, colors);
   298     }
   299 
   300     private void nodeTextBoxText_EditorShowing(object sender, CancelEventArgs e) 
   301     {
   302       e.Cancel = !(treeView.CurrentNode != null &&
   303         treeView.CurrentNode.Tag is SensorNode);
   304     }
   305 
   306     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   307       NodeControlValueEventArgs e) {
   308       SensorNode node = e.Node.Tag as SensorNode;
   309       e.Value = (node != null) && 
   310         (node.Sensor.SensorType == SensorType.Temperature) && 
   311         plotMenuItem.Checked;
   312     }
   313 
   314     private void exitClick(object sender, EventArgs e) {
   315       Close();
   316     }
   317 
   318     private void timer_Tick(object sender, EventArgs e) {
   319       computer.Accept(updateVisitor);
   320       treeView.Invalidate();
   321       plotPanel.Invalidate();
   322       systemTray.Redraw(); 
   323       if (gadget != null)
   324         gadget.Redraw();
   325     }
   326 
   327     private void SaveConfiguration() {
   328       if (WindowState != FormWindowState.Minimized) {
   329         settings.SetValue("mainForm.Location.X", Bounds.X);
   330         settings.SetValue("mainForm.Location.Y", Bounds.Y);
   331         settings.SetValue("mainForm.Width", Bounds.Width);
   332         settings.SetValue("mainForm.Height", Bounds.Height);
   333       }
   334 
   335       foreach (TreeColumn column in treeView.Columns)
   336         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   337           column.Width);
   338 
   339       string fileName = Path.ChangeExtension(
   340           System.Windows.Forms.Application.ExecutablePath, ".config");
   341       try {
   342         settings.Save(fileName);
   343       } catch (UnauthorizedAccessException) {
   344         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
   345           "The current seetings could not be saved.", 
   346           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
   347       }
   348     }
   349 
   350     private void MainForm_Load(object sender, EventArgs e) {
   351       Rectangle newBounds = new Rectangle {
   352         X = settings.GetValue("mainForm.Location.X", Location.X),
   353         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
   354         Width = settings.GetValue("mainForm.Width", 470),
   355         Height = settings.GetValue("mainForm.Height", 640)
   356       };
   357 
   358       Rectangle totalWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
   359         int.MinValue, int.MinValue);
   360 
   361       foreach (Screen screen in Screen.AllScreens)
   362         totalWorkingArea = Rectangle.Union(totalWorkingArea, screen.Bounds);
   363 
   364       Rectangle intersection = Rectangle.Intersect(totalWorkingArea, newBounds);
   365       if (intersection.Width < 20 || intersection.Height < 20 ||
   366         !settings.Contains("mainForm.Location.X")
   367       ) {
   368         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
   369                       (newBounds.Width/2);
   370 
   371         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
   372                       (newBounds.Height / 2);
   373       }
   374 
   375       this.Bounds = newBounds;
   376     }
   377     
   378     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   379       Visible = false;
   380       SaveConfiguration();
   381 
   382       timer.Enabled = false;
   383       systemTray.Dispose();      
   384       computer.Close();
   385     }
   386 
   387     private void aboutMenuItem_Click(object sender, EventArgs e) {
   388       new AboutBox().ShowDialog();
   389     }
   390 
   391     private void treeView_Click(object sender, EventArgs e) {
   392       
   393       MouseEventArgs m = e as MouseEventArgs;
   394       if (m == null || m.Button != MouseButtons.Right)
   395         return;
   396 
   397       NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y));
   398       treeView.SelectedNode = info.Node;
   399       if (info.Node != null) {
   400         SensorNode node = info.Node.Tag as SensorNode;
   401         if (node != null && node.Sensor != null) {
   402           sensorContextMenu.MenuItems.Clear();
   403           if (node.Sensor.Parameters.Length > 0) {
   404             MenuItem item = new MenuItem("Parameters...");
   405             item.Click += delegate(object obj, EventArgs args) {
   406               ShowParameterForm(node.Sensor);
   407             };
   408             sensorContextMenu.MenuItems.Add(item);
   409           }
   410           if (nodeTextBoxText.EditEnabled) {
   411             MenuItem item = new MenuItem("Rename");
   412             item.Click += delegate(object obj, EventArgs args) {
   413               nodeTextBoxText.BeginEdit();
   414             };
   415             sensorContextMenu.MenuItems.Add(item);
   416           }
   417           if (node.IsVisible) {
   418             MenuItem item = new MenuItem("Hide");
   419             item.Click += delegate(object obj, EventArgs args) {
   420               node.IsVisible = false;
   421             };
   422             sensorContextMenu.MenuItems.Add(item);
   423           } else {
   424             MenuItem item = new MenuItem("Unhide");
   425             item.Click += delegate(object obj, EventArgs args) {
   426               node.IsVisible = true;
   427             };
   428             sensorContextMenu.MenuItems.Add(item);
   429           }
   430           sensorContextMenu.MenuItems.Add(new MenuItem("-"));
   431           {
   432             MenuItem item = new MenuItem("Show in Tray");
   433             item.Checked = systemTray.Contains(node.Sensor);
   434             item.Click += delegate(object obj, EventArgs args) {
   435               if (item.Checked)
   436                 systemTray.Remove(node.Sensor);
   437               else
   438                 systemTray.Add(node.Sensor, true);
   439             };
   440             sensorContextMenu.MenuItems.Add(item);
   441           }
   442           if (gadget != null) {
   443             MenuItem item = new MenuItem("Show in Gadget");
   444             item.Checked = gadget.Contains(node.Sensor);
   445             item.Click += delegate(object obj, EventArgs args) {
   446               if (item.Checked) {
   447                 gadget.Remove(node.Sensor);
   448               } else {
   449                 gadget.Add(node.Sensor);
   450               }
   451             };
   452             sensorContextMenu.MenuItems.Add(item);
   453           }
   454 
   455           sensorContextMenu.Show(treeView, new Point(m.X, m.Y));
   456         }
   457       }
   458     }
   459 
   460     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   461       string report = computer.GetReport();
   462       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   463         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   464           w.Write(report);
   465         }
   466       }
   467     }
   468 
   469     private void SysTrayHideShow() {
   470       Visible = !Visible;
   471       if (Visible)
   472         Activate();    
   473     }
   474 
   475     protected override void WndProc(ref Message m) {
   476       const int WM_SYSCOMMAND = 0x112;
   477       const int SC_MINIMIZE = 0xF020;
   478       const int SC_CLOSE = 0xF060;
   479 
   480       if (minimizeToTray.Value && 
   481         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   482         SysTrayHideShow();
   483       } else if(minimizeOnClose.Value && 
   484         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   485         /*
   486          * Apparently the user wants to minimize rather than close
   487          * Now we still need to check if we're going to the tray or not
   488          * 
   489          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   490          * but since the code here is so simple,
   491          * that would just be a waste of time.
   492          */
   493         if (minimizeToTray.Value)
   494           SysTrayHideShow();
   495         else
   496           WindowState = FormWindowState.Minimized;
   497       } else {      
   498         base.WndProc(ref m);
   499       }
   500     }
   501 
   502     private void hideShowClick(object sender, EventArgs e) {
   503       SysTrayHideShow();
   504     }
   505 
   506     private void ShowParameterForm(ISensor sensor) {
   507       ParameterForm form = new ParameterForm();
   508       form.Parameters = sensor.Parameters;
   509       form.captionLabel.Text = sensor.Name;
   510       form.ShowDialog();
   511     }
   512 
   513     private void treeView_NodeMouseDoubleClick(object sender, 
   514       TreeNodeAdvMouseEventArgs e) {
   515       SensorNode node = e.Node.Tag as SensorNode;
   516       if (node != null && node.Sensor != null && 
   517         node.Sensor.Parameters.Length > 0) {
   518         ShowParameterForm(node.Sensor);
   519       }
   520     }
   521 
   522     private void celciusMenuItem_Click(object sender, EventArgs e) {
   523       celciusMenuItem.Checked = true;
   524       fahrenheitMenuItem.Checked = false;
   525       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   526     }
   527 
   528     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   529       celciusMenuItem.Checked = false;
   530       fahrenheitMenuItem.Checked = true;
   531       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   532     }
   533 
   534     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   535     {
   536       ReportForm form = new ReportForm();
   537       form.Report = computer.GetReport();
   538       form.ShowDialog();      
   539     }
   540 
   541     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   542       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   543         sensor.ResetMin();
   544         sensor.ResetMax();
   545       }));
   546     }
   547   }
   548 }