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 . moel@1: Portions created by the Initial Developer are Copyright (C) 2009-2010 moel@1: the Initial Developer. All Rights Reserved. moel@1: paulwerelds@223: Contributor(s): Paul Werelds 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.Drawing; moel@83: using System.IO; 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 sensorPlotColors = moel@1: new Dictionary(); 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@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; paulwerelds@223: paulwerelds@223: private WmiProvider wmiProvider; moel@156: moel@28: public MainForm() { moel@1: InitializeComponent(); moel@156: 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@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@63: plotPanel.Font = SystemFonts.MessageBoxFont; moel@1: moel@133: nodeCheckBox.IsVisibleValueNeeded += nodeCheckBox_IsVisibleValueNeeded; moel@133: nodeCheckBox.CheckStateChanged += UpdatePlotSelection; 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@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@202: } else { // Windows moel@202: gadget = new SensorGadget(computer, settings, unitManager); moel@232: wmiProvider = new WmiProvider(computer); moel@202: } moel@176: moel@28: computer.HardwareAdded += new HardwareEventHandler(HardwareAdded); moel@232: computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved); paulwerelds@223: moel@28: computer.Open(); moel@28: moel@86: timer.Enabled = true; 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@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: moel@165: showPlot = new UserOption("plotMenuItem", false, plotMenuItem, settings); moel@156: showPlot.Changed += delegate(object sender, EventArgs e) { moel@156: splitContainer.Panel2Collapsed = !showPlot.Value; moel@156: treeView.Invalidate(); moel@156: }; moel@1: 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: UpdatePlotSelection(null, null); 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@156: celciusMenuItem.Checked = moel@165: unitManager.TemperatureUnit == TemperatureUnit.Celcius; moel@156: fahrenheitMenuItem.Checked = !celciusMenuItem.Checked; moel@55: 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(); paulwerelds@223: }; moel@1: } moel@128: moel@64: private void SubHardwareAdded(IHardware hardware, Node node) { moel@165: Node hardwareNode = new HardwareNode(hardware, settings, unitManager); 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@165: Node hardwareNode = new HardwareNode(hardware, settings, unitManager); 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 nodesToRemove = new List(); 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@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@1: private void UpdatePlotSelection(object sender, moel@1: TreePathEventArgs e) moel@1: { moel@1: List selected = new List(); moel@1: IDictionary colors = new Dictionary(); 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: paulwerelds@223: private void nodeTextBoxText_EditorShowing(object sender, paulwerelds@223: CancelEventArgs e) moel@141: { moel@141: e.Cancel = !(treeView.CurrentNode != null && moel@141: treeView.CurrentNode.Tag is SensorNode); 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@14: if (WindowState != FormWindowState.Minimized) { paulwerelds@214: settings.SetValue("mainForm.Location.X", Bounds.X); paulwerelds@214: settings.SetValue("mainForm.Location.Y", Bounds.Y); paulwerelds@214: settings.SetValue("mainForm.Width", Bounds.Width); paulwerelds@214: settings.SetValue("mainForm.Height", Bounds.Height); moel@14: } moel@86: 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@212: "The current seetings 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@156: Visible = false; moel@128: SaveConfiguration(); moel@128: moel@86: timer.Enabled = false; moel@133: systemTray.Dispose(); moel@28: computer.Close(); 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@1: 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@156: sensorContextMenu.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@156: sensorContextMenu.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@156: sensorContextMenu.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@156: sensorContextMenu.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@156: sensorContextMenu.MenuItems.Add(item); moel@176: } moel@176: sensorContextMenu.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@178: sensorContextMenu.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@178: sensorContextMenu.MenuItems.Add(item); moel@178: } moel@176: moel@156: sensorContextMenu.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@28: m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MINIMIZE) { moel@82: SysTrayHideShow(); paulwerelds@198: } else if(minimizeOnClose.Value && paulwerelds@198: m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == 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@156: private void celciusMenuItem_Click(object sender, EventArgs e) { moel@156: celciusMenuItem.Checked = true; moel@156: fahrenheitMenuItem.Checked = false; moel@165: unitManager.TemperatureUnit = TemperatureUnit.Celcius; moel@122: } moel@122: moel@156: private void fahrenheitMenuItem_Click(object sender, EventArgs e) { moel@156: celciusMenuItem.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@1: } moel@1: }