Mercurial > servermonitor
comparison ServerMonitor/Forms/ServerSummaryForm.cs @ 16:7626b099aefd
More comments.
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Tue, 30 Apr 2019 20:40:58 -0400 |
parents | 75ca86e0862c |
children | b3128fe10d57 |
comparison
equal
deleted
inserted
replaced
15:23f2e0da1094 | 16:7626b099aefd |
---|---|
1 using NAppUpdate.Framework; | 1 using NAppUpdate.Framework; |
2 using NAppUpdate.Framework.Sources; | 2 using NAppUpdate.Framework.Sources; |
3 using NAppUpdate.Framework.Tasks; | |
4 using ServerMonitorApp.Properties; | 3 using ServerMonitorApp.Properties; |
5 using System; | 4 using System; |
6 using System.Collections.Generic; | 5 using System.Collections.Generic; |
7 using System.ComponentModel; | 6 using System.ComponentModel; |
8 using System.Data; | 7 using System.Data; |
9 using System.Drawing; | 8 using System.Drawing; |
10 using System.Linq; | 9 using System.Linq; |
11 using System.Text; | |
12 using System.Windows.Forms; | 10 using System.Windows.Forms; |
13 | 11 |
14 namespace ServerMonitorApp | 12 namespace ServerMonitorApp |
15 { | 13 { |
14 /// <summary>Main application form that shows an overview of all servers.</summary> | |
16 public partial class ServerSummaryForm : Form | 15 public partial class ServerSummaryForm : Form |
17 { | 16 { |
18 private readonly Dictionary<Server, ServerForm> serverForms = new Dictionary<Server, ServerForm>(); | 17 private readonly Dictionary<Server, ServerForm> serverForms = new Dictionary<Server, ServerForm>(); |
19 private ServerMonitor monitor; | 18 private ServerMonitor monitor; |
20 | 19 |
21 public ServerSummaryForm() | 20 public ServerSummaryForm() |
22 { | 21 { |
23 InitializeComponent(); | 22 InitializeComponent(); |
24 } | 23 } |
25 | 24 |
26 public void AlertServerForm(Check check) | |
27 { | |
28 bool existingForm = serverForms.ContainsKey(check.Server); | |
29 ServerForm form = ShowServerForm(check.Server, false); | |
30 Win32Helpers.FlashWindowEx(form); | |
31 if (!existingForm) | |
32 { | |
33 form.ShowLog(check); | |
34 } | |
35 } | |
36 | |
37 public void ShowBalloon(CheckResult result) | |
38 { | |
39 string title = string.Format("{0}: {1} failed", result.Check.Server.Name, result.Check.Name); | |
40 NotifyIcon.Tag = result; | |
41 NotifyIcon.ShowBalloonTip(30000, title, result.Message, GetToolTipIcon(result.CheckStatus)); | |
42 } | |
43 | |
44 private void ServerSummaryForm_Load(object sender, EventArgs e) | 25 private void ServerSummaryForm_Load(object sender, EventArgs e) |
45 { | 26 { |
27 // Restore the window size from the previous session. | |
46 Size size = Settings.Default.SummaryFormSize; | 28 Size size = Settings.Default.SummaryFormSize; |
47 if (size.Height > 0 && size.Width > 0) | 29 if (size.Height > 0 && size.Width > 0) |
48 Size = size; | 30 Size = size; |
49 | 31 |
32 // Resize the images in buttons to fit the button size. | |
50 Helpers.FormatImageButton(NewServerButton); | 33 Helpers.FormatImageButton(NewServerButton); |
51 Helpers.FormatImageButton(SettingsButton); | 34 Helpers.FormatImageButton(SettingsButton); |
35 // Create the global server monitor object. | |
52 monitor = new ServerMonitor(this); | 36 monitor = new ServerMonitor(this); |
37 // Load the server configuration file. | |
53 while (true) | 38 while (true) |
54 { | 39 { |
55 try | 40 try |
56 { | 41 { |
42 // If the configuration file is loaded successfully, proceed. | |
57 monitor.LoadServers(); | 43 monitor.LoadServers(); |
58 break; | 44 break; |
59 } | 45 } |
60 catch (Exception ex) | 46 catch (Exception ex) |
61 { | 47 { |
48 // If there was an error loading the config file, show it. | |
62 DialogResult result = MessageBox.Show("Could not load servers. Please fix or delete the file " + monitor.ConfigFile + Environment.NewLine + Environment.NewLine | 49 DialogResult result = MessageBox.Show("Could not load servers. Please fix or delete the file " + monitor.ConfigFile + Environment.NewLine + Environment.NewLine |
63 + "Error details:" + Environment.NewLine + ex.GetAllMessages(), | 50 + "Error details:" + Environment.NewLine + ex.GetAllMessages(), |
64 "Error loading servers", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); | 51 "Error loading servers", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); |
52 // If the error message was cancelled, exit. Otherwise, retry by continuing the loop. | |
65 if (result == DialogResult.Cancel) | 53 if (result == DialogResult.Cancel) |
66 { | 54 { |
67 Environment.Exit(1); | 55 Environment.Exit(1); |
68 } | 56 } |
69 } | 57 } |
70 } | 58 } |
59 // Listen to server monitor events. | |
71 monitor.CheckStatusChanged += Monitor_CheckStatusChanged; | 60 monitor.CheckStatusChanged += Monitor_CheckStatusChanged; |
61 // Show the servers. | |
72 RefreshDisplay(); | 62 RefreshDisplay(); |
63 // If any servers have encrypted private keys, attempt to open them immediately | |
64 // rather than interrupting the user later when they are first used. | |
73 CollectPrivateKeyPasswords(); | 65 CollectPrivateKeyPasswords(); |
74 CheckForUpdate(); | 66 CheckForUpdate(); |
75 } | 67 } |
76 | 68 |
69 /// <summary>Shows a form to edit or create a server.</summary> | |
70 /// <param name="server">The server to edit. If null, a new server will be created.</param> | |
71 /// <param name="activate">Whether the server form should be activated.</param> | |
72 /// <returns>The created or existing server for for the server.</returns> | |
77 private ServerForm ShowServerForm(Server server, bool activate = true) | 73 private ServerForm ShowServerForm(Server server, bool activate = true) |
78 { | 74 { |
79 bool isNewServer = false; | 75 bool isNewServer = false; |
80 if (server == null) | 76 if (server == null) |
81 { | 77 { |
78 // Create a new server if none was given. | |
82 server = new Server(); | 79 server = new Server(); |
80 // The server is added to the server monitor immediately so that | |
81 // checks can be created and run. If the server was created by | |
82 // mistake, it will automatically be removed when the form is closed | |
83 // as long as no information was entered into the form. | |
83 monitor.AddServer(server); | 84 monitor.AddServer(server); |
84 isNewServer = true; | 85 isNewServer = true; |
85 } | 86 } |
86 if (serverForms.TryGetValue(server, out ServerForm form)) | 87 if (serverForms.TryGetValue(server, out ServerForm form)) |
87 { | 88 { |
89 // If the server form is already open, just activate it if requested. | |
88 if (activate) | 90 if (activate) |
89 form.Activate(); | 91 form.Activate(); |
90 } | 92 } |
91 else | 93 else |
92 { | 94 { |
95 // Open a new server form for the server. | |
93 form = new ServerForm(monitor, server, isNewServer); | 96 form = new ServerForm(monitor, server, isNewServer); |
97 // Keep track of the form so it can be activated later if the server is clicked again. | |
94 serverForms[server] = form; | 98 serverForms[server] = form; |
95 form.FormClosing += ServerForm_FormClosing; | 99 form.FormClosing += ServerForm_FormClosing; |
96 form.Show(activate); | 100 form.Show(activate); |
97 } | 101 } |
98 return form; | 102 return form; |
99 } | 103 } |
100 | 104 |
105 /// <summary>Refreshes the server list with the server monitor data.</summary> | |
101 private void RefreshDisplay() | 106 private void RefreshDisplay() |
102 { | 107 { |
108 // Delete all server controls and recreate them. | |
103 ServerPanel.Controls.Clear(); | 109 ServerPanel.Controls.Clear(); |
104 foreach (Server server in monitor.Servers) | 110 foreach (Server server in monitor.Servers) |
105 { | 111 { |
112 // Subscribe to server events. | |
106 server.EnabledChanged -= Server_EnabledChanged; | 113 server.EnabledChanged -= Server_EnabledChanged; |
107 server.EnabledChanged += Server_EnabledChanged; | 114 server.EnabledChanged += Server_EnabledChanged; |
115 // Create a server control and add it to the panel. | |
108 ServerSummaryControl control = new ServerSummaryControl(server); | 116 ServerSummaryControl control = new ServerSummaryControl(server); |
109 control.ContextMenuStrip = ServerContextMenu; | 117 control.ContextMenuStrip = ServerContextMenu; |
110 control.Click += ServerSummaryControl_Click; | 118 control.Click += ServerSummaryControl_Click; |
111 ServerPanel.Controls.Add(control); | 119 ServerPanel.Controls.Add(control); |
112 } | 120 } |
121 // Refresh the form icon that depends on the status of all servers. | |
113 UpdateIcon(); | 122 UpdateIcon(); |
114 } | 123 } |
115 | 124 |
125 /// <summary>Refreshes a single server control.</summary> | |
126 /// <param name="server">The server to refresh.</param> | |
116 private void RefreshServer(Server server) | 127 private void RefreshServer(Server server) |
117 { | 128 { |
118 ServerPanel.Controls.Cast<ServerSummaryControl>().FirstOrDefault(c => c.Server == server).Refresh(); | 129 ServerPanel.Controls.Cast<ServerSummaryControl>().FirstOrDefault(c => c.Server == server).Refresh(); |
130 // The server's status might have changed, so refresh the form icon. | |
119 UpdateIcon(); | 131 UpdateIcon(); |
120 } | 132 } |
121 | 133 |
134 /// <summary>Flashes the taskbar button for a server form.</summary> | |
135 /// <param name="check">The check that needs attention.</param> | |
136 public void AlertServerForm(Check check) | |
137 { | |
138 // Show the form, but don't activate it since the user did not initiate this event. | |
139 ServerForm form = ShowServerForm(check.Server, false); | |
140 // Flash the taskbar button. | |
141 Win32Helpers.FlashWindowEx(form); | |
142 // If the form was not already open, focus the Log tab and display | |
143 // only the log entries for this check. Do not do this if the form | |
144 // was already open since the user might be in the middle of doing | |
145 // something with it. | |
146 if (!serverForms.ContainsKey(check.Server)) | |
147 { | |
148 form.ShowLog(check); | |
149 } | |
150 } | |
151 | |
152 /// <summary>Shows a balloon popup with the results of a failed check.</summary> | |
153 /// <param name="check">The check that failed.</param> | |
154 public void ShowBalloon(CheckResult result) | |
155 { | |
156 string title = string.Format("{0}: {1} failed", result.Check.Server.Name, result.Check.Name); | |
157 NotifyIcon.Tag = result; | |
158 NotifyIcon.ShowBalloonTip(30000, title, result.Message, GetToolTipIcon(result.CheckStatus)); | |
159 } | |
160 | |
161 /// <summary>Updates the form icon to reflect a summary of the status of all servers.</summary> | |
122 private void UpdateIcon() | 162 private void UpdateIcon() |
123 { | 163 { |
164 // The status for the summary icon is the most severe status of all servers. | |
165 // When performing the comparison: | |
166 // - Enabled servers use their current status. | |
167 // - If a server is disabled due to a locked private key, report a warning. | |
168 // Otherwise, report success to effectively ignore it. | |
169 // The integer value of the CheckStatus enum increases with the severity, | |
170 // so the maximum value of all servers gives the most severe status. | |
124 CheckStatus status = monitor.Servers | 171 CheckStatus status = monitor.Servers |
125 .Select(s => s.Enabled | 172 .Select(s => s.Enabled |
126 ? s.Status | 173 ? s.Status |
127 : s.KeyStatus == KeyStatus.NeedPassword ? CheckStatus.Warning : CheckStatus.Success) | 174 : s.KeyStatus == KeyStatus.NeedPassword ? CheckStatus.Warning : CheckStatus.Success) |
128 .DefaultIfEmpty(CheckStatus.Success) | 175 .DefaultIfEmpty(CheckStatus.Success) |
129 .Max(); | 176 .Max(); |
130 Icon = status.GetIcon(); | 177 Icon = status.GetIcon(); |
131 NotifyIcon.Icon = Icon; | 178 NotifyIcon.Icon = Icon; |
132 } | 179 } |
133 | 180 |
181 /// <summary>Prompts the user for the passwords to open all encrypted private keys.</summary> | |
134 private void CollectPrivateKeyPasswords() | 182 private void CollectPrivateKeyPasswords() |
135 { | 183 { |
184 // List of paths to keyfiles. | |
136 List<string> triedKeys = new List<string>(); | 185 List<string> triedKeys = new List<string>(); |
137 foreach (Server server in monitor.Servers) | 186 foreach (Server server in monitor.Servers) |
138 { | 187 { |
188 // If the same private key is used for multiple servers, don't prompt | |
189 // the user multiple times to open the same keyfile. | |
139 if (triedKeys.Contains(server.KeyFile)) | 190 if (triedKeys.Contains(server.KeyFile)) |
140 continue; | 191 continue; |
192 // Show the prompt. | |
141 ServerForm.OpenPrivateKey(monitor, server, this); | 193 ServerForm.OpenPrivateKey(monitor, server, this); |
194 // Keep track of the keyfile so we don't needlessly ask again. | |
142 triedKeys.Add(server.KeyFile); | 195 triedKeys.Add(server.KeyFile); |
143 } | 196 } |
144 } | 197 } |
145 | 198 |
199 /// <summary>Refreshes a server control when the server state changes.</summary> | |
146 private void Server_EnabledChanged(object sender, EventArgs e) | 200 private void Server_EnabledChanged(object sender, EventArgs e) |
147 { | 201 { |
148 RefreshServer((Server)sender); | 202 RefreshServer((Server)sender); |
149 } | 203 } |
150 | 204 |
205 /// <summary>Refreshes a server control when the server status might have changed.</summary> | |
151 private void Monitor_CheckStatusChanged(object sender, CheckStatusChangedEventArgs e) | 206 private void Monitor_CheckStatusChanged(object sender, CheckStatusChangedEventArgs e) |
152 { | 207 { |
153 if (e.CheckResult != null) | 208 if (e.CheckResult != null) |
154 { | 209 { |
155 RefreshServer(e.Check.Server); | 210 RefreshServer(e.Check.Server); |
156 } | 211 } |
157 } | 212 } |
158 | 213 |
214 /// <summary>Gets a Windows tooltip icon based on the severity of the message.</summary> | |
215 /// <param name="status">The status of the check that will be reported in the balloon tip.</param> | |
159 private ToolTipIcon GetToolTipIcon(CheckStatus status) | 216 private ToolTipIcon GetToolTipIcon(CheckStatus status) |
160 { | 217 { |
161 switch (status) | 218 switch (status) |
162 { | 219 { |
163 case CheckStatus.Error: return ToolTipIcon.Error; | 220 case CheckStatus.Error: return ToolTipIcon.Error; |
165 case CheckStatus.Information: return ToolTipIcon.Info; | 222 case CheckStatus.Information: return ToolTipIcon.Info; |
166 default: return ToolTipIcon.None; | 223 default: return ToolTipIcon.None; |
167 } | 224 } |
168 } | 225 } |
169 | 226 |
227 /// <summary>Shows a server form when a server control is clicked.</summary> | |
170 private void ServerSummaryControl_Click(object sender, EventArgs e) | 228 private void ServerSummaryControl_Click(object sender, EventArgs e) |
171 { | 229 { |
172 ShowServerForm(((ServerSummaryControl)sender).Server); | 230 ShowServerForm(((ServerSummaryControl)sender).Server); |
173 } | 231 } |
174 | 232 |
233 /// <summary>Handles the closing of a server form.</summary> | |
175 private void ServerForm_FormClosing(object sender, FormClosingEventArgs e) | 234 private void ServerForm_FormClosing(object sender, FormClosingEventArgs e) |
176 { | 235 { |
177 ServerForm form = (ServerForm)sender; | 236 ServerForm form = (ServerForm)sender; |
178 form.FormClosing -= ServerForm_FormClosing; | 237 form.FormClosing -= ServerForm_FormClosing; |
179 Server server = form.Server; | 238 Server server = form.Server; |
239 // Remove the closed form from the list of open forms. | |
180 serverForms.Remove(form.Server); | 240 serverForms.Remove(form.Server); |
241 // If there is no user data associated with the server, it can be deleted. | |
242 // This usually happens when the New Server button is clicked and the server form | |
243 // is closed without entering any information. | |
181 if (server.IsEmpty()) | 244 if (server.IsEmpty()) |
182 { | 245 { |
183 monitor.DeleteServer(server); | 246 monitor.DeleteServer(server); |
184 } | 247 } |
185 RefreshDisplay(); | 248 RefreshDisplay(); |
186 } | 249 } |
187 | 250 |
251 /// <summary>Shows a server form to create a new server.</summary> | |
188 private void NewServerButton_Click(object sender, EventArgs e) | 252 private void NewServerButton_Click(object sender, EventArgs e) |
189 { | 253 { |
190 ShowServerForm(null); | 254 ShowServerForm(null); |
191 } | 255 } |
192 | 256 |
257 /// <summary>Hides the main form instead of exiting the application based on user preferences.</summary> | |
258 /// <remarks>Allows the monitor to run in the background without being shown in the taskbar.</remarks> | |
193 private void ServerSummaryForm_FormClosing(object sender, FormClosingEventArgs e) | 259 private void ServerSummaryForm_FormClosing(object sender, FormClosingEventArgs e) |
194 { | 260 { |
195 if ((e.CloseReason == CloseReason.None || e.CloseReason == CloseReason.UserClosing) && Settings.Default.HideToNotificationArea) | 261 if ((e.CloseReason == CloseReason.None || e.CloseReason == CloseReason.UserClosing) && Settings.Default.HideToNotificationArea) |
196 { | 262 { |
197 Hide(); | 263 Hide(); |
198 e.Cancel = true; | 264 e.Cancel = true; |
199 } | 265 } |
200 } | 266 } |
201 | 267 |
268 /// <summary>Shows the settings form.</summary> | |
202 private void SettingsButton_Click(object sender, EventArgs e) | 269 private void SettingsButton_Click(object sender, EventArgs e) |
203 { | 270 { |
204 new SettingsForm().Show(); | 271 new SettingsForm().Show(); |
205 } | 272 } |
206 | 273 |
274 /// <summary>Shows the details of a failed check when the balloon notification is clicked.</summary> | |
207 private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e) | 275 private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e) |
208 { | 276 { |
209 CheckResult result = (CheckResult)(sender as NotifyIcon).Tag; | 277 CheckResult result = (CheckResult)(sender as NotifyIcon).Tag; |
210 ServerForm form = ShowServerForm(result.Check.Server); | 278 ServerForm form = ShowServerForm(result.Check.Server); |
211 form.ShowLog(result.Check); | 279 form.ShowLog(result.Check); |
212 form.WindowState = FormWindowState.Normal; | 280 form.WindowState = FormWindowState.Normal; |
213 } | 281 } |
214 | 282 |
283 /// <summary>Handles the server context menu.</summary> | |
215 private void ServerContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) | 284 private void ServerContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) |
216 { | 285 { |
217 Server server = GetClickedServer((ContextMenuStrip)e.ClickedItem.Owner); | 286 Server server = GetClickedServer((ContextMenuStrip)e.ClickedItem.Owner); |
218 if (e.ClickedItem == DeleteServerMenuItem) | 287 if (e.ClickedItem == DeleteServerMenuItem) |
219 { | 288 { |
289 // Close the menu immediately so it doesn't stay open while the messagebox is shown. | |
220 ServerContextMenu.Close(); | 290 ServerContextMenu.Close(); |
291 // Show the server delete confirmation dialog. No option to not ask again | |
292 // since it's a rare and very destructive event. | |
221 DialogResult result = MessageBox.Show( | 293 DialogResult result = MessageBox.Show( |
222 string.Format("The server \"{0}\" and its {1} {2} will be deleted.", server.Name, server.Checks.Count, server.Checks.Count == 1 ? "check" : "checks"), | 294 string.Format("The server \"{0}\" and its {1} {2} will be deleted.", server.Name, server.Checks.Count, server.Checks.Count == 1 ? "check" : "checks"), |
223 "Delete server", | 295 "Delete server", |
224 MessageBoxButtons.OKCancel, | 296 MessageBoxButtons.OKCancel, |
225 MessageBoxIcon.Warning ); | 297 MessageBoxIcon.Warning); |
226 if (result == DialogResult.OK) | 298 if (result == DialogResult.OK) |
227 { | 299 { |
228 monitor.DeleteServer(server); | 300 monitor.DeleteServer(server); |
229 RefreshDisplay(); | 301 RefreshDisplay(); |
230 } | 302 } |
232 else if (e.ClickedItem == ToggleEnableServerMenuItem) | 304 else if (e.ClickedItem == ToggleEnableServerMenuItem) |
233 { | 305 { |
234 bool enable = ToggleEnableServerMenuItem.Text == "Enable"; | 306 bool enable = ToggleEnableServerMenuItem.Text == "Enable"; |
235 if (enable) | 307 if (enable) |
236 { | 308 { |
309 // Close the menu immediately so it doesn't stay open while the messagebox is shown. | |
237 ServerContextMenu.Close(); | 310 ServerContextMenu.Close(); |
311 // Attempt to open the private key for the server immediately since it has not | |
312 // been opened yet. | |
238 ServerForm.OpenPrivateKey(monitor, server, this); | 313 ServerForm.OpenPrivateKey(monitor, server, this); |
239 } | 314 } |
240 server.Enabled = enable; | 315 server.Enabled = enable; |
241 RefreshDisplay(); | 316 RefreshDisplay(); |
242 } | 317 } |
243 } | 318 } |
244 | 319 |
320 /// <summary>Activates the appropriate Enable/Disable menu option based on the server's current state.</summary> | |
245 private void ServerContextMenu_Opening(object sender, CancelEventArgs e) | 321 private void ServerContextMenu_Opening(object sender, CancelEventArgs e) |
246 { | 322 { |
247 Server server = GetClickedServer((ContextMenuStrip)sender); | 323 Server server = GetClickedServer((ContextMenuStrip)sender); |
248 ToggleEnableServerMenuItem.Text = server.Enabled ? "Disable" : "Enable"; | 324 ToggleEnableServerMenuItem.Text = server.Enabled ? "Disable" : "Enable"; |
249 } | 325 } |
250 | 326 |
327 /// <summary>Gets the server corresponding to a server context menu.</summary> | |
251 private Server GetClickedServer(ContextMenuStrip menu) | 328 private Server GetClickedServer(ContextMenuStrip menu) |
252 { | 329 { |
253 return ((ServerSummaryControl)menu.SourceControl).Server; | 330 return ((ServerSummaryControl)menu.SourceControl).Server; |
254 } | 331 } |
255 | 332 |
333 /// <summary>Saves the window size after it is resized so it can be restored next time the program is run.</summary> | |
256 private void ServerSummaryForm_ResizeEnd(object sender, EventArgs e) | 334 private void ServerSummaryForm_ResizeEnd(object sender, EventArgs e) |
257 { | 335 { |
258 Settings.Default.SummaryFormSize = Size; | 336 Settings.Default.SummaryFormSize = Size; |
259 Settings.Default.Save(); | 337 Settings.Default.Save(); |
260 } | 338 } |
261 | 339 |
340 /// <summary>Shows the main form when the WM_SHOWMONITOR message is received.</summary> | |
341 /// <remarks> | |
342 /// This is used to make this a single-instance application. When a second copy of the program | |
343 /// is launched, it sends this message to activate the first copy and then exits. | |
344 /// </remarks> | |
262 protected override void WndProc(ref Message m) | 345 protected override void WndProc(ref Message m) |
263 { | 346 { |
264 if (m.Msg == Win32Helpers.WM_SHOWMONITOR) | 347 if (m.Msg == Win32Helpers.WM_SHOWMONITOR) |
265 ShowWindow(); | 348 ShowWindow(); |
266 base.WndProc(ref m); | 349 base.WndProc(ref m); |
267 } | 350 } |
268 | 351 |
352 /// <summary>Handles clicks on the notification area icon.</summary> | |
269 private void NotifyIcon_MouseClick(object sender, MouseEventArgs e) | 353 private void NotifyIcon_MouseClick(object sender, MouseEventArgs e) |
270 { | 354 { |
271 if (e.Button == MouseButtons.Left) | 355 if (e.Button == MouseButtons.Left) |
272 ShowWindow(); | 356 ShowWindow(); |
273 else if (e.Button == MouseButtons.Right) | 357 else if (e.Button == MouseButtons.Right) |
274 NotificationIconMenu.Show(); | 358 NotificationIconMenu.Show(); |
275 } | 359 } |
276 | 360 |
361 /// <summary>Shows the window.</summary> | |
277 private void ShowWindow() | 362 private void ShowWindow() |
278 { | 363 { |
279 if (WindowState == FormWindowState.Minimized) | 364 if (WindowState == FormWindowState.Minimized) |
280 WindowState = FormWindowState.Normal; | 365 WindowState = FormWindowState.Normal; |
366 // Do various things to try to get this window on top. | |
367 // We only do this as a result of user input, so it's ok. ;) | |
281 Show(); | 368 Show(); |
282 TopMost = true; | 369 TopMost = true; |
283 TopMost = false; | 370 TopMost = false; |
284 Activate(); | 371 Activate(); |
285 } | 372 } |
286 | 373 |
374 /// <summary>Handles clicks on the notification icon menu.</summary> | |
287 private void NotificationIconMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) | 375 private void NotificationIconMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) |
288 { | 376 { |
289 if (e.ClickedItem == ShowServerMonitorMenuItem) | 377 if (e.ClickedItem == ShowServerMonitorMenuItem) |
290 ShowWindow(); | 378 ShowWindow(); |
291 else if (e.ClickedItem == ExitMenuItem) | 379 else if (e.ClickedItem == ExitMenuItem) |
292 Application.Exit(); | 380 Application.Exit(); |
293 } | 381 } |
294 | 382 |
383 /// <summary>Begins checking for program updates in the background.</summary> | |
295 private void CheckForUpdate() | 384 private void CheckForUpdate() |
296 { | 385 { |
297 //System.Threading.Thread.Sleep(5000); | |
298 UpdateManager manager = UpdateManager.Instance; | 386 UpdateManager manager = UpdateManager.Instance; |
387 // Make the update manager happy if the program was just restarted to apply an update. | |
299 manager.ReinstateIfRestarted(); | 388 manager.ReinstateIfRestarted(); |
300 manager.UpdateSource = new SimpleWebSource("https://www.bgreco.net/test/servermonitor.xml"); | 389 manager.UpdateSource = new SimpleWebSource("https://www.bgreco.net/test/servermonitor.xml"); |
301 if (manager.State == UpdateManager.UpdateProcessState.NotChecked) | 390 if (manager.State == UpdateManager.UpdateProcessState.NotChecked) |
302 manager.BeginCheckForUpdates(CheckForUpdatesCallback, null); | 391 manager.BeginCheckForUpdates(CheckForUpdatesCallback, null); |
303 } | 392 } |
304 | 393 |
394 /// <summary>Callback after the program update check completes.</summary> | |
305 private void CheckForUpdatesCallback(IAsyncResult result) | 395 private void CheckForUpdatesCallback(IAsyncResult result) |
306 { | 396 { |
307 UpdateManager manager = UpdateManager.Instance; | 397 UpdateManager manager = UpdateManager.Instance; |
308 if (manager.UpdatesAvailable > 0) | 398 if (manager.UpdatesAvailable > 0) |
309 { | 399 { |
400 // Extract the new version number from the result. | |
310 GetUpdateInfo(out string version, out string _); | 401 GetUpdateInfo(out string version, out string _); |
402 // If the user has not chosen to ignore this update, show a notification. | |
311 if (Settings.Default.IgnoreUpdate != version) | 403 if (Settings.Default.IgnoreUpdate != version) |
312 Invoke((MethodInvoker)(() => UpdatePanel.Show())); | 404 Invoke((MethodInvoker)(() => UpdatePanel.Show())); |
313 } | 405 } |
314 } | 406 } |
315 | 407 |
408 /// <summary>Applies the program updates.</summary> | |
316 private void PrepareUpdatesCallback(IAsyncResult result) | 409 private void PrepareUpdatesCallback(IAsyncResult result) |
317 { | 410 { |
318 UpdateManager manager = UpdateManager.Instance; | 411 UpdateManager manager = UpdateManager.Instance; |
319 manager.EndCheckForUpdates(result); | 412 manager.EndCheckForUpdates(result); |
320 manager.ApplyUpdates(true); | 413 manager.ApplyUpdates(true); |
321 } | 414 } |
322 | 415 |
416 /// <summary>Shows information about a program update when the notification is clicked.</summary> | |
323 private void UpdateLabel_Click(object sender, EventArgs e) | 417 private void UpdateLabel_Click(object sender, EventArgs e) |
324 { | 418 { |
419 // Extract the update information from the update manager result. | |
325 GetUpdateInfo(out string version, out string changeMessage); | 420 GetUpdateInfo(out string version, out string changeMessage); |
326 string message = "Server Monitor version {0} is available for download." + Environment.NewLine | 421 string message = "Server Monitor version {0} is available for download." + Environment.NewLine |
327 + Environment.NewLine | 422 + Environment.NewLine |
328 + "What's new:" + Environment.NewLine | 423 + "What's new:" + Environment.NewLine |
329 + "{1}" + Environment.NewLine | 424 + "{1}" + Environment.NewLine |
330 + Environment.NewLine | 425 + Environment.NewLine |
331 + "Would you like to download and apply the update now?"; | 426 + "Would you like to download and apply the update now?"; |
332 using (UpdateDialog dialog = new UpdateDialog { Message = string.Format(message, version, changeMessage) }) | 427 using (UpdateDialog dialog = new UpdateDialog { Message = string.Format(message, version, changeMessage) }) |
333 { | 428 { |
334 DialogResult result = dialog.ShowDialog(); | 429 DialogResult result = dialog.ShowDialog(); |
430 // If the user declined the update and asked not to be notified again, | |
431 // save the preference so they will not be asked again for this version. | |
335 if (dialog.Checked && result == DialogResult.Cancel) | 432 if (dialog.Checked && result == DialogResult.Cancel) |
336 { | 433 { |
337 Settings.Default.IgnoreUpdate = version; | 434 Settings.Default.IgnoreUpdate = version; |
338 Settings.Default.Save(); | 435 Settings.Default.Save(); |
339 UpdatePanel.Hide(); | 436 UpdatePanel.Hide(); |
340 } | 437 } |
438 // If Yes was not chosen, do not apply the update. | |
341 if (result != DialogResult.OK) | 439 if (result != DialogResult.OK) |
342 return; | 440 return; |
343 } | 441 } |
344 UpdateManager.Instance.BeginPrepareUpdates(PrepareUpdatesCallback, null); | 442 UpdateManager.Instance.BeginPrepareUpdates(PrepareUpdatesCallback, null); |
345 } | 443 } |
346 | 444 |
445 /// <summary>Extracts the update information from the update manager result.</summary> | |
347 private void GetUpdateInfo(out string version, out string changeMessage) | 446 private void GetUpdateInfo(out string version, out string changeMessage) |
348 { | 447 { |
448 // The update description is in the form {version}:{change message}. | |
349 string[] parts = UpdateManager.Instance.Tasks.First().Description.Split(new char[] { ':' }, 2); | 449 string[] parts = UpdateManager.Instance.Tasks.First().Description.Split(new char[] { ':' }, 2); |
350 version = parts[0]; | 450 version = parts[0]; |
351 changeMessage = parts[1]; | 451 changeMessage = parts[1]; |
352 } | 452 } |
353 } | 453 } |