moel@1: /*
moel@344:  
moel@344:   This Source Code Form is subject to the terms of the Mozilla Public
moel@344:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@344:  
moel@344:   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344: 	Copyright (C) 2010 Paul Werelds <paul@werelds.net>
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.Drawing;
moel@83: using System.IO;
moel@291: using System.Reflection;
moel@1: using System.Windows.Forms;
moel@1: using Aga.Controls.Tree;
moel@1: using Aga.Controls.Tree.NodeControls;
moel@1: using OpenHardwareMonitor.Hardware;
paulwerelds@227: using OpenHardwareMonitor.WMI;
moel@1: 
moel@1: namespace OpenHardwareMonitor.GUI {
moel@1:   public partial class MainForm : Form {
moel@1: 
moel@165:     private PersistentSettings settings;
moel@165:     private UnitManager unitManager;
moel@165:     private Computer 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@133:     private SystemTray systemTray;    
moel@82:     private StartupManager startupManager = new StartupManager();
moel@110:     private UpdateVisitor updateVisitor = new UpdateVisitor();
moel@176:     private SensorGadget gadget;
moel@295:     private Form plotForm;
moel@326:     private PlotPanel plotPanel;
moel@1: 
moel@156:     private UserOption showHiddenSensors;
moel@156:     private UserOption showPlot;
moel@156:     private UserOption showValue;
moel@156:     private UserOption showMin;
moel@156:     private UserOption showMax;
moel@156:     private UserOption startMinimized;
moel@156:     private UserOption minimizeToTray;
paulwerelds@198:     private UserOption minimizeOnClose;
moel@156:     private UserOption autoStart;
moel@156:     private UserOption readHddSensors;
moel@176:     private UserOption showGadget;
moel@295:     private UserRadioGroup plotLocation;
paulwerelds@223: 
paulwerelds@223:     private WmiProvider wmiProvider;
moel@156: 
moel@288:     private bool selectionDragging = false;
moel@288: 
moel@28:     public MainForm() {      
moel@1:       InitializeComponent();
moel@156: 
moel@291:       // check if the OpenHardwareMonitorLib assembly has the correct version
moel@291:       if (Assembly.GetAssembly(typeof(Computer)).GetName().Version !=
moel@291:         Assembly.GetExecutingAssembly().GetName().Version) {
moel@291:         MessageBox.Show(
moel@291:           "The version of the file OpenHardwareMonitorLib.dll is incompatible.",
moel@291:           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
moel@291:         Environment.Exit(0);
moel@291:       }
moel@291: 
moel@165:       this.settings = new PersistentSettings();      
moel@165:       this.settings.Load(Path.ChangeExtension(
paulwerelds@198:         Application.ExecutablePath, ".config"));
moel@165: 
moel@165:       this.unitManager = new UnitManager(settings);
moel@165: 
moel@304:       // make sure the buffers used for double buffering are not disposed 
moel@304:       // after each draw call
moel@304:       BufferedGraphicsManager.Current.MaximumBuffer =
moel@304:         Screen.PrimaryScreen.Bounds.Size;  
moel@304: 
moel@156:       // set the DockStyle here, to avoid conflicts with the MainMenu
moel@156:       this.splitContainer.Dock = DockStyle.Fill;
moel@202:             
moel@1:       this.Font = SystemFonts.MessageBoxFont;
moel@1:       treeView.Font = SystemFonts.MessageBoxFont;
moel@326: 
moel@326:       plotPanel = new PlotPanel(settings);
moel@326:       plotPanel.Font = SystemFonts.MessageBoxFont;
moel@326:       plotPanel.Dock = DockStyle.Fill;
moel@1:       
moel@133:       nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded;
moel@133:       nodeTextBoxText.DrawText += nodeTextBoxText_DrawText;
moel@133:       nodeTextBoxValue.DrawText += nodeTextBoxText_DrawText;
moel@133:       nodeTextBoxMin.DrawText += nodeTextBoxText_DrawText;
moel@133:       nodeTextBoxMax.DrawText += nodeTextBoxText_DrawText;
moel@141:       nodeTextBoxText.EditorShowing += nodeTextBoxText_EditorShowing;
moel@1: 
moel@113:       foreach (TreeColumn column in treeView.Columns) 
moel@165:         column.Width = Math.Max(20, Math.Min(400,
moel@166:           settings.GetValue("treeView.Columns." + column.Header + ".Width",
moel@113:           column.Width)));
moel@113: 
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@165:       treeView.Model = treeModel;
moel@40: 
moel@165:       this.computer = new Computer(settings);
moel@165: 
moel@165:       systemTray = new SystemTray(computer, settings);
moel@133:       systemTray.HideShowCommand += hideShowClick;
moel@133:       systemTray.ExitCommand += exitClick;
moel@1: 
moel@202:       int p = (int)Environment.OSVersion.Platform;
moel@202:       if ((p == 4) || (p == 128)) { // Unix
moel@287:         treeView.RowHeight = Math.Max(treeView.RowHeight, 18); 
moel@202:         splitContainer.BorderStyle = BorderStyle.None;
moel@202:         splitContainer.Border3DStyle = Border3DStyle.Adjust;
moel@202:         splitContainer.SplitterWidth = 4;
moel@202:         treeView.BorderStyle = BorderStyle.Fixed3D;
moel@202:         plotPanel.BorderStyle = BorderStyle.Fixed3D;
moel@202:         gadgetMenuItem.Visible = false;
moel@202:         minCloseMenuItem.Visible = false;
moel@269:         minTrayMenuItem.Visible = false;
moel@269:         startMinMenuItem.Visible = false;
moel@202:       } else { // Windows
moel@287:         treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18); 
moel@267: 
moel@202:         gadget = new SensorGadget(computer, settings, unitManager);
moel@244:         gadget.HideShowCommand += hideShowClick;
moel@244: 
moel@232:         wmiProvider = new WmiProvider(computer);
moel@327:       }
moel@86: 
moel@111:       plotColorPalette = new Color[13];
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@111:       plotColorPalette[8] = Color.RoyalBlue;
moel@111:       plotColorPalette[9] = Color.DeepPink;
moel@111:       plotColorPalette[10] = Color.MediumSeaGreen;
moel@111:       plotColorPalette[11] = Color.Olive;
moel@111:       plotColorPalette[12] = Color.Firebrick;
moel@327:       
moel@327:       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
moel@327:       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);        
moel@327: 
moel@327:       computer.Open();
moel@327: 
moel@327:       timer.Enabled = true;
moel@1: 
paulwerelds@223:       showHiddenSensors = new UserOption("hiddenMenuItem", false,
paulwerelds@223:         hiddenMenuItem, settings);
moel@156:       showHiddenSensors.Changed += delegate(object sender, EventArgs e) {
moel@156:         treeModel.ForceVisible = showHiddenSensors.Value;
moel@156:       };
moel@111: 
paulwerelds@223:       showValue = new UserOption("valueMenuItem", true, valueMenuItem,
paulwerelds@223:         settings);
moel@156:       showValue.Changed += delegate(object sender, EventArgs e) {
moel@156:         treeView.Columns[1].IsVisible = showValue.Value;
moel@156:       };
moel@122: 
moel@165:       showMin = new UserOption("minMenuItem", false, minMenuItem, settings);
moel@156:       showMin.Changed += delegate(object sender, EventArgs e) {
moel@156:         treeView.Columns[2].IsVisible = showMin.Value;
moel@156:       };
moel@156: 
moel@165:       showMax = new UserOption("maxMenuItem", true, maxMenuItem, settings);
moel@156:       showMax.Changed += delegate(object sender, EventArgs e) {
moel@156:         treeView.Columns[3].IsVisible = showMax.Value;
moel@156:       };
moel@156: 
paulwerelds@223:       startMinimized = new UserOption("startMinMenuItem", false,
paulwerelds@223:         startMinMenuItem, settings);
moel@156: 
paulwerelds@223:       minimizeToTray = new UserOption("minTrayMenuItem", true,
paulwerelds@223:         minTrayMenuItem, settings);
moel@156:       minimizeToTray.Changed += delegate(object sender, EventArgs e) {
moel@156:         systemTray.IsMainIconEnabled = minimizeToTray.Value;
moel@156:       };
moel@156: 
paulwerelds@223:       minimizeOnClose = new UserOption("minCloseMenuItem", false,
paulwerelds@223:         minCloseMenuItem, settings);
paulwerelds@198: 
paulwerelds@223:       autoStart = new UserOption(null, startupManager.Startup,
paulwerelds@223:         startupMenuItem, settings);
moel@156:       autoStart.Changed += delegate(object sender, EventArgs e) {
moel@185:         try {
moel@185:           startupManager.Startup = autoStart.Value;
moel@185:         } catch (InvalidOperationException) {
moel@185:           MessageBox.Show("Updating the auto-startup option failed.", "Error", 
moel@185:             MessageBoxButtons.OK, MessageBoxIcon.Error);
moel@185:           autoStart.Value = startupManager.Startup;
moel@185:         }
moel@156:       };
moel@156: 
paulwerelds@223:       readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem,
paulwerelds@223:         settings);
moel@156:       readHddSensors.Changed += delegate(object sender, EventArgs e) {
moel@156:         computer.HDDEnabled = readHddSensors.Value;
moel@156:       };
moel@156: 
paulwerelds@223:       showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem,
paulwerelds@223:         settings);
moel@176:       showGadget.Changed += delegate(object sender, EventArgs e) {
moel@202:         if (gadget != null) 
moel@202:           gadget.Visible = showGadget.Value;
moel@176:       };
moel@176: 
moel@299:       celsiusMenuItem.Checked = 
moel@299:         unitManager.TemperatureUnit == TemperatureUnit.Celsius;
moel@299:       fahrenheitMenuItem.Checked = !celsiusMenuItem.Checked;
moel@55: 
moel@295:       InitializePlotForm();
moel@295: 
moel@142:       startupMenuItem.Visible = startupManager.IsAvailable;
moel@125:       
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@128: 
moel@128:       // Make sure the settings are saved when the user logs off
paulwerelds@223:       Microsoft.Win32.SystemEvents.SessionEnded += delegate {
paulwerelds@223:         SaveConfiguration();
moel@304:       };
moel@1:     }
moel@295: 
moel@295:     private void InitializePlotForm() {
moel@295:       plotForm = new Form();
moel@295:       plotForm.FormBorderStyle = FormBorderStyle.SizableToolWindow;
moel@295:       plotForm.ShowInTaskbar = false;
moel@295:       plotForm.StartPosition = FormStartPosition.Manual;
moel@295:       this.AddOwnedForm(plotForm);
moel@295:       plotForm.Bounds = new Rectangle {
moel@295:         X = settings.GetValue("plotForm.Location.X", -100000),
moel@295:         Y = settings.GetValue("plotForm.Location.Y", 100),
moel@295:         Width = settings.GetValue("plotForm.Width", 600),
moel@295:         Height = settings.GetValue("plotForm.Height", 400)
moel@295:       };
moel@295: 
moel@295:       showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings);
moel@295:       plotLocation = new UserRadioGroup("plotLocation", 0,
moel@295:         new[] { plotWindowMenuItem, plotBottomMenuItem, plotRightMenuItem },
moel@295:         settings);
moel@295: 
moel@295:       showPlot.Changed += delegate(object sender, EventArgs e) {
moel@295:         if (plotLocation.Value == 0) {
moel@295:           if (showPlot.Value && this.Visible)
moel@295:             plotForm.Show();
moel@295:           else
moel@295:             plotForm.Hide();
moel@295:         } else {
moel@295:           splitContainer.Panel2Collapsed = !showPlot.Value;
moel@295:         }
moel@295:         treeView.Invalidate();
moel@295:       };
moel@295:       plotLocation.Changed += delegate(object sender, EventArgs e) {
moel@295:         switch (plotLocation.Value) {
moel@295:           case 0:
moel@295:             splitContainer.Panel2.Controls.Clear();
moel@295:             splitContainer.Panel2Collapsed = true;
moel@295:             plotForm.Controls.Add(plotPanel);
moel@295:             if (showPlot.Value && this.Visible)
moel@295:               plotForm.Show();
moel@295:             break;
moel@295:           case 1:
moel@295:             plotForm.Controls.Clear();
moel@295:             plotForm.Hide();
moel@295:             splitContainer.Orientation = Orientation.Horizontal;
moel@295:             splitContainer.Panel2.Controls.Add(plotPanel);
moel@295:             splitContainer.Panel2Collapsed = !showPlot.Value;
moel@295:             break;
moel@295:           case 2:
moel@295:             plotForm.Controls.Clear();
moel@295:             plotForm.Hide();
moel@295:             splitContainer.Orientation = Orientation.Vertical;
moel@295:             splitContainer.Panel2.Controls.Add(plotPanel);
moel@295:             splitContainer.Panel2Collapsed = !showPlot.Value;
moel@295:             break;
moel@295:         }
moel@295:       };
moel@297: 
moel@297:       plotForm.FormClosing += delegate(object sender, FormClosingEventArgs e) {
moel@297:         if (e.CloseReason == CloseReason.UserClosing) {
moel@297:           // just switch off the plotting when the user closes the form
moel@297:           if (plotLocation.Value == 0) {
moel@297:             showPlot.Value = false;
moel@297:           }
moel@297:           e.Cancel = true;
moel@295:         }
moel@295:       };
moel@297: 
moel@295:       EventHandler moveOrResizePlotForm = delegate(object sender, EventArgs e) {
moel@295:         if (plotForm.WindowState != FormWindowState.Minimized) {
moel@295:           settings.SetValue("plotForm.Location.X", plotForm.Bounds.X);
moel@295:           settings.SetValue("plotForm.Location.Y", plotForm.Bounds.Y);
moel@295:           settings.SetValue("plotForm.Width", plotForm.Bounds.Width);
moel@295:           settings.SetValue("plotForm.Height", plotForm.Bounds.Height);
moel@295:         }
moel@295:       };
moel@295:       plotForm.Move += moveOrResizePlotForm;
moel@295:       plotForm.Resize += moveOrResizePlotForm;
moel@295: 
moel@295:       plotForm.VisibleChanged += delegate(object sender, EventArgs e) {
moel@295:         Rectangle bounds = new Rectangle(plotForm.Location, plotForm.Size);
moel@295:         Screen screen = Screen.FromRectangle(bounds);
moel@295:         Rectangle intersection =
moel@295:           Rectangle.Intersect(screen.WorkingArea, bounds);
moel@295:         if (intersection.Width < Math.Min(16, bounds.Width) ||
moel@295:             intersection.Height < Math.Min(16, bounds.Height)) {
moel@295:           plotForm.Location = new Point(
moel@295:             screen.WorkingArea.Width / 2 - bounds.Width / 2,
moel@295:             screen.WorkingArea.Height / 2 - bounds.Height / 2);
moel@295:         }
moel@295:       };
moel@295: 
moel@295:       this.VisibleChanged += delegate(object sender, EventArgs e) {
moel@295:         if (this.Visible && showPlot.Value && plotLocation.Value == 0)
moel@295:           plotForm.Show();
moel@295:         else
moel@295:           plotForm.Hide();
moel@295:       };
moel@295:     }
moel@128:     
moel@64:     private void SubHardwareAdded(IHardware hardware, Node node) {
moel@327:       HardwareNode hardwareNode = 
moel@327:         new HardwareNode(hardware, settings, unitManager);
moel@327:       hardwareNode.PlotSelectionChanged += PlotSelectionChanged;
moel@327: 
moel@64:       node.Nodes.Add(hardwareNode);
moel@64:       foreach (IHardware subHardware in hardware.SubHardware)
moel@64:         SubHardwareAdded(subHardware, hardwareNode);  
moel@64:     }
moel@64: 
moel@327:     private void HardwareAdded(IHardware hardware) {      
moel@327:       SubHardwareAdded(hardware, root);
moel@327:       PlotSelectionChanged(this, null);
moel@1:     }
moel@1: 
moel@327:     private void HardwareRemoved(IHardware hardware) {
moel@327:       List<HardwareNode> nodesToRemove = new List<HardwareNode>();
moel@28:       foreach (Node node in root.Nodes) {
moel@28:         HardwareNode hardwareNode = node as HardwareNode;
moel@28:         if (hardwareNode != null && hardwareNode.Hardware == hardware)
moel@327:           nodesToRemove.Add(hardwareNode);
moel@28:       }
moel@327:       foreach (HardwareNode hardwareNode in nodesToRemove) {
moel@327:         root.Nodes.Remove(hardwareNode);
moel@327:         hardwareNode.PlotSelectionChanged -= PlotSelectionChanged;
moel@327:       }
moel@327:       PlotSelectionChanged(this, null);
moel@1:     }
moel@1: 
moel@111:     private void nodeTextBoxText_DrawText(object sender, DrawEventArgs e) {       
moel@111:       Node node = e.Node.Tag as Node;
moel@111:       if (node != null) {
moel@1:         Color color;
moel@111:         if (node.IsVisible) {
moel@111:           SensorNode sensorNode = node as SensorNode;
moel@111:           if (plotMenuItem.Checked && sensorNode != null &&
moel@111:             sensorPlotColors.TryGetValue(sensorNode.Sensor, out color))
moel@111:             e.TextColor = color;
moel@111:         } else {
moel@111:           e.TextColor = Color.DarkGray;
moel@111:         }
moel@1:       }
moel@1:     }
moel@1: 
moel@327:     private void PlotSelectionChanged(object sender, EventArgs e) {
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@327:         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: 
paulwerelds@223:     private void nodeTextBoxText_EditorShowing(object sender,
paulwerelds@223:       CancelEventArgs e) 
moel@141:     {
moel@141:       e.Cancel = !(treeView.CurrentNode != null &&
moel@275:         (treeView.CurrentNode.Tag is SensorNode || 
moel@275:          treeView.CurrentNode.Tag is HardwareNode));
moel@141:     }
moel@141: 
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@133:     private void exitClick(object sender, EventArgs e) {
paulwerelds@198:       Close();
moel@1:     }
moel@1: 
moel@86:     private void timer_Tick(object sender, EventArgs e) {
moel@110:       computer.Accept(updateVisitor);
moel@1:       treeView.Invalidate();
moel@1:       plotPanel.Invalidate();
paulwerelds@223:       systemTray.Redraw();
moel@202:       if (gadget != null)
moel@202:         gadget.Redraw();
paulwerelds@223: 
paulwerelds@223:       if (wmiProvider != null)
paulwerelds@223:         wmiProvider.Update();
moel@1:     }
moel@1: 
moel@128:     private void SaveConfiguration() {
moel@128:       foreach (TreeColumn column in treeView.Columns)
moel@166:         settings.SetValue("treeView.Columns." + column.Header + ".Width",
moel@113:           column.Width);
moel@113: 
moel@212:       string fileName = Path.ChangeExtension(
moel@212:           System.Windows.Forms.Application.ExecutablePath, ".config");
moel@212:       try {
moel@212:         settings.Save(fileName);
moel@212:       } catch (UnauthorizedAccessException) {
paulwerelds@214:         MessageBox.Show("Access to the path '" + fileName + "' is denied. " +
moel@284:           "The current settings could not be saved.",
moel@284:           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
moel@284:       } catch (IOException) {
moel@284:         MessageBox.Show("The path '" + fileName + "' is not writeable. " +
moel@284:           "The current settings could not be saved.",
moel@212:           "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
moel@212:       }
moel@128:     }
moel@128: 
paulwerelds@214:     private void MainForm_Load(object sender, EventArgs e) {
paulwerelds@214:       Rectangle newBounds = new Rectangle {
paulwerelds@214:         X = settings.GetValue("mainForm.Location.X", Location.X),
paulwerelds@214:         Y = settings.GetValue("mainForm.Location.Y", Location.Y),
paulwerelds@214:         Width = settings.GetValue("mainForm.Width", 470),
paulwerelds@214:         Height = settings.GetValue("mainForm.Height", 640)
paulwerelds@214:       };
paulwerelds@214: 
paulwerelds@223:       Rectangle fullWorkingArea = new Rectangle(int.MaxValue, int.MaxValue,
paulwerelds@214:         int.MinValue, int.MinValue);
paulwerelds@214: 
paulwerelds@214:       foreach (Screen screen in Screen.AllScreens)
paulwerelds@223:         fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds);
paulwerelds@214: 
paulwerelds@223:       Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds);
paulwerelds@214:       if (intersection.Width < 20 || intersection.Height < 20 ||
paulwerelds@214:         !settings.Contains("mainForm.Location.X")
paulwerelds@214:       ) {
paulwerelds@214:         newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) -
paulwerelds@214:                       (newBounds.Width/2);
paulwerelds@214: 
paulwerelds@214:         newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) -
paulwerelds@214:                       (newBounds.Height / 2);
paulwerelds@214:       }
paulwerelds@214: 
paulwerelds@214:       this.Bounds = newBounds;
paulwerelds@214:     }
paulwerelds@214:     
paulwerelds@214:     private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
moel@298:       Visible = false;      
moel@262:       systemTray.IsMainIconEnabled = false;
moel@262:       timer.Enabled = false;            
moel@28:       computer.Close();
moel@298:       SaveConfiguration();
moel@262:       systemTray.Dispose();
moel@1:     }
moel@1: 
moel@156:     private void aboutMenuItem_Click(object sender, EventArgs e) {
moel@1:       new AboutBox().ShowDialog();
moel@1:     }
moel@1: 
moel@1:     private void treeView_Click(object sender, EventArgs e) {
moel@275: 
moel@1:       MouseEventArgs m = e as MouseEventArgs;
moel@1:       if (m == null || m.Button != MouseButtons.Right)
moel@1:         return;
moel@1: 
paulwerelds@223:       NodeControlInfo info = treeView.GetNodeControlInfoAt(
paulwerelds@223:         new Point(m.X, m.Y)
paulwerelds@223:       );
moel@156:       treeView.SelectedNode = info.Node;
moel@156:       if (info.Node != null) {
moel@40:         SensorNode node = info.Node.Tag as SensorNode;
moel@40:         if (node != null && node.Sensor != null) {
moel@275:           treeContextMenu.MenuItems.Clear();
moel@63:           if (node.Sensor.Parameters.Length > 0) {
moel@156:             MenuItem item = new MenuItem("Parameters...");
moel@63:             item.Click += delegate(object obj, EventArgs args) {
moel@63:               ShowParameterForm(node.Sensor);
moel@63:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@63:           }
moel@156:           if (nodeTextBoxText.EditEnabled) {
moel@156:             MenuItem item = new MenuItem("Rename");
moel@141:             item.Click += delegate(object obj, EventArgs args) {
moel@156:               nodeTextBoxText.BeginEdit();
moel@141:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@176:           }
moel@111:           if (node.IsVisible) {
moel@156:             MenuItem item = new MenuItem("Hide");
moel@111:             item.Click += delegate(object obj, EventArgs args) {
moel@111:               node.IsVisible = false;
moel@111:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@111:           } else {
moel@156:             MenuItem item = new MenuItem("Unhide");
moel@111:             item.Click += delegate(object obj, EventArgs args) {
moel@111:               node.IsVisible = true;
moel@111:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@176:           }
moel@275:           treeContextMenu.MenuItems.Add(new MenuItem("-"));
moel@178:           {
moel@178:             MenuItem item = new MenuItem("Show in Tray");
moel@178:             item.Checked = systemTray.Contains(node.Sensor);
moel@178:             item.Click += delegate(object obj, EventArgs args) {
moel@178:               if (item.Checked)
moel@178:                 systemTray.Remove(node.Sensor);
moel@178:               else
moel@178:                 systemTray.Add(node.Sensor, true);
moel@178:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@178:           }
moel@211:           if (gadget != null) {
moel@178:             MenuItem item = new MenuItem("Show in Gadget");
moel@178:             item.Checked = gadget.Contains(node.Sensor);
moel@178:             item.Click += delegate(object obj, EventArgs args) {
moel@178:               if (item.Checked) {
moel@178:                 gadget.Remove(node.Sensor);
moel@178:               } else {
moel@178:                 gadget.Add(node.Sensor);
moel@178:               }
moel@178:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@178:           }
moel@247:           if (node.Sensor.Control != null) {
moel@275:             treeContextMenu.MenuItems.Add(new MenuItem("-"));
moel@247:             IControl control = node.Sensor.Control;
moel@247:             MenuItem controlItem = new MenuItem("Control");
moel@247:             MenuItem defaultItem = new MenuItem("Default");
moel@247:             defaultItem.Checked = control.ControlMode == ControlMode.Default;
moel@247:             controlItem.MenuItems.Add(defaultItem);
moel@247:             defaultItem.Click += delegate(object obj, EventArgs args) {
moel@247:               control.SetDefault();
moel@247:             };
moel@275:             MenuItem manualItem = new MenuItem("Manual");
moel@247:             controlItem.MenuItems.Add(manualItem);
moel@247:             manualItem.Checked = control.ControlMode == ControlMode.Software;
moel@247:             for (int i = 0; i <= 100; i += 5) {
moel@247:               if (i <= control.MaxSoftwareValue &&
moel@275:                   i >= control.MinSoftwareValue) {
moel@247:                 MenuItem item = new MenuItem(i + " %");
moel@247:                 manualItem.MenuItems.Add(item);
moel@247:                 item.Checked = control.ControlMode == ControlMode.Software &&
moel@247:                   Math.Round(control.SoftwareValue) == i;
moel@247:                 int softwareValue = i;
moel@247:                 item.Click += delegate(object obj, EventArgs args) {
moel@247:                   control.SetSoftware(softwareValue);
moel@247:                 };
moel@247:               }
moel@247:             }
moel@275:             treeContextMenu.MenuItems.Add(controlItem);
moel@247:           }
moel@176: 
moel@275:           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
moel@275:         }
moel@275: 
moel@275:         HardwareNode hardwareNode = info.Node.Tag as HardwareNode;
moel@275:         if (hardwareNode != null && hardwareNode.Hardware != null) {
moel@275:           treeContextMenu.MenuItems.Clear();
moel@275: 
moel@275:           if (nodeTextBoxText.EditEnabled) {
moel@275:             MenuItem item = new MenuItem("Rename");
moel@275:             item.Click += delegate(object obj, EventArgs args) {
moel@275:               nodeTextBoxText.BeginEdit();
moel@275:             };
moel@275:             treeContextMenu.MenuItems.Add(item);
moel@275:           }
moel@275: 
moel@275:           treeContextMenu.Show(treeView, new Point(m.X, m.Y));
moel@40:         }
moel@40:       }
moel@1:     }
moel@1: 
moel@156:     private void saveReportMenuItem_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@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;
paulwerelds@198:       const int SC_CLOSE = 0xF060;
paulwerelds@198: 
moel@156:       if (minimizeToTray.Value && 
moel@335:         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_MINIMIZE) {
moel@82:         SysTrayHideShow();
moel@335:       } else if (minimizeOnClose.Value &&
moel@335:         m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_CLOSE) {
paulwerelds@198:         /*
paulwerelds@198:          * Apparently the user wants to minimize rather than close
paulwerelds@198:          * Now we still need to check if we're going to the tray or not
paulwerelds@198:          * 
paulwerelds@198:          * Note: the correct way to do this would be to send out SC_MINIMIZE,
paulwerelds@198:          * but since the code here is so simple,
paulwerelds@198:          * that would just be a waste of time.
paulwerelds@198:          */
paulwerelds@198:         if (minimizeToTray.Value)
paulwerelds@198:           SysTrayHideShow();
paulwerelds@198:         else
paulwerelds@198:           WindowState = FormWindowState.Minimized;
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@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@299:     private void celsiusMenuItem_Click(object sender, EventArgs e) {
moel@299:       celsiusMenuItem.Checked = true;
moel@156:       fahrenheitMenuItem.Checked = false;
moel@299:       unitManager.TemperatureUnit = TemperatureUnit.Celsius;
moel@122:     }
moel@122: 
moel@156:     private void fahrenheitMenuItem_Click(object sender, EventArgs e) {
moel@299:       celsiusMenuItem.Checked = false;
moel@156:       fahrenheitMenuItem.Checked = true;
moel@165:       unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit;
moel@122:     }
moel@150: 
moel@156:     private void sumbitReportMenuItem_Click(object sender, EventArgs e) 
moel@150:     {
moel@150:       ReportForm form = new ReportForm();
moel@150:       form.Report = computer.GetReport();
moel@150:       form.ShowDialog();      
moel@150:     }
moel@151: 
moel@151:     private void resetMinMaxMenuItem_Click(object sender, EventArgs e) {
moel@159:       computer.Accept(new SensorVisitor(delegate(ISensor sensor) {
moel@159:         sensor.ResetMin();
moel@159:         sensor.ResetMax();
moel@159:       }));
moel@151:     }
moel@241: 
moel@241:     private void MainForm_MoveOrResize(object sender, EventArgs e) {
moel@241:       if (WindowState != FormWindowState.Minimized) {
moel@241:         settings.SetValue("mainForm.Location.X", Bounds.X);
moel@241:         settings.SetValue("mainForm.Location.Y", Bounds.Y);
moel@241:         settings.SetValue("mainForm.Width", Bounds.Width);
moel@241:         settings.SetValue("mainForm.Height", Bounds.Height);
moel@241:       }
moel@241:     }
moel@262: 
moel@262:     private void resetClick(object sender, EventArgs e) {
moel@262:       // disable the fallback MainIcon during reset, otherwise icon visibility
moel@262:       // might be lost 
moel@262:       systemTray.IsMainIconEnabled = false;
moel@262:       computer.Close();
moel@262:       computer.Open();
moel@262:       // restore the MainIcon setting
moel@262:       systemTray.IsMainIconEnabled = minimizeToTray.Value;
moel@262:     }
moel@287: 
moel@287:     private void treeView_MouseMove(object sender, MouseEventArgs e) {
moel@288:       selectionDragging = selectionDragging &
moel@288:         (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0; 
moel@288: 
moel@288:       if (selectionDragging)
moel@288:         treeView.SelectedNode = treeView.GetNodeAt(e.Location);     
moel@288:     }
moel@288: 
moel@288:     private void treeView_MouseDown(object sender, MouseEventArgs e) {
moel@288:       selectionDragging = true;
moel@288:     }
moel@288: 
moel@288:     private void treeView_MouseUp(object sender, MouseEventArgs e) {
moel@288:       selectionDragging = false;
moel@287:     }
moel@1:   }
moel@1: }