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