GUI/MainForm.cs
author moel.mich
Mon, 27 Sep 2010 23:48:41 +0000
changeset 200 50de2faf3336
parent 185 edb59f3745e8
child 202 551243a66b32
permissions -rw-r--r--
Fixed a problem where the ADL Main_Memory_Alloc callback delegate could be garbage collected while still in use.
     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       int p = (int)Environment.OSVersion.Platform;
    92       if ((p == 4) || (p == 128)) {
    93         splitContainer.BorderStyle = BorderStyle.None;
    94         splitContainer.Border3DStyle = Border3DStyle.Adjust;
    95         splitContainer.SplitterWidth = 4;
    96         treeView.BorderStyle = BorderStyle.Fixed3D;
    97         plotPanel.BorderStyle = BorderStyle.Fixed3D;
    98       }
    99       
   100       this.Font = SystemFonts.MessageBoxFont;
   101       treeView.Font = SystemFonts.MessageBoxFont;
   102       plotPanel.Font = SystemFonts.MessageBoxFont;
   103       
   104       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
   105       nodeCheckBox.CheckStateChanged += UpdatePlotSelection;
   106       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
   107       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
   108       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
   109       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
   110       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
   111 
   112       if (settings.Contains("mainForm.Location.X")) {
   113         int x = settings.GetValue("mainForm.Location.X", Location.X);
   114         x = x < 0 ? 0 : x;
   115         int y = settings.GetValue("mainForm.Location.Y", Location.Y);
   116         y = y < 0 ? 0 : y;
   117         this.Location = new Point(x, y);
   118       } else {
   119         StartPosition = FormStartPosition.CenterScreen;
   120       }
   121 
   122       ClientSize = new Size(
   123         settings.GetValue("mainForm.Width", 470),
   124         settings.GetValue("mainForm.Height", 640));
   125 
   126       foreach (TreeColumn column in treeView.Columns) 
   127         column.Width = Math.Max(20, Math.Min(400,
   128           settings.GetValue("treeView.Columns." + column.Header + ".Width",
   129           column.Width)));
   130 
   131       treeModel = new TreeModel();
   132       root = new Node(System.Environment.MachineName);
   133       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
   134       
   135       treeModel.Nodes.Add(root);
   136       treeView.Model = treeModel;
   137 
   138       this.computer = new Computer(settings);
   139 
   140       systemTray = new SystemTray(computer, settings);
   141       systemTray.HideShowCommand += hideShowClick;
   142       systemTray.ExitCommand += exitClick;
   143 
   144       gadget = new SensorGadget(computer, settings, unitManager);
   145 
   146       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
   147       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
   148       computer.Open();
   149 
   150       timer.Enabled = true;
   151 
   152       plotColorPalette = new Color[13];
   153       plotColorPalette[0] = Color.Blue;
   154       plotColorPalette[1] = Color.OrangeRed;
   155       plotColorPalette[2] = Color.Green;
   156       plotColorPalette[3] = Color.LightSeaGreen;
   157       plotColorPalette[4] = Color.Goldenrod;
   158       plotColorPalette[5] = Color.DarkViolet;
   159       plotColorPalette[6] = Color.YellowGreen;
   160       plotColorPalette[7] = Color.SaddleBrown;
   161       plotColorPalette[8] = Color.RoyalBlue;
   162       plotColorPalette[9] = Color.DeepPink;
   163       plotColorPalette[10] = Color.MediumSeaGreen;
   164       plotColorPalette[11] = Color.Olive;
   165       plotColorPalette[12] = Color.Firebrick;
   166 
   167       showHiddenSensors = new UserOption("hiddenMenuItem", false, hiddenMenuItem, settings);
   168       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
   169         treeModel.ForceVisible = showHiddenSensors.Value;
   170       };
   171 
   172       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
   173       showPlot.Changed += delegate(object sender, EventArgs e) {
   174         splitContainer.Panel2Collapsed = !showPlot.Value;
   175         treeView.Invalidate();
   176       };
   177 
   178       showValue = new UserOption("valueMenuItem", true, valueMenuItem, settings);
   179       showValue.Changed += delegate(object sender, EventArgs e) {
   180         treeView.Columns[1].IsVisible = showValue.Value;
   181       };
   182 
   183       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
   184       showMin.Changed += delegate(object sender, EventArgs e) {
   185         treeView.Columns[2].IsVisible = showMin.Value;
   186       };
   187 
   188       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
   189       showMax.Changed += delegate(object sender, EventArgs e) {
   190         treeView.Columns[3].IsVisible = showMax.Value;
   191       };
   192 
   193       startMinimized = new UserOption("startMinMenuItem", false, startMinMenuItem, settings);
   194 
   195       minimizeToTray = new UserOption("minTrayMenuItem", true, minTrayMenuItem, settings);
   196       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
   197         systemTray.IsMainIconEnabled = minimizeToTray.Value;
   198       };
   199 
   200       minimizeOnClose = new UserOption("minCloseMenuItem", false, minCloseMenuItem, settings);
   201 
   202       autoStart = new UserOption(null, startupManager.Startup, startupMenuItem, settings);
   203       autoStart.Changed += delegate(object sender, EventArgs e) {
   204         try {
   205           startupManager.Startup = autoStart.Value;
   206         } catch (InvalidOperationException) {
   207           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
   208             MessageBoxButtons.OK, MessageBoxIcon.Error);
   209           autoStart.Value = startupManager.Startup;
   210         }
   211       };
   212 
   213       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem, 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, settings);
   220       showGadget.Changed += delegate(object sender, EventArgs e) {
   221         gadget.Visible = showGadget.Value;
   222       };
   223 
   224       celciusMenuItem.Checked = 
   225         unitManager.TemperatureUnit == TemperatureUnit.Celcius;
   226       fahrenheitMenuItem.Checked = !celciusMenuItem.Checked;
   227 
   228       startupMenuItem.Visible = startupManager.IsAvailable;
   229       
   230       if (startMinMenuItem.Checked) {
   231         if (!minTrayMenuItem.Checked) {
   232           WindowState = FormWindowState.Minimized;
   233           Show();
   234         }
   235       } else {
   236         Show();
   237       }
   238 
   239       // Create a handle, otherwise calling Close() does not fire FormClosed     
   240       IntPtr handle = Handle;
   241 
   242       // Make sure the settings are saved when the user logs off
   243       Microsoft.Win32.SystemEvents.SessionEnded +=
   244         delegate(object sender, Microsoft.Win32.SessionEndedEventArgs e) {
   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, CancelEventArgs e) 
   312     {
   313       e.Cancel = !(treeView.CurrentNode != null &&
   314         treeView.CurrentNode.Tag is SensorNode);
   315     }
   316 
   317     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
   318       NodeControlValueEventArgs e) {
   319       SensorNode node = e.Node.Tag as SensorNode;
   320       e.Value = (node != null) && 
   321         (node.Sensor.SensorType == SensorType.Temperature) && 
   322         plotMenuItem.Checked;
   323     }
   324 
   325     private void exitClick(object sender, EventArgs e) {
   326       Close();
   327     }
   328 
   329     private void timer_Tick(object sender, EventArgs e) {
   330       computer.Accept(updateVisitor);
   331       treeView.Invalidate();
   332       plotPanel.Invalidate();
   333       systemTray.Redraw();
   334       gadget.Redraw();
   335     }
   336 
   337     private void SaveConfiguration() {
   338       if (WindowState != FormWindowState.Minimized) {
   339         settings.SetValue("mainForm.Location.X", Location.X);
   340         settings.SetValue("mainForm.Location.Y", Location.Y);
   341         settings.SetValue("mainForm.Width", ClientSize.Width);
   342         settings.SetValue("mainForm.Height", ClientSize.Height);
   343       }
   344 
   345       foreach (TreeColumn column in treeView.Columns)
   346         settings.SetValue("treeView.Columns." + column.Header + ".Width",
   347           column.Width);
   348 
   349       settings.Save(Path.ChangeExtension(
   350         System.Windows.Forms.Application.ExecutablePath, ".config"));
   351     }
   352 
   353    private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
   354       Visible = false;
   355       SaveConfiguration();
   356 
   357       timer.Enabled = false;
   358       systemTray.Dispose();      
   359       computer.Close();
   360     }
   361 
   362     private void aboutMenuItem_Click(object sender, EventArgs e) {
   363       new AboutBox().ShowDialog();
   364     }
   365 
   366     private void treeView_Click(object sender, EventArgs e) {
   367       
   368       MouseEventArgs m = e as MouseEventArgs;
   369       if (m == null || m.Button != MouseButtons.Right)
   370         return;
   371 
   372       NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y));
   373       treeView.SelectedNode = info.Node;
   374       if (info.Node != null) {
   375         SensorNode node = info.Node.Tag as SensorNode;
   376         if (node != null && node.Sensor != null) {
   377           sensorContextMenu.MenuItems.Clear();
   378           if (node.Sensor.Parameters.Length > 0) {
   379             MenuItem item = new MenuItem("Parameters...");
   380             item.Click += delegate(object obj, EventArgs args) {
   381               ShowParameterForm(node.Sensor);
   382             };
   383             sensorContextMenu.MenuItems.Add(item);
   384           }
   385           if (nodeTextBoxText.EditEnabled) {
   386             MenuItem item = new MenuItem("Rename");
   387             item.Click += delegate(object obj, EventArgs args) {
   388               nodeTextBoxText.BeginEdit();
   389             };
   390             sensorContextMenu.MenuItems.Add(item);
   391           }
   392           if (node.IsVisible) {
   393             MenuItem item = new MenuItem("Hide");
   394             item.Click += delegate(object obj, EventArgs args) {
   395               node.IsVisible = false;
   396             };
   397             sensorContextMenu.MenuItems.Add(item);
   398           } else {
   399             MenuItem item = new MenuItem("Unhide");
   400             item.Click += delegate(object obj, EventArgs args) {
   401               node.IsVisible = true;
   402             };
   403             sensorContextMenu.MenuItems.Add(item);
   404           }
   405           sensorContextMenu.MenuItems.Add(new MenuItem("-"));
   406           {
   407             MenuItem item = new MenuItem("Show in Tray");
   408             item.Checked = systemTray.Contains(node.Sensor);
   409             item.Click += delegate(object obj, EventArgs args) {
   410               if (item.Checked)
   411                 systemTray.Remove(node.Sensor);
   412               else
   413                 systemTray.Add(node.Sensor, true);
   414             };
   415             sensorContextMenu.MenuItems.Add(item);
   416           }
   417           {
   418             MenuItem item = new MenuItem("Show in Gadget");
   419             item.Checked = gadget.Contains(node.Sensor);
   420             item.Click += delegate(object obj, EventArgs args) {
   421               if (item.Checked) {
   422                 gadget.Remove(node.Sensor);
   423               } else {
   424                 gadget.Add(node.Sensor);
   425               }
   426             };
   427             sensorContextMenu.MenuItems.Add(item);
   428           }
   429 
   430           sensorContextMenu.Show(treeView, new Point(m.X, m.Y));
   431         }
   432       }
   433     }
   434 
   435     private void saveReportMenuItem_Click(object sender, EventArgs e) {
   436       string report = computer.GetReport();
   437       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
   438         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
   439           w.Write(report);
   440         }
   441       }
   442     }
   443 
   444     private void SysTrayHideShow() {
   445       Visible = !Visible;
   446       if (Visible)
   447         Activate();    
   448     }
   449 
   450     protected override void WndProc(ref Message m) {
   451       const int WM_SYSCOMMAND = 0x112;
   452       const int SC_MINIMIZE = 0xF020;
   453       const int SC_CLOSE = 0xF060;
   454 
   455       if (minimizeToTray.Value && 
   456         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
   457         SysTrayHideShow();
   458       } else if(minimizeOnClose.Value && 
   459         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) {
   460         /*
   461          * Apparently the user wants to minimize rather than close
   462          * Now we still need to check if we're going to the tray or not
   463          * 
   464          * Note: the correct way to do this would be to send out SC_MINIMIZE,
   465          * but since the code here is so simple,
   466          * that would just be a waste of time.
   467          */
   468         if (minimizeToTray.Value)
   469           SysTrayHideShow();
   470         else
   471           WindowState = FormWindowState.Minimized;
   472       } else {      
   473         base.WndProc(ref m);
   474       }
   475     }
   476 
   477     private void hideShowClick(object sender, EventArgs e) {
   478       SysTrayHideShow();
   479     }
   480 
   481     private void removeMenuItem_Click(object sender, EventArgs e) {
   482       MenuItem item = sender as MenuItem;
   483       if (item == null)
   484         return;
   485 
   486       ISensor sensor = item.Parent.Tag as ISensor;
   487       if (sensor == null)
   488         return;
   489 
   490       systemTray.Remove(sensor);
   491     }
   492 
   493     private void ShowParameterForm(ISensor sensor) {
   494       ParameterForm form = new ParameterForm();
   495       form.Parameters = sensor.Parameters;
   496       form.captionLabel.Text = sensor.Name;
   497       form.ShowDialog();
   498     }
   499 
   500     private void treeView_NodeMouseDoubleClick(object sender, 
   501       TreeNodeAdvMouseEventArgs e) {
   502       SensorNode node = e.Node.Tag as SensorNode;
   503       if (node != null && node.Sensor != null && 
   504         node.Sensor.Parameters.Length > 0) {
   505         ShowParameterForm(node.Sensor);
   506       }
   507     }
   508 
   509     private void celciusMenuItem_Click(object sender, EventArgs e) {
   510       celciusMenuItem.Checked = true;
   511       fahrenheitMenuItem.Checked = false;
   512       unitManager.TemperatureUnit = TemperatureUnit.Celcius;
   513     }
   514 
   515     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
   516       celciusMenuItem.Checked = false;
   517       fahrenheitMenuItem.Checked = true;
   518       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
   519     }
   520 
   521     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
   522     {
   523       ReportForm form = new ReportForm();
   524       form.Report = computer.GetReport();
   525       form.ShowDialog();      
   526     }
   527 
   528     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
   529       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
   530         sensor.ResetMin();
   531         sensor.ResetMax();
   532       }));
   533     }
   534   }
   535 }