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