19942332c7b3dae191e1c9137f1ec7f317ddac89
[reactos.git] / reactos / base / applications / mscutils / devmgmt_new / MainWindow.cpp
1 /*
2 * PROJECT: ReactOS Device Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/devmgmt/deviceview.cpp
5 * PURPOSE: Implements main window
6 * COPYRIGHT: Copyright 2014 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11 #include "MainWindow.h"
12
13
14 /* DATA *****************************************************/
15
16 /* menu hints */
17 static const MENU_HINT MainMenuHintTable[] =
18 {
19 /* File Menu */
20 {IDC_EXIT, IDS_HINT_EXIT},
21
22 /* Action Menu */
23 {IDC_REFRESH, IDS_HINT_REFRESH},
24 {IDC_PROP, IDS_HINT_PROP},
25
26 {IDC_ABOUT, IDS_HINT_ABOUT},
27
28 {IDC_DEVBYTYPE, IDS_HINT_DEV_BY_TYPE},
29 {IDC_DEVBYCONN, IDS_HINT_DEV_BY_CONN},
30 {IDC_RESBYTYPE, IDS_HINT_RES_BY_TYPE},
31 {IDC_RESBYCONN, IDS_HINT_RES_BY_TYPE}
32
33 };
34
35 /* system menu hints */
36 static const MENU_HINT SystemMenuHintTable[] =
37 {
38 {SC_RESTORE, IDS_HINT_SYS_RESTORE},
39 {SC_MOVE, IDS_HINT_SYS_MOVE},
40 {SC_SIZE, IDS_HINT_SYS_SIZE},
41 {SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
42 {SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
43 {SC_CLOSE, IDS_HINT_SYS_CLOSE},
44 };
45
46
47 /* PUBLIC METHODS **********************************************/
48
49 CMainWindow::CMainWindow(void) :
50 m_hMainWnd(NULL),
51 m_hStatusBar(NULL),
52 m_hToolBar(NULL),
53 m_ToolbarhImageList(NULL),
54 m_CmdShow(0)
55 {
56 m_szMainWndClass = L"DevMgmtWndClass";
57 }
58
59 CMainWindow::~CMainWindow(void)
60 {
61 /* Destroy any previous list */
62 if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
63 }
64
65 BOOL
66 CMainWindow::Initialize(LPCTSTR lpCaption,
67 int nCmdShow)
68 {
69 WNDCLASSEXW wc = {0};
70
71 /* Store the show window value */
72 m_CmdShow = nCmdShow;
73
74 /* Setup the window class struct */
75 wc.cbSize = sizeof(WNDCLASSEXW);
76 wc.lpfnWndProc = MainWndProc;
77 wc.hInstance = g_hInstance;
78 wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
79 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
80 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
81 wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
82 wc.lpszClassName = m_szMainWndClass;
83 wc.hIconSm = (HICON)LoadImage(g_hInstance,
84 MAKEINTRESOURCE(IDI_MAIN_ICON),
85 IMAGE_ICON,
86 16,
87 16,
88 LR_SHARED);
89
90 /* Register the window */
91 if (RegisterClassExW(&wc))
92 {
93 /* Create the main window and store the info pointer */
94 m_hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
95 m_szMainWndClass,
96 lpCaption,
97 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
98 CW_USEDEFAULT,
99 CW_USEDEFAULT,
100 600,
101 450,
102 NULL,
103 NULL,
104 g_hInstance,
105 this);
106 }
107
108 /* Return creation result */
109 return !!(m_hMainWnd);
110 }
111
112 VOID
113 CMainWindow::Uninitialize()
114 {
115 /* Unregister the window class */
116 UnregisterClassW(m_szMainWndClass, g_hInstance);
117 }
118
119 INT
120 CMainWindow::Run()
121 {
122 MSG Msg;
123
124 /* Pump the message queue */
125 while (GetMessageW(&Msg, NULL, 0, 0 ) != 0)
126 {
127 TranslateMessage(&Msg);
128 DispatchMessageW(&Msg);
129 }
130
131 return 0;
132 }
133
134
135 /* PRIVATE METHODS **********************************************/
136
137
138 BOOL
139 CMainWindow::MainWndMenuHint(WORD CmdId,
140 const MENU_HINT *HintArray,
141 DWORD HintsCount,
142 UINT DefHintId)
143 {
144 BOOL Found = FALSE;
145 const MENU_HINT *LastHint;
146 UINT HintId = DefHintId;
147
148 LastHint = HintArray + HintsCount;
149 while (HintArray != LastHint)
150 {
151 if (HintArray->CmdId == CmdId)
152 {
153 HintId = HintArray->HintId;
154 Found = TRUE;
155 break;
156 }
157 HintArray++;
158 }
159
160 StatusBarLoadString(m_hStatusBar,
161 SB_SIMPLEID,
162 g_hInstance,
163 HintId);
164
165 return Found;
166 }
167
168 BOOL
169 CMainWindow::UpdateDevicesDisplay(ListDevices List)
170 {
171 UINT CheckId;
172
173 /* Set the new type*/
174 m_DeviceView->SetDeviceListType(List);
175
176 /* Get the menu item id */
177 switch (List)
178 {
179 case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
180 case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
181 case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
182 case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
183 default: ATLASSERT(FALSE); break;
184 }
185
186 /* Set the new check item */
187 CheckMenuRadioItem(m_hMenu,
188 IDC_DEVBYTYPE,
189 IDC_RESBYCONN,
190 CheckId,
191 MF_BYCOMMAND);
192
193 /* Refresh the view */
194 m_DeviceView->Refresh();
195
196 return TRUE;
197 }
198
199 BOOL
200 CMainWindow::CreateToolBar()
201 {
202 HIMAGELIST hImageList;
203 HBITMAP hBitmap;
204 UINT StartResource, EndResource;
205 INT NumButtons;
206 BOOL bRet = FALSE;
207
208 static TBBUTTON ToolbarButtons [] =
209 {
210 {TBICON_PROP, IDC_PROP, TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0},
211 {TBICON_REFRESH, IDC_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
212
213 /* Add a seperator: First item for a seperator is its width in pixels */
214 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
215 };
216
217 /* Calculate the number of buttons */
218 NumButtons = sizeof(ToolbarButtons) / sizeof(ToolbarButtons[0]);
219
220 /* Create the toolbar window */
221 m_hToolBar = CreateWindowExW(0,
222 TOOLBARCLASSNAME,
223 NULL,
224 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
225 0, 0, 0, 0,
226 m_hMainWnd,
227 (HMENU)IDC_TOOLBAR,
228 g_hInstance,
229 NULL);
230 if (m_hToolBar == NULL) return FALSE;
231
232 /* Don't show clipped buttons */
233 SendMessageW(m_hToolBar,
234 TB_SETEXTENDEDSTYLE,
235 0,
236 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
237
238 /* Set the struct size, the toobar needs this... */
239 SendMessageW(m_hToolBar,
240 TB_BUTTONSTRUCTSIZE,
241 sizeof(ToolbarButtons[0]),
242 0);
243
244 /* Create the toolbar icon image list */
245 m_ToolbarhImageList = ImageList_Create(16,
246 16,
247 ILC_MASK | ILC_COLOR24,
248 NumButtons,
249 0);
250 if (m_ToolbarhImageList == NULL) return FALSE;
251
252 /* Set the index endpoints */
253 StartResource = IDB_PROP;
254 EndResource = IDB_REFRESH;
255
256 /* Add all icons to the image list */
257 for (UINT i = StartResource; i <= EndResource; i++)
258 {
259 /* Load the image resource */
260 hBitmap = (HBITMAP)LoadImage(g_hInstance,
261 MAKEINTRESOURCE(i),
262 IMAGE_BITMAP,
263 16,
264 16,
265 LR_LOADTRANSPARENT);
266 if (hBitmap)
267 {
268 /* Add it to the image list */
269 ImageList_AddMasked(m_ToolbarhImageList,
270 hBitmap,
271 RGB(255, 0, 128));
272
273 /* Delete the bitmap */
274 DeleteObject(hBitmap);
275 }
276 }
277
278 /* Set the new image list */
279 hImageList = (HIMAGELIST)SendMessageW(m_hToolBar,
280 TB_SETIMAGELIST,
281 0,
282 (LPARAM)m_ToolbarhImageList);
283
284 /* Destroy any previous list */
285 if (hImageList) ImageList_Destroy(hImageList);
286
287 /* Add the buttons */
288 bRet = (BOOL)SendMessageW(m_hToolBar,
289 TB_ADDBUTTONS,
290 NumButtons,
291 (LPARAM)ToolbarButtons);
292
293 return bRet;
294 }
295
296 BOOL
297 CMainWindow::CreateStatusBar()
298 {
299 INT StatWidths[] = {110, -1}; /* widths of status bar */
300 BOOL bRet = FALSE;
301
302 /* Create the status bar */
303 m_hStatusBar = CreateWindowExW(0,
304 STATUSCLASSNAME,
305 NULL,
306 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
307 0, 0, 0, 0,
308 m_hMainWnd,
309 (HMENU)IDC_STATUSBAR,
310 g_hInstance,
311 NULL);
312 if (m_hStatusBar)
313 {
314 /* Set the width */
315 bRet = (BOOL)SendMessageW(m_hStatusBar,
316 SB_SETPARTS,
317 sizeof(StatWidths) / sizeof(INT),
318 (LPARAM)StatWidths);
319 }
320
321 return bRet;
322 }
323
324 BOOL
325 CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
326 IN INT PartId,
327 IN HINSTANCE hInstance,
328 IN UINT uID)
329 {
330 WCHAR szMessage[4096];
331 BOOL bRet = FALSE;
332
333 /* Load the string */
334 if (LoadStringW(hInstance, uID, szMessage, _countof(szMessage)))
335 {
336 /* Send the message to the status bar */
337 bRet = (BOOL)SendMessageW(hStatusBar,
338 SB_SETTEXT,
339 (WPARAM)PartId,
340 (LPARAM)szMessage);
341 }
342
343 return bRet;
344 }
345
346 LRESULT
347 CMainWindow::OnCreate(HWND hwnd)
348 {
349 LRESULT RetCode;
350
351 /* Assume failure */
352 RetCode = -1;
353
354 /* Store the window handle */
355 m_hMainWnd = hwnd;
356
357 /* Get the menu handle */
358 m_hMenu = GetMenu(m_hMainWnd);
359
360 /* Create the toolbar */
361 if (CreateToolBar() && CreateStatusBar())
362 {
363 /* Create the device view object */
364 m_DeviceView = new CDeviceView(m_hMainWnd, DevicesByType);
365
366 /* Initialize it */
367 if (m_DeviceView->Initialize())
368 {
369 UpdateDevicesDisplay(DevicesByType);
370
371 /* Display the window according to the user request */
372 ShowWindow(hwnd, m_CmdShow);
373
374 /* Set as handled */
375 RetCode = 0;
376 }
377 }
378
379 return RetCode;
380 }
381
382 LRESULT
383 CMainWindow::OnSize()
384 {
385 RECT rcClient, rcTool, rcStatus;
386 INT lvHeight, iToolHeight, iStatusHeight;
387
388 /* Autosize the toolbar */
389 SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
390
391 /* Get the toolbar rect and save the height */
392 GetWindowRect(m_hToolBar, &rcTool);
393 iToolHeight = rcTool.bottom - rcTool.top;
394
395 /* Resize the status bar */
396 SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
397
398 /* Get the statusbar rect and save the height */
399 GetWindowRect(m_hStatusBar, &rcStatus);
400 iStatusHeight = rcStatus.bottom - rcStatus.top;
401
402 /* Get the full client rect */
403 GetClientRect(m_hMainWnd, &rcClient);
404
405 /* Calculate the remaining height for the treeview */
406 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
407
408 /* Resize the device view */
409 m_DeviceView->Size(0,
410 iToolHeight,
411 rcClient.right,
412 lvHeight);
413
414 return 0;
415 }
416
417 LRESULT
418 CMainWindow::OnNotify(LPARAM lParam)
419 {
420 LPNMHDR NmHdr = (LPNMHDR)lParam;
421
422 switch (NmHdr->code)
423 {
424 case TVN_DELETEITEMW:
425 {
426 LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
427
428 NmTreeView->action = NmTreeView->action;
429
430 break;
431 }
432
433 case NM_DBLCLK:
434 {
435 m_DeviceView->DisplayPropertySheet();
436 break;
437 }
438
439 case NM_RETURN:
440 {
441 m_DeviceView->DisplayPropertySheet();
442 break;
443 }
444 }
445
446 return 0;
447 }
448
449 LRESULT
450 CMainWindow::OnContext(LPARAM lParam)
451 {
452 INT xPos = GET_X_LPARAM(lParam);
453 INT yPos = GET_Y_LPARAM(lParam);
454
455 m_DeviceView->ShowContextMenu(xPos, yPos);
456 return 0;
457 }
458
459 LRESULT
460 CMainWindow::OnCommand(WPARAM wParam,
461 LPARAM lParam)
462 {
463 LRESULT RetCode = 0;
464 WORD Msg;
465
466 /* Get the message */
467 Msg = LOWORD(wParam);
468
469 switch (Msg)
470 {
471 case IDC_PROP:
472 {
473 /* Display the device property sheet */
474 m_DeviceView->DisplayPropertySheet();
475 break;
476 }
477
478 case IDC_REFRESH:
479 {
480 /* Refresh the device list */
481 m_DeviceView->Refresh();
482 break;
483 }
484
485 case IDC_DEVBYTYPE:
486 {
487 UpdateDevicesDisplay(DevicesByType);
488 break;
489 }
490
491 case IDC_DEVBYCONN:
492 {
493 UpdateDevicesDisplay(DevicesByConnection);
494 break;
495 }
496
497 case IDC_SHOWHIDDEN:
498 {
499 UINT CurCheckState, NewCheckState;
500
501 /* Get the current state */
502 CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
503
504 /* Inform the device view of the change */
505 if (CurCheckState == MF_CHECKED)
506 {
507 NewCheckState = MF_UNCHECKED;
508 m_DeviceView->ShowHiddenDevices(FALSE);
509 }
510 else if (CurCheckState == MF_UNCHECKED)
511 {
512 NewCheckState = MF_CHECKED;
513 m_DeviceView->ShowHiddenDevices(TRUE);
514 }
515 else
516 {
517 ATLASSERT(FALSE);
518 break;
519 }
520
521 /* Set the new check state */
522 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | NewCheckState);
523
524 /* Refresh the device view */
525 m_DeviceView->Refresh();
526 break;
527 }
528
529 case IDC_ABOUT:
530 {
531 /* Apportion blame */
532 MessageBoxW(m_hMainWnd,
533 L"ReactOS Device Manager\r\nCopyright Ged Murphy 2014",
534 L"About",
535 MB_OK | MB_APPLMODAL);
536
537 /* Set focus back to the treeview */
538 m_DeviceView->SetFocus();
539 break;
540 }
541
542 case IDC_EXIT:
543 {
544 /* Post a close message to the window */
545 PostMessageW(m_hMainWnd,
546 WM_CLOSE,
547 0,
548 0);
549 break;
550 }
551
552 default:
553 break;
554 }
555
556 return RetCode;
557 }
558
559 LRESULT
560 CMainWindow::OnDestroy()
561 {
562 /* Uninitialize the device view */
563 m_DeviceView->Uninitialize();
564
565 /* Kill the object */
566 delete m_DeviceView;
567 m_DeviceView = NULL;
568
569 /* Clear the user data pointer */
570 SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
571
572 /* Break the message loop */
573 PostQuitMessage(0);
574
575 return 0;
576 }
577
578 LRESULT CALLBACK
579 CMainWindow::MainWndProc(HWND hwnd,
580 UINT msg,
581 WPARAM wParam,
582 LPARAM lParam)
583 {
584 CMainWindow *pThis;
585 LRESULT RetCode = 0;
586
587 /* Get the object pointer from window context */
588 pThis = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
589
590 /* Check for an invalid pointer */
591 if (pThis == NULL)
592 {
593 /* Check that this isn't a create message */
594 if (msg != WM_CREATE)
595 {
596 /* Don't handle null info pointer */
597 goto HandleDefaultMessage;
598 }
599 }
600
601 switch(msg)
602 {
603 case WM_CREATE:
604 {
605 /* Get the object pointer from the create param */
606 pThis = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
607
608 /* Store the info pointer in the window's global user data */
609 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
610
611 /* Call the create handler */
612 RetCode = pThis->OnCreate(hwnd);
613 break;
614 }
615
616 case WM_SIZE:
617 {
618 RetCode = pThis->OnSize();
619 break;
620 }
621
622 case WM_NOTIFY:
623 {
624 /* Handle the notify message */
625 RetCode = pThis->OnNotify(lParam);
626 break;
627 }
628
629 case WM_CONTEXTMENU:
630 {
631 /* Handle creating the context menu */
632 RetCode = pThis->OnContext(lParam);
633 break;
634 }
635
636 case WM_MENUSELECT:
637 {
638 if (pThis->m_hStatusBar != NULL)
639 {
640 if (!pThis->MainWndMenuHint(LOWORD(wParam),
641 MainMenuHintTable,
642 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
643 IDS_HINT_BLANK))
644 {
645 pThis->MainWndMenuHint(LOWORD(wParam),
646 SystemMenuHintTable,
647 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
648 IDS_HINT_BLANK);
649 }
650 }
651
652 break;
653 }
654
655 case WM_COMMAND:
656 {
657 /* Handle the command message */
658 RetCode = pThis->OnCommand(wParam, lParam);
659
660 /* Hand it off to the default message handler */
661 goto HandleDefaultMessage;
662 }
663
664 case WM_CLOSE:
665 {
666 /* Destroy the main window */
667 DestroyWindow(hwnd);
668 }
669 break;
670
671 case WM_DESTROY:
672 {
673 /* Call the destroy handler */
674 RetCode = pThis->OnDestroy();
675 break;
676 }
677
678 default:
679 {
680 HandleDefaultMessage:
681 RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
682 break;
683 }
684 }
685
686 return RetCode;
687 }