moel@1: /*
moel@1:   
moel@1:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1: 
moel@1:   The contents of this file are subject to the Mozilla Public License Version
moel@1:   1.1 (the "License"); you may not use this file except in compliance with
moel@1:   the License. You may obtain a copy of the License at
moel@1:  
moel@1:   http://www.mozilla.org/MPL/
moel@1: 
moel@1:   Software distributed under the License is distributed on an "AS IS" basis,
moel@1:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1:   for the specific language governing rights and limitations under the License.
moel@1: 
moel@1:   The Original Code is the Open Hardware Monitor code.
moel@1: 
moel@1:   The Initial Developer of the Original Code is 
moel@1:   Michael Möller <m.moeller@gmx.ch>.
moel@1:   Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1:   the Initial Developer. All Rights Reserved.
moel@1: 
moel@1:   Contributor(s):
moel@1: 
moel@1:   Alternatively, the contents of this file may be used under the terms of
moel@1:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@1:   of those above. If you wish to allow use of your version of this file only
moel@1:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@1:   use your version of this file under the terms of the MPL, indicate your
moel@1:   decision by deleting the provisions above and replace them with the notice
moel@1:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@1:   the provisions above, a recipient may use your version of this file under
moel@1:   the terms of any one of the MPL, the GPL or the LGPL.
moel@1:  
moel@1: */
moel@1: 
moel@1: using System;
moel@1: using System.Collections.Generic;
moel@1: using System.ComponentModel;
moel@1: using System.Configuration;
moel@1: using System.Drawing;
moel@83: using System.IO;
moel@1: using System.Text;
moel@1: using System.Windows.Forms;
moel@1: using Aga.Controls.Tree;
moel@1: using Aga.Controls.Tree.NodeControls;
moel@1: using OpenHardwareMonitor.Hardware;
moel@28: using OpenHardwareMonitor.Utilities;
moel@1: 
moel@1: namespace OpenHardwareMonitor.GUI {
moel@1:   public partial class MainForm : Form {
moel@1: 
moel@28:     private Computer computer = new Computer();
moel@1:     private Node root;
moel@1:     private TreeModel treeModel;
moel@1:     private IDictionary<ISensor, Color> sensorPlotColors = 
moel@1:       new Dictionary<ISensor, Color>();
moel@1:     private Color[] plotColorPalette;
moel@40:     private SensorSystemTray sensorSystemTray;
moel@40:     private NotifyIcon notifyIcon;
moel@82:     private StartupManager startupManager = new StartupManager();
moel@1: 
moel@28:     public MainForm() {      
moel@1:       InitializeComponent();
moel@1:       this.Font = SystemFonts.MessageBoxFont;
moel@1:       treeView.Font = SystemFonts.MessageBoxFont;
moel@63:       plotPanel.Font = SystemFonts.MessageBoxFont;
moel@1:       
moel@1:       nodeCheckBox.IsVisibleValueNeeded += 
moel@1:         new EventHandler<NodeControlValueEventArgs>(
moel@1:           nodeCheckBox_IsVisibleValueNeeded);
moel@1:       nodeCheckBox.CheckStateChanged += 
moel@1:         new EventHandler<TreePathEventArgs>(UpdatePlotSelection);
moel@1:       nodeTextBoxText.DrawText += 
moel@1:         new EventHandler<DrawEventArgs>(nodeTextBoxText_DrawText);
moel@1:       nodeTextBoxValue.DrawText +=
moel@1:         new EventHandler<DrawEventArgs>(nodeTextBoxText_DrawText);
moel@1:       nodeTextBoxMin.DrawText +=
moel@1:         new EventHandler<DrawEventArgs>(nodeTextBoxText_DrawText);
moel@1:       nodeTextBoxMax.DrawText +=
moel@1:         new EventHandler<DrawEventArgs>(nodeTextBoxText_DrawText);
moel@1:       nodeTextBoxLimit.DrawText += 
moel@1:         new EventHandler<DrawEventArgs>(nodeTextBoxLimit_DrawText);
moel@1: 
moel@1:       if (Utilities.Config.Contains("mainForm.Location.X")) {
moel@1:         int x = Utilities.Config.Get("mainForm.Location.X", Location.X);
moel@1:         x = x < 0 ? 0 : x;
moel@1:         int y = Utilities.Config.Get("mainForm.Location.Y", Location.Y);
moel@1:         y = y < 0 ? 0 : y;
moel@1:         this.Location = new Point(x, y);
moel@1:       } else {
moel@1:         StartPosition = FormStartPosition.CenterScreen;
moel@1:       }
moel@1: 
moel@1:       Width = Utilities.Config.Get("mainForm.Width", Width);
moel@1:       Height = Utilities.Config.Get("mainForm.Height", Height);
moel@1:          
moel@1:       treeModel = new TreeModel();
moel@1:       root = new Node(System.Environment.MachineName);
moel@1:       root.Image = Utilities.EmbeddedResources.GetImage("computer.png");
moel@1:       
moel@1:       treeModel.Nodes.Add(root);
moel@1:       treeView.Model = treeModel;
moel@40:       
moel@40:       notifyIcon = new NotifyIcon();
moel@40:       notifyIcon.ContextMenuStrip = this.notifyContextMenuStrip;
moel@40:       notifyIcon.Icon = EmbeddedResources.GetIcon("smallicon.ico");
moel@40:       notifyIcon.Text = "Open Hardware Monitor";      
moel@82:       notifyIcon.DoubleClick += new EventHandler(this.hideShowClick);
moel@40: 
moel@40:       sensorSystemTray = new SensorSystemTray(computer);
moel@1: 
moel@28:       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
moel@28:       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
moel@28:       computer.Open();
moel@28: 
moel@86:       timer.Enabled = true;
moel@86: 
moel@1:       plotColorPalette = new Color[14];
moel@1:       plotColorPalette[0] = Color.Blue;
moel@1:       plotColorPalette[1] = Color.OrangeRed;
moel@1:       plotColorPalette[2] = Color.Green;
moel@1:       plotColorPalette[3] = Color.LightSeaGreen;
moel@1:       plotColorPalette[4] = Color.Goldenrod;
moel@1:       plotColorPalette[5] = Color.DarkViolet;
moel@1:       plotColorPalette[6] = Color.YellowGreen;
moel@1:       plotColorPalette[7] = Color.SaddleBrown;
moel@1:       plotColorPalette[8] = Color.Gray;
moel@1:       plotColorPalette[9] = Color.RoyalBlue;
moel@1:       plotColorPalette[10] = Color.DeepPink;
moel@1:       plotColorPalette[11] = Color.MediumSeaGreen;
moel@1:       plotColorPalette[12] = Color.Olive;
moel@1:       plotColorPalette[13] = Color.Firebrick;
moel@1: 
moel@28:       plotMenuItem.Checked = Config.Get(plotMenuItem.Name, false);
moel@28:       minMenuItem.Checked = Config.Get(minMenuItem.Name, false);
moel@28:       maxMenuItem.Checked = Config.Get(maxMenuItem.Name, true);
moel@28:       limitMenuItem.Checked = Config.Get(limitMenuItem.Name, false);
moel@1: 
moel@55:       startMinMenuItem.Checked = Config.Get(startMinMenuItem.Name, false); 
moel@28:       minTrayMenuItem.Checked = Config.Get(minTrayMenuItem.Name, true);
moel@82:       startupMenuItem.Checked = startupManager.Startup;
moel@28:       hddMenuItem.Checked = Config.Get(hddMenuItem.Name, true);
moel@1: 
moel@28:       voltMenuItem.Checked = Config.Get(voltMenuItem.Name, true);
moel@28:       clocksMenuItem.Checked = Config.Get(clocksMenuItem.Name, true);
moel@28:       loadMenuItem.Checked = Config.Get(loadMenuItem.Name, true);
moel@28:       tempMenuItem.Checked = Config.Get(tempMenuItem.Name, true);
moel@28:       fansMenuItem.Checked = Config.Get(fansMenuItem.Name, true);
moel@83:       flowsMenuItem.Checked = Config.Get(flowsMenuItem.Name, true);    
moel@55: 
moel@55:       if (startMinMenuItem.Checked) {
moel@82:         if (!minTrayMenuItem.Checked) {
moel@55:           WindowState = FormWindowState.Minimized;
moel@55:           Show();
moel@55:         }
moel@55:       } else {
moel@55:         Show();
moel@55:       }
moel@70: 
moel@71:       // Create a handle, otherwise calling Close() does not fire FormClosed     
moel@71:       IntPtr handle = Handle;
moel@1:     }
moel@1: 
moel@64:     private void SubHardwareAdded(IHardware hardware, Node node) {
moel@64:       Node hardwareNode = new HardwareNode(hardware);
moel@64:       node.Nodes.Add(hardwareNode);
moel@64:       foreach (IHardware subHardware in hardware.SubHardware)
moel@64:         SubHardwareAdded(subHardware, hardwareNode);  
moel@64:     }
moel@64: 
moel@28:     private void HardwareAdded(IHardware hardware) {
moel@64:       Node hardwareNode = new HardwareNode(hardware);
moel@64:       root.Nodes.Add(hardwareNode);
moel@64:       foreach (IHardware subHardware in hardware.SubHardware)
moel@64:         SubHardwareAdded(subHardware, hardwareNode);     
moel@1:     }
moel@1: 
moel@28:     private void HardwareRemoved(IHardware hardware) {      
moel@1:       List<Node> nodesToRemove = new List<Node>();
moel@28:       foreach (Node node in root.Nodes) {
moel@28:         HardwareNode hardwareNode = node as HardwareNode;
moel@28:         if (hardwareNode != null && hardwareNode.Hardware == hardware)
moel@28:           nodesToRemove.Add(node);
moel@28:       }
moel@1:       foreach (Node node in nodesToRemove)
moel@1:         root.Nodes.Remove(node);
moel@1:     }
moel@1: 
moel@1:     private void nodeTextBoxLimit_DrawText(object sender, DrawEventArgs e) {
moel@1:       SensorNode sensorNode = e.Node.Tag as SensorNode;
moel@1:       if (sensorNode != null) 
moel@1:         e.Text = sensorNode.ValueToString(sensorNode.Sensor.Limit);
moel@1:     }
moel@1: 
moel@1:     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {
moel@1:       if (!plotMenuItem.Checked)
moel@1:         return;      
moel@1: 
moel@1:       SensorNode sensorNode = e.Node.Tag as SensorNode;
moel@1:       if (sensorNode != null) {
moel@1:         Color color;
moel@1:         if (sensorPlotColors.TryGetValue(sensorNode.Sensor, out color)) 
moel@1:           e.TextColor = color;        
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     private void UpdatePlotSelection(object sender, 
moel@1:       TreePathEventArgs e) 
moel@1:     {
moel@1:       List<ISensor> selected = new List<ISensor>();
moel@1:       IDictionary<ISensor, Color> colors = new Dictionary<ISensor, Color>();
moel@1:       int colorIndex = 0;
moel@1:       foreach (TreeNodeAdv node in treeView.AllNodes) {
moel@1:         SensorNode sensorNode = node.Tag as SensorNode;
moel@1:         if (sensorNode != null && 
moel@1:           sensorNode.Sensor.SensorType == SensorType.Temperature) {
moel@1:           if (sensorNode.Plot) {
moel@1:             colors.Add(sensorNode.Sensor,
moel@1:               plotColorPalette[colorIndex % plotColorPalette.Length]);
moel@1:             selected.Add(sensorNode.Sensor);
moel@1:           }
moel@1:           colorIndex++;
moel@1:         }
moel@1:       }
moel@1:       sensorPlotColors = colors;
moel@1:       plotPanel.SetSensors(selected, colors);
moel@1:     }
moel@1: 
moel@1:     private void nodeCheckBox_IsVisibleValueNeeded(object sender, 
moel@1:       NodeControlValueEventArgs e) {
moel@1:       SensorNode node = e.Node.Tag as SensorNode;
moel@1:       e.Value = (node != null) && 
moel@1:         (node.Sensor.SensorType == SensorType.Temperature) && 
moel@1:         plotMenuItem.Checked;
moel@1:     }
moel@1: 
moel@1:     private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
moel@70:       Close();      
moel@1:     }
moel@1: 
moel@86:     private void timer_Tick(object sender, EventArgs e) {
moel@86:       computer.Update();  
moel@1:       treeView.Invalidate();
moel@1:       plotPanel.Invalidate();
moel@40:       sensorSystemTray.Redraw();
moel@1:     }
moel@1: 
moel@1:     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
moel@28:             
moel@28:       Config.Set(plotMenuItem.Name, plotMenuItem.Checked);
moel@28:       Config.Set(minMenuItem.Name, minMenuItem.Checked);
moel@28:       Config.Set(maxMenuItem.Name, maxMenuItem.Checked);
moel@28:       Config.Set(limitMenuItem.Name, limitMenuItem.Checked);
moel@1: 
moel@55:       Config.Set(startMinMenuItem.Name, startMinMenuItem.Checked);
moel@28:       Config.Set(minTrayMenuItem.Name, minTrayMenuItem.Checked);
moel@28:       Config.Set(hddMenuItem.Name, hddMenuItem.Checked);
moel@28: 
moel@28:       Config.Set(voltMenuItem.Name, voltMenuItem.Checked);
moel@28:       Config.Set(clocksMenuItem.Name, clocksMenuItem.Checked);
moel@28:       Config.Set(loadMenuItem.Name, loadMenuItem.Checked);
moel@28:       Config.Set(tempMenuItem.Name, tempMenuItem.Checked);
moel@28:       Config.Set(fansMenuItem.Name, fansMenuItem.Checked);
moel@82:       Config.Set(flowsMenuItem.Name, flowsMenuItem.Checked);      
moel@1: 
moel@14:       if (WindowState != FormWindowState.Minimized) {
moel@28:         Config.Set("mainForm.Location.X", Location.X);
moel@28:         Config.Set("mainForm.Location.Y", Location.Y);
moel@28:         Config.Set("mainForm.Width", Width);
moel@28:         Config.Set("mainForm.Height", Height);
moel@14:       }
moel@86: 
moel@86:       timer.Enabled = false;
moel@86: 
moel@40:       sensorSystemTray.Dispose();
moel@40:       notifyIcon.Dispose();
moel@28:       computer.Close();
moel@1:     }
moel@1: 
moel@1:     private void aboutToolStripMenuItem_Click(object sender, EventArgs e) {
moel@1:       new AboutBox().ShowDialog();
moel@1:     }
moel@1: 
moel@1:     private void plotToolStripMenuItem_CheckedChanged(object sender, 
moel@1:       EventArgs e) 
moel@1:     {
moel@1:       splitContainer.Panel2Collapsed = !plotMenuItem.Checked;
moel@1:       treeView.Invalidate();
moel@1:     }
moel@1: 
moel@1:     private void valueToolStripMenuItem_CheckedChanged(object sender, 
moel@1:       EventArgs e) 
moel@1:     {
moel@1:       treeView.Columns[1].IsVisible = valueToolStripMenuItem.Checked;
moel@1:     }
moel@1: 
moel@1:     private void minToolStripMenuItem_CheckedChanged(object sender, EventArgs e) 
moel@1:     {
moel@1:       treeView.Columns[2].IsVisible = minMenuItem.Checked;
moel@1:     }
moel@1: 
moel@1:     private void maxToolStripMenuItem_CheckedChanged(object sender, EventArgs e) 
moel@1:     {
moel@1:       treeView.Columns[3].IsVisible = maxMenuItem.Checked;
moel@1:     }
moel@1: 
moel@1:     private void limitToolStripMenuItem_CheckedChanged(object sender, 
moel@1:       EventArgs e) {
moel@1:       treeView.Columns[4].IsVisible = limitMenuItem.Checked;
moel@1:     }
moel@1: 
moel@1:     private void treeView_Click(object sender, EventArgs e) {
moel@1:       
moel@1:       MouseEventArgs m = e as MouseEventArgs;
moel@1:       if (m == null || m.Button != MouseButtons.Right)
moel@1:         return;
moel@1: 
moel@1:       NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y));
moel@28:       if (info.Control == null) {
moel@1:         columnsContextMenuStrip.Show(treeView, m.X, m.Y);
moel@40:       } else {
moel@40:         SensorNode node = info.Node.Tag as SensorNode;
moel@40:         if (node != null && node.Sensor != null) {
moel@40: 
moel@40:           sensorContextMenuStrip.Items.Clear();
moel@63:           if (node.Sensor.Parameters.Length > 0) {
moel@63:             ToolStripMenuItem item = new ToolStripMenuItem("Parameters...");
moel@63:             item.Click += delegate(object obj, EventArgs args) {
moel@63:               ShowParameterForm(node.Sensor);
moel@63:             };
moel@63:             sensorContextMenuStrip.Items.Add(item);
moel@63:           }
moel@40:           if (sensorSystemTray.Contains(node.Sensor)) {
moel@40:             ToolStripMenuItem item = new ToolStripMenuItem("Remove From Tray");
moel@40:             item.Click += delegate(object obj, EventArgs args) {
moel@40:               sensorSystemTray.Remove(node.Sensor);
moel@40:             };
moel@40:             sensorContextMenuStrip.Items.Add(item);
moel@40:           } else {
moel@40:             ToolStripMenuItem item = new ToolStripMenuItem("Add To Tray");
moel@40:             item.Click += delegate(object obj, EventArgs args) {
moel@42:               sensorSystemTray.Add(node.Sensor, true);
moel@40:             };
moel@40:             sensorContextMenuStrip.Items.Add(item);
moel@40:           }
moel@40:           sensorContextMenuStrip.Show(treeView, m.X, m.Y);
moel@40:         }
moel@40:       }
moel@1:     }
moel@1: 
moel@1:     private void saveReportToolStripMenuItem_Click(object sender, EventArgs e) {
moel@83:       string report = computer.GetReport();
moel@83:       if (saveFileDialog.ShowDialog() == DialogResult.OK) {
moel@83:         using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) {
moel@83:           w.Write(report);
moel@83:         }
moel@83:       }
moel@1:     }
moel@1: 
moel@1:     private void hddsensorsToolStripMenuItem_CheckedChanged(object sender, 
moel@1:       EventArgs e) 
moel@1:     {
moel@28:       computer.HDDEnabled = hddMenuItem.Checked;
moel@28:       UpdateSensorTypeChecked(null, null);
moel@28:       UpdatePlotSelection(null, null);      
moel@1:     }
moel@1: 
moel@64:     private void UpdateSensorTypeVisible(Node node) {
moel@64:       HardwareNode hardwareNode = node as HardwareNode;
moel@64:       if (hardwareNode == null)
moel@64:         return;
moel@64: 
moel@64:       hardwareNode.SetVisible(SensorType.Voltage, voltMenuItem.Checked);
moel@64:       hardwareNode.SetVisible(SensorType.Clock, clocksMenuItem.Checked);
moel@64:       hardwareNode.SetVisible(SensorType.Load, loadMenuItem.Checked);
moel@64:       hardwareNode.SetVisible(SensorType.Temperature, tempMenuItem.Checked);
moel@64:       hardwareNode.SetVisible(SensorType.Fan, fansMenuItem.Checked);
moel@64:       hardwareNode.SetVisible(SensorType.Flow, flowsMenuItem.Checked);
moel@64: 
moel@64:       foreach (Node n in node.Nodes)
moel@64:         UpdateSensorTypeVisible(n);
moel@64:     }
moel@64: 
moel@64:     private void UpdateSensorTypeChecked(object sender, EventArgs e) {          
moel@64:       foreach (HardwareNode node in root.Nodes) 
moel@64:         UpdateSensorTypeVisible(node);
moel@27:     }
moel@27: 
moel@82:     private void SysTrayHideShow() {
moel@82:       Visible = !Visible;
moel@82:       if (Visible)
moel@82:         Activate();    
moel@27:     }
moel@27: 
moel@27:     protected override void WndProc(ref Message m) {
moel@27:       const int WM_SYSCOMMAND = 0x112;
moel@27:       const int SC_MINIMIZE = 0xF020;
moel@28:       if (minTrayMenuItem.Checked && 
moel@28:         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) {
moel@82:         SysTrayHideShow();
moel@27:       } else {      
moel@27:         base.WndProc(ref m);
moel@27:       }
moel@27:     }
moel@27: 
moel@82:     private void hideShowClick(object sender, EventArgs e) {
moel@82:       SysTrayHideShow();
moel@27:     }
moel@27: 
moel@40:     private void removeToolStripMenuItem_Click(object sender, EventArgs e) {
moel@40:       ToolStripMenuItem item = sender as ToolStripMenuItem;
moel@40:       if (item == null)
moel@40:         return;
moel@40: 
moel@40:       ISensor sensor = item.Owner.Tag as ISensor;
moel@40:       if (sensor == null)
moel@40:         return;
moel@40: 
moel@40:       sensorSystemTray.Remove(sensor);
moel@40:     }
moel@63: 
moel@63:     private void ShowParameterForm(ISensor sensor) {
moel@63:       ParameterForm form = new ParameterForm();
moel@63:       form.Parameters = sensor.Parameters;
moel@63:       form.captionLabel.Text = sensor.Name;
moel@63:       form.ShowDialog();
moel@63:     }
moel@63: 
moel@63:     private void treeView_NodeMouseDoubleClick(object sender, 
moel@63:       TreeNodeAdvMouseEventArgs e) {
moel@63:       SensorNode node = e.Node.Tag as SensorNode;
moel@63:       if (node != null && node.Sensor != null && 
moel@63:         node.Sensor.Parameters.Length > 0) {
moel@63:         ShowParameterForm(node.Sensor);
moel@63:       }
moel@63:     }
moel@82: 
moel@82:     private void runOnWindowsStartupToolStripMenuItem_CheckedChanged(
moel@82:       object sender, EventArgs e) 
moel@82:     {
moel@82:       startupManager.Startup = startupMenuItem.Checked;
moel@82:     }
moel@82: 
moel@82:     private void minTrayMenuItem_CheckedChanged(object sender, EventArgs e) {
moel@82:       notifyIcon.Visible = minTrayMenuItem.Checked;
moel@82:     }
moel@1:   }
moel@1: }