[SHELL32] Remove 2 redundant initializations
[reactos.git] / base / applications / rapps / gui.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: GUI classes for RAPPS
5 * COPYRIGHT: Copyright 2015 David Quintana (gigaherz@gmail.com)
6 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
7 * Copyright 2020 He Yang (1160386205@qq.com)
8 */
9
10 #include "rapps.h"
11 #include "rosui.h"
12 #include "crichedit.h"
13 #include "appview.h"
14 #include "asyncinet.h"
15 #include "misc.h"
16 #include "gui.h"
17 #include "appview.h"
18 #include "winmain.h"
19 #include <shlobj_undoc.h>
20 #include <shlguid_undoc.h>
21
22 #include <atlbase.h>
23 #include <atlcom.h>
24 #include <atltypes.h>
25 #include <atlwin.h>
26 #include <wininet.h>
27 #include <shellutils.h>
28 #include <rosctrls.h>
29 #include <gdiplus.h>
30 #include <math.h>
31
32 #define SEARCH_TIMER_ID 'SR'
33 #define TREEVIEW_ICON_SIZE 24
34
35
36
37 // **** CSideTreeView ****
38
39 CSideTreeView::CSideTreeView() :
40 CUiWindow(),
41 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
42 GetSystemColorDepth() | ILC_MASK,
43 0, 1))
44 {
45 }
46
47 HTREEITEM CSideTreeView::AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
48 {
49 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
50 }
51
52 HTREEITEM CSideTreeView::AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
53 {
54 ATL::CStringW szText;
55 INT Index = 0;
56 HICON hIcon;
57
58 hIcon = (HICON)LoadImageW(hInst,
59 MAKEINTRESOURCE(IconIndex),
60 IMAGE_ICON,
61 TREEVIEW_ICON_SIZE,
62 TREEVIEW_ICON_SIZE,
63 LR_CREATEDIBSECTION);
64 if (hIcon)
65 {
66 Index = ImageList_AddIcon(hImageTreeView, hIcon);
67 DestroyIcon(hIcon);
68 }
69
70 szText.LoadStringW(TextIndex);
71 return AddItem(hRootItem, szText, Index, Index, TextIndex);
72 }
73
74 HIMAGELIST CSideTreeView::SetImageList()
75 {
76 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
77 }
78
79 VOID CSideTreeView::DestroyImageList()
80 {
81 if (hImageTreeView)
82 ImageList_Destroy(hImageTreeView);
83 }
84
85 CSideTreeView::~CSideTreeView()
86 {
87 DestroyImageList();
88 }
89 // **** CSideTreeView ****
90
91
92
93 // **** CMainWindow ****
94
95 CMainWindow::CMainWindow() :
96 m_ClientPanel(NULL),
97 SelectedEnumType(ENUM_ALL_INSTALLED)
98 {
99 }
100
101 CMainWindow::~CMainWindow()
102 {
103 LayoutCleanup();
104 }
105
106 VOID CMainWindow::InitCategoriesList()
107 {
108 HTREEITEM hRootItemInstalled, hRootItemAvailable;
109
110 hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
111 m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
112 m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
113
114 m_TreeView->AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST);
115
116 hRootItemAvailable = m_TreeView->AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
117 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
118 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
119 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
120 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_GAMES, IDI_CAT_GAMES);
121 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
122 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
123 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
124 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_EDU, IDI_CAT_EDU);
125 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
126 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
127 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
128 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
129 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
130 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_LIBS, IDI_CAT_LIBS);
131 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_THEMES, IDI_CAT_THEMES);
132 m_TreeView->AddCategory(hRootItemAvailable, IDS_CAT_OTHER, IDI_CAT_OTHER);
133
134 m_TreeView->SetImageList();
135 m_TreeView->Expand(hRootItemInstalled, TVE_EXPAND);
136 m_TreeView->Expand(hRootItemAvailable, TVE_EXPAND);
137 m_TreeView->SelectItem(hRootItemAvailable);
138 }
139
140 BOOL CMainWindow::CreateStatusBar()
141 {
142 m_StatusBar = new CUiWindow<CStatusBar>();
143 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
144 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
145 m_ClientPanel->Children().Append(m_StatusBar);
146
147 return m_StatusBar->Create(m_hWnd, (HMENU)IDC_STATUSBAR) != NULL;
148 }
149
150 BOOL CMainWindow::CreateTreeView()
151 {
152 m_TreeView = new CSideTreeView();
153 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
154 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
155 m_VSplitter->First().Append(m_TreeView);
156
157 return m_TreeView->Create(m_hWnd) != NULL;
158 }
159
160 BOOL CMainWindow::CreateApplicationView()
161 {
162 m_ApplicationView = new CApplicationView(this); // pass this to ApplicationView for callback purpose
163 m_ApplicationView->m_VerticalAlignment = UiAlign_Stretch;
164 m_ApplicationView->m_HorizontalAlignment = UiAlign_Stretch;
165 m_VSplitter->Second().Append(m_ApplicationView);
166
167 return m_ApplicationView->Create(m_hWnd) != NULL;
168 }
169
170 BOOL CMainWindow::CreateVSplitter()
171 {
172 m_VSplitter = new CUiSplitPanel();
173 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
174 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
175 m_VSplitter->m_DynamicFirst = FALSE;
176 m_VSplitter->m_Horizontal = FALSE;
177 m_VSplitter->m_MinFirst = 0;
178
179 // TODO: m_MinSecond should be calculate dynamically instead of hard-coded
180 m_VSplitter->m_MinSecond = 480;
181 m_VSplitter->m_Pos = 240;
182 m_ClientPanel->Children().Append(m_VSplitter);
183
184 return m_VSplitter->Create(m_hWnd) != NULL;
185 }
186
187 BOOL CMainWindow::CreateLayout()
188 {
189 BOOL b = TRUE;
190 bUpdating = TRUE;
191
192 m_ClientPanel = new CUiPanel();
193 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
194 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
195
196 // Top level
197 b = b && CreateStatusBar();
198 b = b && CreateVSplitter();
199
200 // Inside V Splitter
201 b = b && CreateTreeView();
202 b = b && CreateApplicationView();
203
204 if (b)
205 {
206 RECT rBottom;
207
208 /* Size status bar */
209 m_StatusBar->SendMessageW(WM_SIZE, 0, 0);
210
211 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
212
213 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
214 }
215
216 bUpdating = FALSE;
217 return b;
218 }
219
220 VOID CMainWindow::LayoutCleanup()
221 {
222 delete m_TreeView;
223 delete m_ApplicationView;
224 delete m_VSplitter;
225 delete m_StatusBar;
226 return;
227 }
228
229 BOOL CMainWindow::InitControls()
230 {
231 if (CreateLayout())
232 {
233 InitCategoriesList();
234
235 UpdateStatusBarText();
236
237 return TRUE;
238 }
239
240 return FALSE;
241 }
242
243 VOID CMainWindow::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
244 {
245 if (wParam == SIZE_MINIMIZED)
246 return;
247
248 /* Size status bar */
249 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
250
251
252 RECT r = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
253 HDWP hdwp = NULL;
254 INT count = m_ClientPanel->CountSizableChildren();
255
256 hdwp = BeginDeferWindowPos(count);
257 if (hdwp)
258 {
259 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
260 if (hdwp)
261 {
262 EndDeferWindowPos(hdwp);
263 }
264 }
265 }
266
267 BOOL CMainWindow::RemoveSelectedAppFromRegistry()
268 {
269 if (!IsInstalledEnum(SelectedEnumType))
270 return FALSE;
271
272 ATL::CStringW szMsgText, szMsgTitle;
273
274 if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) ||
275 !szMsgTitle.LoadStringW(IDS_INFORMATION))
276 return FALSE;
277
278 if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == IDYES)
279 {
280 CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo *)m_ApplicationView->GetFocusedItemData();
281 if (!InstalledApp)
282 return FALSE;
283
284 LSTATUS Result = InstalledApp->RemoveFromRegistry();
285 if (Result != ERROR_SUCCESS)
286 {
287 // TODO: popup a messagebox telling user it fails somehow
288 return FALSE;
289 }
290
291 // as it's already removed form registry, this will also remove it from the list
292 UpdateApplicationsList(-1);
293 return TRUE;
294 }
295
296 return FALSE;
297 }
298
299 BOOL CMainWindow::UninstallSelectedApp(BOOL bModify)
300 {
301 if (!IsInstalledEnum(SelectedEnumType))
302 return FALSE;
303
304 CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo *)m_ApplicationView->GetFocusedItemData();
305 if (!InstalledApp)
306 return FALSE;
307
308 return InstalledApp->UninstallApplication(bModify);
309 }
310
311 BOOL CMainWindow::ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId)
312 {
313 theResult = 0;
314 switch (Msg)
315 {
316 case WM_CREATE:
317 if (!InitControls())
318 ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
319 break;
320
321 case WM_DESTROY:
322 {
323 ShowWindow(SW_HIDE);
324 SaveSettings(hwnd, &SettingsInfo);
325
326 FreeLogs();
327 m_AvailableApps.FreeCachedEntries();
328 m_InstalledApps.FreeCachedEntries();
329
330 delete m_ClientPanel;
331
332 PostQuitMessage(0);
333 return 0;
334 }
335
336 case WM_COMMAND:
337 OnCommand(wParam, lParam);
338 break;
339
340 case WM_NOTIFY:
341 {
342 LPNMHDR data = (LPNMHDR)lParam;
343
344 switch (data->code)
345 {
346 case TVN_SELCHANGED:
347 {
348 if (data->hwndFrom == m_TreeView->m_hWnd)
349 {
350 switch (((LPNMTREEVIEW)lParam)->itemNew.lParam)
351 {
352 case IDS_INSTALLED:
353 UpdateApplicationsList(ENUM_ALL_INSTALLED);
354 break;
355
356 case IDS_APPLICATIONS:
357 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS);
358 break;
359
360 case IDS_UPDATES:
361 UpdateApplicationsList(ENUM_UPDATES);
362 break;
363
364 case IDS_AVAILABLEFORINST:
365 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
366 break;
367
368 case IDS_CAT_AUDIO:
369 UpdateApplicationsList(ENUM_CAT_AUDIO);
370 break;
371
372 case IDS_CAT_DEVEL:
373 UpdateApplicationsList(ENUM_CAT_DEVEL);
374 break;
375
376 case IDS_CAT_DRIVERS:
377 UpdateApplicationsList(ENUM_CAT_DRIVERS);
378 break;
379
380 case IDS_CAT_EDU:
381 UpdateApplicationsList(ENUM_CAT_EDU);
382 break;
383
384 case IDS_CAT_ENGINEER:
385 UpdateApplicationsList(ENUM_CAT_ENGINEER);
386 break;
387
388 case IDS_CAT_FINANCE:
389 UpdateApplicationsList(ENUM_CAT_FINANCE);
390 break;
391
392 case IDS_CAT_GAMES:
393 UpdateApplicationsList(ENUM_CAT_GAMES);
394 break;
395
396 case IDS_CAT_GRAPHICS:
397 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
398 break;
399
400 case IDS_CAT_INTERNET:
401 UpdateApplicationsList(ENUM_CAT_INTERNET);
402 break;
403
404 case IDS_CAT_LIBS:
405 UpdateApplicationsList(ENUM_CAT_LIBS);
406 break;
407
408 case IDS_CAT_OFFICE:
409 UpdateApplicationsList(ENUM_CAT_OFFICE);
410 break;
411
412 case IDS_CAT_OTHER:
413 UpdateApplicationsList(ENUM_CAT_OTHER);
414 break;
415
416 case IDS_CAT_SCIENCE:
417 UpdateApplicationsList(ENUM_CAT_SCIENCE);
418 break;
419
420 case IDS_CAT_TOOLS:
421 UpdateApplicationsList(ENUM_CAT_TOOLS);
422 break;
423
424 case IDS_CAT_VIDEO:
425 UpdateApplicationsList(ENUM_CAT_VIDEO);
426 break;
427
428 case IDS_CAT_THEMES:
429 UpdateApplicationsList(ENUM_CAT_THEMES);
430 break;
431
432 case IDS_SELECTEDFORINST:
433 UpdateApplicationsList(ENUM_CAT_SELECTED);
434 break;
435 }
436 }
437
438 HMENU mainMenu = ::GetMenu(hwnd);
439
440 /* Disable/enable items based on treeview selection */
441 if (IsSelectedNodeInstalled())
442 {
443 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
444 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
445 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
446 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
447 }
448 else
449 {
450 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
451 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
452 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
453 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
454 }
455 }
456 break;
457
458 }
459 }
460 break;
461
462 case WM_SIZE:
463 OnSize(hwnd, wParam, lParam);
464 break;
465
466 case WM_SIZING:
467 {
468 LPRECT pRect = (LPRECT)lParam;
469
470 if (pRect->right - pRect->left < 565)
471 pRect->right = pRect->left + 565;
472
473 if (pRect->bottom - pRect->top < 300)
474 pRect->bottom = pRect->top + 300;
475
476 return TRUE;
477 }
478
479 case WM_SYSCOLORCHANGE:
480 {
481 /* Forward WM_SYSCOLORCHANGE to common controls */
482 m_ApplicationView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
483 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
484 }
485 break;
486
487 case WM_TIMER:
488 if (wParam == SEARCH_TIMER_ID)
489 {
490 ::KillTimer(hwnd, SEARCH_TIMER_ID);
491
492 UpdateApplicationsList(-1);
493 }
494 break;
495 }
496
497 return FALSE;
498 }
499
500 BOOL CMainWindow::IsSelectedNodeInstalled()
501 {
502 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
503 TV_ITEM tItem;
504
505 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
506 tItem.hItem = hSelectedItem;
507 m_TreeView->GetItem(&tItem);
508 switch (tItem.lParam)
509 {
510 case IDS_INSTALLED:
511 case IDS_APPLICATIONS:
512 case IDS_UPDATES:
513 return TRUE;
514 default:
515 return FALSE;
516 }
517 }
518
519 VOID CMainWindow::ShowAboutDlg()
520 {
521 ATL::CStringW szApp;
522 ATL::CStringW szAuthors;
523 HICON hIcon;
524
525 szApp.LoadStringW(IDS_APPTITLE);
526 szAuthors.LoadStringW(IDS_APP_AUTHORS);
527 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
528 ShellAboutW(m_hWnd, szApp, szAuthors, hIcon);
529 DestroyIcon(hIcon);
530 }
531
532 VOID CMainWindow::OnCommand(WPARAM wParam, LPARAM lParam)
533 {
534 WORD wCommand = LOWORD(wParam);
535
536 if (!lParam)
537 {
538 switch (wCommand)
539 {
540 case ID_SETTINGS:
541 CreateSettingsDlg(m_hWnd);
542 break;
543
544 case ID_EXIT:
545 PostMessageW(WM_CLOSE, 0, 0);
546 break;
547
548 case ID_INSTALL:
549 if (IsAvailableEnum(SelectedEnumType))
550 {
551 ATL::CSimpleArray<CAvailableApplicationInfo> AppsList;
552
553 // enum all selected apps
554 m_AvailableApps.Enum(ENUM_CAT_SELECTED, s_EnumSelectedAppForDownloadProc, (PVOID)&AppsList);
555
556 if (AppsList.GetSize())
557 {
558 if (DownloadListOfApplications(AppsList, FALSE))
559 {
560 m_AvailableApps.RemoveAllSelected();
561 UpdateApplicationsList(-1);
562 }
563 }
564 else
565 {
566 // use the currently focused item in application-view
567 CAvailableApplicationInfo *FocusedApps = (CAvailableApplicationInfo *)m_ApplicationView->GetFocusedItemData();
568 if (FocusedApps)
569 {
570 if (DownloadApplication(FocusedApps, FALSE))
571 {
572 UpdateApplicationsList(-1);
573 }
574 }
575 else
576 {
577 // TODO: in this case, Install button in toolbar (and all other places) should be disabled
578 // or at least popup a messagebox telling user to select/check some app first
579 }
580 }
581 }
582 break;
583
584 case ID_UNINSTALL:
585 if (UninstallSelectedApp(FALSE))
586 UpdateApplicationsList(-1);
587 break;
588
589 case ID_MODIFY:
590 if (UninstallSelectedApp(TRUE))
591 UpdateApplicationsList(-1);
592 break;
593
594 case ID_REGREMOVE:
595 RemoveSelectedAppFromRegistry();
596 break;
597
598 case ID_REFRESH:
599 UpdateApplicationsList(-1);
600 break;
601
602 case ID_RESETDB:
603 CAvailableApps::ForceUpdateAppsDB();
604 UpdateApplicationsList(-1);
605 break;
606
607 case ID_HELP:
608 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
609 break;
610
611 case ID_ABOUT:
612 ShowAboutDlg();
613 break;
614
615 case ID_CHECK_ALL:
616 m_ApplicationView->CheckAll();
617 break;
618 }
619 }
620 }
621
622 BOOL CALLBACK CMainWindow::EnumInstalledAppProc(CInstalledApplicationInfo *Info)
623 {
624 if (!SearchPatternMatch(Info->szDisplayName.GetString(), szSearchPattern))
625 {
626 return TRUE;
627 }
628 return m_ApplicationView->AddInstalledApplication(Info, Info); // currently, the callback param is Info itself
629 }
630
631 BOOL CALLBACK CMainWindow::EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState)
632 {
633 if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) &&
634 !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
635 {
636 return TRUE;
637 }
638 return m_ApplicationView->AddAvailableApplication(Info, bInitialCheckState, Info); // currently, the callback param is Info itself
639 }
640
641 BOOL CALLBACK CMainWindow::s_EnumInstalledAppProc(CInstalledApplicationInfo *Info, PVOID param)
642 {
643 CMainWindow *pThis = (CMainWindow *)param;
644 return pThis->EnumInstalledAppProc(Info);
645 }
646
647 BOOL CALLBACK CMainWindow::s_EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param)
648 {
649 CMainWindow *pThis = (CMainWindow *)param;
650 return pThis->EnumAvailableAppProc(Info, bInitialCheckState);
651 }
652
653 BOOL CALLBACK CMainWindow::s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param)
654 {
655 ATL::CSimpleArray<CAvailableApplicationInfo> *pAppList = (ATL::CSimpleArray<CAvailableApplicationInfo> *)param;
656 pAppList->Add(*Info);
657 return TRUE;
658 }
659
660 VOID CMainWindow::UpdateStatusBarText()
661 {
662 if (m_StatusBar)
663 {
664 ATL::CStringW szBuffer;
665
666 szBuffer.Format(IDS_APPS_COUNT, m_ApplicationView->GetItemCount(), m_AvailableApps.GetSelectedCount());
667 m_StatusBar->SetText(szBuffer);
668 }
669 }
670
671 VOID CMainWindow::UpdateApplicationsList(INT EnumType)
672 {
673 bUpdating = TRUE;
674
675 if (EnumType == -1)
676 {
677 // keep the old enum type
678 EnumType = SelectedEnumType;
679 }
680 else
681 {
682 SelectedEnumType = EnumType;
683 }
684
685 m_ApplicationView->SetRedraw(FALSE);
686 if (IsInstalledEnum(EnumType))
687 {
688 // set the display type of application-view. this will remove all the item in application-view too.
689 m_ApplicationView->SetDisplayAppType(AppViewTypeInstalledApps);
690
691 // enum installed softwares
692 m_InstalledApps.Enum(EnumType, s_EnumInstalledAppProc, this);
693 }
694 else if (IsAvailableEnum(EnumType))
695 {
696 // set the display type of application-view. this will remove all the item in application-view too.
697 m_ApplicationView->SetDisplayAppType(AppViewTypeAvailableApps);
698
699 // enum available softwares
700 m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
701 }
702 m_ApplicationView->SetRedraw(TRUE);
703 m_ApplicationView->RedrawWindow(0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN); // force the child window to repaint
704 UpdateStatusBarText();
705 bUpdating = FALSE;
706 }
707
708 ATL::CWndClassInfo &CMainWindow::GetWndClassInfo()
709 {
710 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
711 static ATL::CWndClassInfo wc =
712 {
713 {
714 sizeof(WNDCLASSEX),
715 csStyle,
716 StartWindowProc,
717 0,
718 0,
719 NULL,
720 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
721 LoadCursorW(NULL, IDC_ARROW),
722 (HBRUSH)(COLOR_BTNFACE + 1),
723 MAKEINTRESOURCEW(IDR_MAINMENU),
724 szWindowClass,
725 NULL
726 },
727 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
728 };
729 return wc;
730 }
731
732 HWND CMainWindow::Create()
733 {
734 ATL::CStringW szWindowName;
735 szWindowName.LoadStringW(IDS_APPTITLE);
736
737 RECT r = {
738 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
739 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
740 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
741 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
742 };
743 r.right += r.left;
744 r.bottom += r.top;
745
746 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
747 }
748
749 // this function is called when a item of application-view is checked/unchecked
750 // CallbackParam is the param passed to application-view when adding the item (the one getting focus now).
751 BOOL CMainWindow::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
752 {
753 if (!bUpdating)
754 {
755 if (bChecked)
756 {
757 if (!m_AvailableApps.AddSelected((CAvailableApplicationInfo *)CallbackParam))
758 {
759 return FALSE;
760 }
761 }
762 else
763 {
764 if (!m_AvailableApps.RemoveSelected((CAvailableApplicationInfo *)CallbackParam))
765 {
766 return FALSE;
767 }
768 }
769
770 UpdateStatusBarText();
771 return TRUE;
772 }
773 else
774 {
775 return TRUE;
776 }
777 }
778
779 // this function is called when one or more application(s) should be installed install
780 // if Info is not zero, this app should be installed. otherwise those checked apps should be installed
781 BOOL CMainWindow::InstallApplication(CAvailableApplicationInfo *Info)
782 {
783 if (Info)
784 {
785 if (DownloadApplication(Info, FALSE))
786 {
787 UpdateApplicationsList(-1);
788 return TRUE;
789 }
790 }
791 else
792 {
793 ATL::CSimpleArray<CAvailableApplicationInfo> AppsList;
794
795 // enum all selected apps
796 m_AvailableApps.Enum(ENUM_CAT_SELECTED, s_EnumSelectedAppForDownloadProc, (PVOID)&AppsList);
797
798 if (AppsList.GetSize())
799 {
800 if (DownloadListOfApplications(AppsList, FALSE))
801 {
802 m_AvailableApps.RemoveAllSelected();
803 UpdateApplicationsList(-1);
804 return TRUE;
805 }
806 }
807 }
808
809 return FALSE;
810 }
811
812 BOOL CMainWindow::SearchTextChanged(ATL::CStringW &SearchText)
813 {
814 if (szSearchPattern == SearchText)
815 {
816 return FALSE;
817 }
818
819 szSearchPattern = SearchText;
820
821 DWORD dwDelay;
822 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
823 SetTimer(SEARCH_TIMER_ID, dwDelay);
824
825 return TRUE;
826 }
827
828 void CMainWindow::HandleTabOrder(int direction)
829 {
830 ATL::CSimpleArray<HWND> TabOrderHwndList;
831
832 m_TreeView->AppendTabOrderWindow(direction, TabOrderHwndList);
833 m_ApplicationView->AppendTabOrderWindow(direction, TabOrderHwndList);
834
835
836 if (TabOrderHwndList.GetSize() == 0)
837 {
838 // in case the list is empty
839 return;
840 }
841
842 int FocusIndex;
843
844 if ((FocusIndex = TabOrderHwndList.Find(GetFocus())) == -1)
845 {
846 FocusIndex = 0; // focus the first window in the list
847 }
848 else
849 {
850 FocusIndex += direction;
851 FocusIndex += TabOrderHwndList.GetSize(); // FocusIndex might be negative. we don't want to mod a negative number
852 FocusIndex %= TabOrderHwndList.GetSize();
853 }
854
855 ::SetFocus(TabOrderHwndList[FocusIndex]);
856 return;
857 }
858 // **** CMainWindow ****
859
860
861
862 VOID MainWindowLoop(INT nShowCmd)
863 {
864 HACCEL KeyBrd;
865 MSG Msg;
866
867 CMainWindow* wnd = new CMainWindow();
868 if (!wnd)
869 return;
870
871 hMainWnd = wnd->Create();
872 if (!hMainWnd)
873 return;
874
875 /* Maximize it if we must */
876 wnd->ShowWindow((SettingsInfo.bSaveWndPos && SettingsInfo.Maximized) ? SW_MAXIMIZE : nShowCmd);
877 wnd->UpdateWindow();
878
879 /* Load the menu hotkeys */
880 KeyBrd = LoadAcceleratorsW(NULL, MAKEINTRESOURCEW(HOTKEYS));
881
882 /* Message Loop */
883 while (GetMessageW(&Msg, NULL, 0, 0))
884 {
885 if (!TranslateAcceleratorW(hMainWnd, KeyBrd, &Msg))
886 {
887 if (Msg.message == WM_CHAR &&
888 Msg.wParam == VK_TAB)
889 {
890 // Move backwards if shift is held down
891 int direction = (GetKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
892
893 wnd->HandleTabOrder(direction);
894 continue;
895 }
896
897 TranslateMessage(&Msg);
898 DispatchMessageW(&Msg);
899 }
900 }
901
902 delete wnd;
903 }