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