[RAPPS] Making checkboxes useful WIP
[reactos.git] / reactos / base / applications / rapps / gui.cpp
1 /* PROJECT: ReactOS CE Applications Manager
2 * LICENSE: GPL - See COPYING in the top level directory
3 * AUTHORS: David Quintana <gigaherz@gmail.com>
4 * Alexander Shaposhnikov <chaez.san@gmail.com>
5 */
6
7 #include "rapps.h"
8
9 #include <shlobj_undoc.h>
10 #include <shlguid_undoc.h>
11
12 #include <atlbase.h>
13 #include <atlcom.h>
14 #include <atlwin.h>
15 #include <wininet.h>
16 #include <shellutils.h>
17
18 #include <rosctrls.h>
19
20 #include "rosui.h"
21 #include "crichedit.h"
22
23 #define SEARCH_TIMER_ID 'SR'
24
25 HWND hListView = NULL;
26
27 class CAvailableAppView
28 {
29 static inline VOID InsertTextAfterLoaded_RichEdit(UINT uStringID,
30 const ATL::CStringW& szText,
31 DWORD StringFlags,
32 DWORD TextFlags)
33 {
34 ATL::CStringW szLoadedText;
35 if (!szText.IsEmpty() && szLoadedText.LoadStringW(hInst, uStringID))
36 {
37 InsertRichEditText(szLoadedText, StringFlags);
38 InsertRichEditText(szText, TextFlags);
39 }
40 }
41
42 static inline VOID InsertLoadedTextNewl_RichEdit(UINT uStringID,
43 DWORD StringFlags)
44 {
45 ATL::CStringW szLoadedText;
46 if (szLoadedText.LoadStringW(hInst, uStringID))
47 {
48 InsertRichEditText(L"\n", 0);
49 InsertRichEditText(szLoadedText, StringFlags);
50 InsertRichEditText(L"\n", 0);
51 }
52 }
53
54 static VOID InsertVersionInfo_RichEdit(CAvailableApplicationInfo* Info)
55 {
56 if (Info->IsInstalled())
57 {
58 if (Info->HasInstalledVersion())
59 {
60 if (Info->HasUpdate())
61 InsertLoadedTextNewl_RichEdit(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC);
62 else
63 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED, CFE_ITALIC);
64
65 InsertTextAfterLoaded_RichEdit(IDS_AINFO_VERSION, Info->szInstalledVersion, CFE_BOLD, 0);
66 }
67 else
68 {
69 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED, CFE_ITALIC);
70 }
71 }
72 else
73 {
74 InsertLoadedTextNewl_RichEdit(IDS_STATUS_NOTINSTALLED, CFE_ITALIC);
75 }
76
77 InsertTextAfterLoaded_RichEdit(IDS_AINFO_AVAILABLEVERSION, Info->szVersion, CFE_BOLD, 0);
78 }
79
80 static VOID InsertLicenseInfo_RichEdit(CAvailableApplicationInfo* Info)
81 {
82 ATL::CStringW szLicense;
83 switch (Info->LicenseType)
84 {
85 case LICENSE_TYPE::OpenSource:
86 szLicense.LoadStringW(hInst, IDS_LICENSE_OPENSOURCE);
87 break;
88 case LICENSE_TYPE::Freeware:
89 szLicense.LoadStringW(hInst, IDS_LICENSE_FREEWARE);
90 break;
91 case LICENSE_TYPE::Trial:
92 szLicense.LoadStringW(hInst, IDS_LICENSE_TRIAL);
93 break;
94 default:
95 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE, Info->szLicense, CFE_BOLD, 0);
96 return;
97 }
98
99 szLicense += L" (" + Info->szLicense + L")";
100 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE, szLicense, CFE_BOLD, 0);
101 }
102
103 static VOID InsertLanguageInfo_RichEdit(CAvailableApplicationInfo* Info)
104 {
105 if (!Info->HasLanguageInfo())
106 {
107 return;
108 }
109
110 const INT nTranslations = Info->Languages.GetSize();
111 ATL::CStringW szLangInfo;
112 ATL::CStringW szLoadedTextAvailability;
113 ATL::CStringW szLoadedAInfoText;
114
115 szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES);
116
117 //TODO: replace those hardcoded strings
118 if (Info->HasNativeLanguage())
119 {
120 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION);
121 if (nTranslations > 1)
122 {
123 szLangInfo.Format(L" (+%d more)", nTranslations - 1);
124 }
125 else
126 {
127 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
128 szLangInfo = L" (" + szLangInfo + L")";
129 }
130 }
131 else if (Info->HasEnglishLanguage())
132 {
133 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION);
134 if (nTranslations > 1)
135 {
136 szLangInfo.Format(L" (+%d available)", nTranslations - 1);
137 }
138 else
139 {
140 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
141 szLangInfo = L" (" + szLangInfo + L")";
142 }
143 }
144 else
145 {
146 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION);
147 }
148
149 InsertRichEditText(szLoadedAInfoText, CFE_BOLD);
150 InsertRichEditText(szLoadedTextAvailability, NULL);
151 InsertRichEditText(szLangInfo, CFE_ITALIC);
152 }
153
154 public:
155 static BOOL ShowAvailableAppInfo(INT Index)
156 {
157 CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*) ListViewGetlParam(Index);
158 if (!Info) return FALSE;
159
160 NewRichEditText(Info->szName, CFE_BOLD);
161 InsertVersionInfo_RichEdit(Info);
162 InsertLicenseInfo_RichEdit(Info);
163 InsertLanguageInfo_RichEdit(Info);
164
165 InsertTextAfterLoaded_RichEdit(IDS_AINFO_SIZE, Info->szSize, CFE_BOLD, 0);
166 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLSITE, Info->szUrlSite, CFE_BOLD, CFE_LINK);
167 InsertTextAfterLoaded_RichEdit(IDS_AINFO_DESCRIPTION, Info->szDesc, CFE_BOLD, 0);
168 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLDOWNLOAD, Info->szUrlDownload, CFE_BOLD, CFE_LINK);
169
170 return TRUE;
171 }
172 };
173
174 class CMainToolbar :
175 public CUiWindow< CToolbar<> >
176 {
177 #define TOOLBAR_HEIGHT 24
178
179 WCHAR szInstallBtn[MAX_STR_LEN];
180 WCHAR szUninstallBtn[MAX_STR_LEN];
181 WCHAR szModifyBtn[MAX_STR_LEN];
182 WCHAR szSelectAll[MAX_STR_LEN];
183
184 VOID AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex)
185 {
186 HICON hImage;
187
188 if (!(hImage = (HICON) LoadImageW(hInst,
189 MAKEINTRESOURCE(ImageIndex),
190 IMAGE_ICON,
191 TOOLBAR_HEIGHT,
192 TOOLBAR_HEIGHT,
193 0)))
194 {
195 /* TODO: Error message */
196 }
197
198 ImageList_AddIcon(hImageList, hImage);
199 DeleteObject(hImage);
200 }
201
202 HIMAGELIST InitImageList()
203 {
204 HIMAGELIST hImageList;
205
206 /* Create the toolbar icon image list */
207 hImageList = ImageList_Create(TOOLBAR_HEIGHT,//GetSystemMetrics(SM_CXSMICON),
208 TOOLBAR_HEIGHT,//GetSystemMetrics(SM_CYSMICON),
209 ILC_MASK | GetSystemColorDepth(),
210 1,
211 1);
212 if (!hImageList)
213 {
214 /* TODO: Error message */
215 return NULL;
216 }
217
218 AddImageToImageList(hImageList, IDI_INSTALL);
219 AddImageToImageList(hImageList, IDI_UNINSTALL);
220 AddImageToImageList(hImageList, IDI_MODIFY);
221 AddImageToImageList(hImageList, IDI_CHECK_ALL);
222 AddImageToImageList(hImageList, IDI_REFRESH);
223 AddImageToImageList(hImageList, IDI_UPDATE_DB);
224 AddImageToImageList(hImageList, IDI_SETTINGS);
225 AddImageToImageList(hImageList, IDI_EXIT);
226
227 return hImageList;
228 }
229
230 public:
231 VOID OnGetDispInfo(LPTOOLTIPTEXT lpttt)
232 {
233 UINT idButton = (UINT) lpttt->hdr.idFrom;
234
235 switch (idButton)
236 {
237 case ID_EXIT:
238 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXIT);
239 break;
240
241 case ID_INSTALL:
242 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_INSTALL);
243 break;
244
245 case ID_UNINSTALL:
246 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UNINSTALL);
247 break;
248
249 case ID_MODIFY:
250 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_MODIFY);
251 break;
252
253 case ID_SETTINGS:
254 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SETTINGS);
255 break;
256
257 case ID_REFRESH:
258 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH);
259 break;
260
261 case ID_RESETDB:
262 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UPDATE_DB);
263 break;
264 }
265 }
266
267 HWND Create(HWND hwndParent)
268 {
269 HIMAGELIST hImageList;
270
271 // buttons
272 static TBBUTTON Buttons[] =
273 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
274 { 0, ID_INSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szInstallBtn },
275 { 1, ID_UNINSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szUninstallBtn },
276 { 2, ID_MODIFY, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szModifyBtn },
277 { 3, ID_CHECK_ALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE,{0}, 0, (INT_PTR) szSelectAll},
278 {-1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
279 { 4, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
280 { 5, ID_RESETDB, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
281 {-1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
282 { 6, ID_SETTINGS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
283 { 7, ID_EXIT, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
284 };
285
286 LoadStringW(hInst, IDS_INSTALL, szInstallBtn, _countof(szInstallBtn));
287 LoadStringW(hInst, IDS_UNINSTALL, szUninstallBtn, _countof(szUninstallBtn));
288 LoadStringW(hInst, IDS_MODIFY, szModifyBtn, _countof(szModifyBtn));
289 LoadStringW(hInst, IDS_SELECT_ALL, szSelectAll, _countof(szSelectAll));
290
291 m_hWnd = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
292 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST,
293 0, 0, 0, 0,
294 hwndParent,
295 0, hInst, NULL);
296
297 if (!m_hWnd)
298 {
299 /* TODO: Show error message */
300 return FALSE;
301 }
302
303 SendMessageW(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
304 SetButtonStructSize();
305
306 hImageList = InitImageList();
307
308 if (!hImageList)
309 {
310 /* TODO: Show error message */
311 return FALSE;
312 }
313
314 ImageList_Destroy((HIMAGELIST) SetImageList(hImageList));
315
316 AddButtons(_countof(Buttons), Buttons);
317
318 return m_hWnd;
319 }
320 };
321
322 class CAppsListView :
323 public CUiWindow<CListView>
324 {
325 struct SortContext
326 {
327 CAppsListView * lvw;
328 int iSubItem;
329 };
330
331 BOOL bHasAllChecked;
332 BOOL bAscending;
333
334 public:
335 CAppsListView() :
336 bAscending(TRUE),
337 bHasAllChecked(FALSE)
338 {
339 }
340
341 VOID ColumnClick(LPNMLISTVIEW pnmv)
342 {
343 SortContext ctx = {this, pnmv->iSubItem};
344
345 SortItems(s_CompareFunc, &ctx);
346
347 bAscending = !bAscending;
348 }
349
350 PVOID GetLParam(INT Index)
351 {
352 INT ItemIndex;
353 LVITEMW Item;
354
355 if (Index == -1)
356 {
357 ItemIndex = (INT) SendMessage(LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
358 if (ItemIndex == -1)
359 return NULL;
360 }
361 else
362 {
363 ItemIndex = Index;
364 }
365
366 ZeroMemory(&Item, sizeof(Item));
367
368 Item.mask = LVIF_PARAM;
369 Item.iItem = ItemIndex;
370 if (!GetItem(&Item))
371 return NULL;
372
373 return (PVOID) Item.lParam;
374 }
375
376 BOOL AddColumn(INT Index, ATL::CStringW& Text, INT Width, INT Format)
377 {
378 return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, Format);
379 }
380
381 BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
382 {
383 LV_COLUMNW Column;
384
385 ZeroMemory(&Column, sizeof(Column));
386
387 Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
388 Column.iSubItem = Index;
389 Column.pszText = lpText;
390 Column.cx = Width;
391 Column.fmt = Format;
392
393 return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
394 }
395
396 INT AddItem(INT ItemIndex, INT IconIndex, LPWSTR lpText, LPARAM lParam)
397 {
398 LV_ITEMW Item;
399
400 ZeroMemory(&Item, sizeof(Item));
401
402 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
403 Item.pszText = lpText;
404 Item.lParam = lParam;
405 Item.iItem = ItemIndex;
406 Item.iImage = IconIndex;
407
408 return InsertItem(&Item);
409 }
410
411 static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
412 {
413 SortContext * ctx = ((SortContext*) lParamSort);
414 return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
415 }
416
417 INT CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
418 {
419 ATL::CStringW Item1, Item2;
420 LVFINDINFOW IndexInfo;
421 INT Index;
422
423 IndexInfo.flags = LVFI_PARAM;
424
425 IndexInfo.lParam = lParam1;
426 Index = FindItem(-1, &IndexInfo);
427 GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
428 Item1.ReleaseBuffer();
429
430 IndexInfo.lParam = lParam2;
431 Index = FindItem(-1, &IndexInfo);
432 GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
433 Item2.ReleaseBuffer();
434
435 if (bAscending)
436 return Item2 == Item1;
437 else
438 return Item1 == Item2;
439
440 return 0;
441 }
442
443 HWND Create(HWND hwndParent)
444 {
445 RECT r = {205, 28, 465, 250};
446 DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS;
447 HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
448
449 HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE, menu);
450
451 if (hwnd)
452 {
453 SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
454 }
455
456 return hwnd;
457 }
458
459 BOOL GetCheckState(INT item)
460 {
461 return (BOOL) GetItemState(item, LVIS_STATEIMAGEMASK);
462 }
463
464 VOID SetCheckState(INT item, BOOL fCheck)
465 {
466 SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
467 }
468
469 VOID CheckAll()
470 {
471 bHasAllChecked = !bHasAllChecked;
472 SetCheckState(-1, bHasAllChecked);
473 }
474
475 ATL::CAtlList<PAPPLICATION_INFO> GetCheckedItems()
476 {
477 ATL::CAtlList<PAPPLICATION_INFO> list;
478 for (INT i = 0; i != -1; i = GetNextItem(i, LVNI_ALL))
479 {
480 if (GetCheckState(i) != FALSE)
481 {
482 list.AddTail((PAPPLICATION_INFO) GetItemData(i));
483 }
484 }
485 return list;
486 }
487 };
488
489 class CSideTreeView :
490 public CUiWindow<CTreeView>
491 {
492 HIMAGELIST hImageTreeView = ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
493 GetSystemColorDepth() | ILC_MASK,
494 0, 1);
495
496 public:
497 HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
498 {
499 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
500 }
501
502 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
503 {
504 ATL::CStringW szText;
505 INT Index;
506 HICON hIcon;
507
508 hIcon = (HICON) LoadImage(hInst,
509 MAKEINTRESOURCE(IconIndex),
510 IMAGE_ICON,
511 TREEVIEW_ICON_SIZE,
512 TREEVIEW_ICON_SIZE,
513 LR_CREATEDIBSECTION);
514 if (hIcon)
515 {
516 Index = ImageList_AddIcon(hImageTreeView, hIcon);
517 DestroyIcon(hIcon);
518 }
519
520 szText.LoadStringW(hInst, TextIndex);
521 return AddItem(hRootItem, szText, Index, Index, TextIndex);
522 }
523
524 HIMAGELIST SetImageList()
525 {
526 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
527 }
528
529 VOID DestroyImageList()
530 {
531 if (hImageTreeView)
532 ImageList_Destroy(hImageTreeView);
533 }
534
535 ~CSideTreeView()
536 {
537 DestroyImageList();
538 CUiWindow<CTreeView>::~CUiWindow();
539 }
540 };
541
542 class CSearchBar :
543 public CWindow
544 {
545 public:
546 VOID SetText(LPCWSTR lpszText)
547 {
548 SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
549 }
550
551 HWND Create(HWND hwndParent)
552 {
553 ATL::CStringW szBuf;
554 m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
555 WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
556 0, 0, 200, 22,
557 hwndParent, (HMENU) NULL,
558 hInst, 0);
559
560 SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
561 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
562 SetWindowTextW(szBuf);
563 return m_hWnd;
564 }
565
566 };
567
568 class CMainWindow :
569 public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
570 {
571 CUiPanel * m_ClientPanel;
572 CUiSplitPanel * m_VSplitter;
573 CUiSplitPanel * m_HSplitter;
574
575 CMainToolbar * m_Toolbar;
576 CAppsListView * m_ListView;
577
578 CSideTreeView * m_TreeView;
579 CUiWindow<CStatusBar> * m_StatusBar;
580 CUiWindow<CRichEdit> * m_RichEdit;
581
582 CUiWindow<CSearchBar> * m_SearchBar;
583 CAvailableApps m_AvailableApps;
584
585 LPWSTR pLink;
586
587 INT nSelectedApps;
588
589 BOOL bSearchEnabled;
590 BOOL bUpdating;
591 public:
592 CMainWindow() :
593 m_ClientPanel(NULL),
594 pLink(NULL),
595 bSearchEnabled(FALSE)
596 {
597 }
598
599 private:
600 VOID InitApplicationsList()
601 {
602 ATL::CStringW szText;
603
604 /* Add columns to ListView */
605 szText.LoadStringW(hInst, IDS_APP_NAME);
606 m_ListView->AddColumn(0, szText, 200, LVCFMT_LEFT);
607
608 szText.LoadStringW(hInst, IDS_APP_INST_VERSION);
609 m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
610
611 szText.LoadStringW(hInst, IDS_APP_DESCRIPTION);
612 m_ListView->AddColumn(3, szText, 250, LVCFMT_LEFT);
613
614 // Unnesesary since the list updates on every TreeView selection
615 // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
616 }
617
618 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
619 {
620 return m_TreeView->AddCategory(hRootItem, TextIndex, IconIndex);
621 }
622
623 VOID InitCategoriesList()
624 {
625 HTREEITEM hRootItem;
626
627 hRootItem = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
628 AddCategory(hRootItem, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
629 AddCategory(hRootItem, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
630 AddCategory(hRootItem, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
631 AddCategory(hRootItem, IDS_CAT_GAMES, IDI_CAT_GAMES);
632 AddCategory(hRootItem, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
633 AddCategory(hRootItem, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
634 AddCategory(hRootItem, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
635 AddCategory(hRootItem, IDS_CAT_EDU, IDI_CAT_EDU);
636 AddCategory(hRootItem, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
637 AddCategory(hRootItem, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
638 AddCategory(hRootItem, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
639 AddCategory(hRootItem, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
640 AddCategory(hRootItem, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
641 AddCategory(hRootItem, IDS_CAT_LIBS, IDI_CAT_LIBS);
642 AddCategory(hRootItem, IDS_CAT_OTHER, IDI_CAT_OTHER);
643
644 m_TreeView->SetImageList();
645 m_TreeView->Expand(hRootItem, TVE_EXPAND);
646 m_TreeView->SelectItem(hRootItem);
647 }
648
649 BOOL CreateStatusBar()
650 {
651 m_StatusBar = new CUiWindow<CStatusBar>();
652 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
653 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
654 m_ClientPanel->Children().Append(m_StatusBar);
655
656 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
657 }
658
659 BOOL CreateToolbar()
660 {
661 m_Toolbar = new CMainToolbar();
662 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
663 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
664 m_ClientPanel->Children().Append(m_Toolbar);
665
666 return m_Toolbar->Create(m_hWnd) != NULL;
667 }
668
669 BOOL CreateTreeView()
670 {
671 m_TreeView = new CSideTreeView();
672 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
673 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
674 m_VSplitter->First().Append(m_TreeView);
675
676 return m_TreeView->Create(m_hWnd) != NULL;
677 }
678
679 BOOL CreateListView()
680 {
681 m_ListView = new CAppsListView();
682 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
683 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
684 m_HSplitter->First().Append(m_ListView);
685
686 hListView = m_ListView->Create(m_hWnd);
687 return hListView != NULL;
688 }
689
690 BOOL CreateRichEdit()
691 {
692 m_RichEdit = new CUiWindow<CRichEdit>();
693 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
694 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
695 m_HSplitter->Second().Append(m_RichEdit);
696
697 return m_RichEdit->Create(m_hWnd) != NULL;
698 }
699
700 BOOL CreateVSplitter()
701 {
702 m_VSplitter = new CUiSplitPanel();
703 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
704 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
705 m_VSplitter->m_DynamicFirst = FALSE;
706 m_VSplitter->m_Horizontal = FALSE;
707 m_VSplitter->m_MinFirst = 240;
708 m_VSplitter->m_MinSecond = 300;
709 m_ClientPanel->Children().Append(m_VSplitter);
710
711 return m_VSplitter->Create(m_hWnd) != NULL;
712 }
713
714 BOOL CreateHSplitter()
715 {
716 m_HSplitter = new CUiSplitPanel();
717 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
718 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
719 m_HSplitter->m_DynamicFirst = TRUE;
720 m_HSplitter->m_Horizontal = TRUE;
721 m_HSplitter->m_Pos = 32768;
722 m_HSplitter->m_MinFirst = 300;
723 m_HSplitter->m_MinSecond = 150;
724 m_VSplitter->Second().Append(m_HSplitter);
725
726 return m_HSplitter->Create(m_hWnd) != NULL;
727 }
728
729 BOOL CreateSearchBar()
730 {
731 m_SearchBar = new CUiWindow<CSearchBar>();
732 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
733 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
734 m_SearchBar->m_Margin.top = 6;
735 m_SearchBar->m_Margin.right = 6;
736
737 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
738 }
739
740 BOOL CreateLayout()
741 {
742 BOOL b = TRUE;
743 bUpdating = TRUE;
744
745 m_ClientPanel = new CUiPanel();
746 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
747 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
748
749 // Top level
750 b = b && CreateStatusBar();
751 b = b && CreateToolbar();
752 b = b && CreateSearchBar();
753 b = b && CreateVSplitter();
754
755 // Inside V Splitter
756 b = b && CreateHSplitter();
757 b = b && CreateTreeView();
758
759 // Inside H Splitter
760 b = b && CreateListView();
761 b = b && CreateRichEdit();
762
763 if (b)
764 {
765 RECT rTop;
766 RECT rBottom;
767
768 /* Size status bar */
769 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
770
771 /* Size tool bar */
772 m_Toolbar->AutoSize();
773
774 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
775 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
776
777 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
778 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
779 }
780
781 bUpdating = FALSE;
782 return b;
783 }
784
785 BOOL InitControls()
786 {
787 if (CreateLayout())
788 {
789
790 InitApplicationsList();
791 InitCategoriesList();
792
793 nSelectedApps = 0;
794 UpdateStatusBarText();
795
796 return TRUE;
797 }
798
799 return FALSE;
800 }
801
802 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
803 {
804 /* Size status bar */
805 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
806
807 /* Size tool bar */
808 m_Toolbar->AutoSize();
809
810 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
811 HDWP hdwp = NULL;
812 int count = m_ClientPanel->CountSizableChildren();
813
814 hdwp = BeginDeferWindowPos(count);
815 if (hdwp)
816 {
817 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
818 }
819 if (hdwp)
820 {
821 EndDeferWindowPos(hdwp);
822 }
823
824 // TODO: Sub-layouts for children of children
825 count = m_SearchBar->CountSizableChildren();
826 hdwp = BeginDeferWindowPos(count);
827 if (hdwp)
828 {
829 hdwp = m_SearchBar->OnParentSize(r, hdwp);
830 }
831 if (hdwp)
832 {
833 EndDeferWindowPos(hdwp);
834 }
835 }
836
837 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
838 {
839 theResult = 0;
840 switch (Msg)
841 {
842 case WM_CREATE:
843 if (!InitControls())
844 ::PostMessage(hwnd, WM_CLOSE, 0, 0);
845 break;
846
847 case WM_DESTROY:
848 {
849 ShowWindow(SW_HIDE);
850 SaveSettings(hwnd);
851
852 FreeLogs();
853
854 if (IS_INSTALLED_ENUM(SelectedEnumType))
855 FreeInstalledAppList();
856
857 delete m_ClientPanel;
858
859 PostQuitMessage(0);
860 return 0;
861 }
862
863 case WM_COMMAND:
864 OnCommand(wParam, lParam);
865 break;
866
867 case WM_NOTIFY:
868 {
869 LPNMHDR data = (LPNMHDR) lParam;
870
871 switch (data->code)
872 {
873 case TVN_SELCHANGED:
874 {
875 if (data->hwndFrom == m_TreeView->m_hWnd)
876 {
877 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
878 {
879 case IDS_INSTALLED:
880 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
881 break;
882
883 case IDS_APPLICATIONS:
884 UpdateApplicationsList(ENUM_APPLICATIONS);
885 break;
886
887 case IDS_UPDATES:
888 UpdateApplicationsList(ENUM_UPDATES);
889 break;
890
891 case IDS_AVAILABLEFORINST:
892 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
893 break;
894
895 case IDS_CAT_AUDIO:
896 UpdateApplicationsList(ENUM_CAT_AUDIO);
897 break;
898
899 case IDS_CAT_DEVEL:
900 UpdateApplicationsList(ENUM_CAT_DEVEL);
901 break;
902
903 case IDS_CAT_DRIVERS:
904 UpdateApplicationsList(ENUM_CAT_DRIVERS);
905 break;
906
907 case IDS_CAT_EDU:
908 UpdateApplicationsList(ENUM_CAT_EDU);
909 break;
910
911 case IDS_CAT_ENGINEER:
912 UpdateApplicationsList(ENUM_CAT_ENGINEER);
913 break;
914
915 case IDS_CAT_FINANCE:
916 UpdateApplicationsList(ENUM_CAT_FINANCE);
917 break;
918
919 case IDS_CAT_GAMES:
920 UpdateApplicationsList(ENUM_CAT_GAMES);
921 break;
922
923 case IDS_CAT_GRAPHICS:
924 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
925 break;
926
927 case IDS_CAT_INTERNET:
928 UpdateApplicationsList(ENUM_CAT_INTERNET);
929 break;
930
931 case IDS_CAT_LIBS:
932 UpdateApplicationsList(ENUM_CAT_LIBS);
933 break;
934
935 case IDS_CAT_OFFICE:
936 UpdateApplicationsList(ENUM_CAT_OFFICE);
937 break;
938
939 case IDS_CAT_OTHER:
940 UpdateApplicationsList(ENUM_CAT_OTHER);
941 break;
942
943 case IDS_CAT_SCIENCE:
944 UpdateApplicationsList(ENUM_CAT_SCIENCE);
945 break;
946
947 case IDS_CAT_TOOLS:
948 UpdateApplicationsList(ENUM_CAT_TOOLS);
949 break;
950
951 case IDS_CAT_VIDEO:
952 UpdateApplicationsList(ENUM_CAT_VIDEO);
953 break;
954 }
955 }
956
957 HMENU mainMenu = ::GetMenu(hwnd);
958 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
959
960 /* Disable/enable items based on treeview selection */
961 if (IsSelectedNodeInstalled())
962 {
963 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
964 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
965 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
966 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
967
968 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
969 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
970 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
971 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
972
973 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
974 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
975 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
976 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
977 }
978 else
979 {
980 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
981 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
982 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
983 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
984
985 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
986 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
987 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
988 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
989
990 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
991 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
992 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
993 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
994 }
995 }
996 break;
997
998 case LVN_ITEMCHANGED:
999 {
1000 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1001
1002 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1003 {
1004 /* Check if this is a valid item
1005 * (technically, it can be also an unselect) */
1006 INT ItemIndex = pnic->iItem;
1007 if (ItemIndex == -1 ||
1008 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1009 {
1010 break;
1011 }
1012
1013 /* Check if the focus has been moved to another item */
1014 if ((pnic->uChanged & LVIF_STATE) &&
1015 (pnic->uNewState & LVIS_FOCUSED) &&
1016 !(pnic->uOldState & LVIS_FOCUSED))
1017 {
1018 if (IS_INSTALLED_ENUM(SelectedEnumType))
1019 ShowInstalledAppInfo(ItemIndex);
1020 if (IS_AVAILABLE_ENUM(SelectedEnumType))
1021 CAvailableAppView::ShowAvailableAppInfo(ItemIndex);
1022 }
1023 /* Check if the item is checked */
1024 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1025 {
1026 BOOL checked = m_ListView->GetCheckState(pnic->iItem);
1027 nSelectedApps += (checked) ? 1 : -1;
1028 UpdateStatusBarText();
1029 }
1030 }
1031 }
1032 break;
1033
1034 case LVN_COLUMNCLICK:
1035 {
1036 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1037
1038 m_ListView->ColumnClick(pnmv);
1039 }
1040 break;
1041
1042 case NM_CLICK:
1043 {
1044 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1045 {
1046 if (IS_INSTALLED_ENUM(SelectedEnumType))
1047 ShowInstalledAppInfo(-1);
1048 if (IS_AVAILABLE_ENUM(SelectedEnumType))
1049 CAvailableAppView::ShowAvailableAppInfo(-1);
1050 }
1051 }
1052 break;
1053
1054 case NM_DBLCLK:
1055 {
1056 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1057 {
1058 /* this won't do anything if the program is already installed */
1059 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1060 }
1061 }
1062 break;
1063
1064 case NM_RCLICK:
1065 {
1066 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1067 {
1068 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1069 }
1070 }
1071 break;
1072
1073 case EN_LINK:
1074 OnLink((ENLINK*) lParam);
1075 break;
1076
1077 case TTN_GETDISPINFO:
1078 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1079 break;
1080 }
1081 }
1082 break;
1083
1084 case WM_SIZE:
1085 OnSize(hwnd, wParam, lParam);
1086 break;
1087
1088 case WM_SIZING:
1089 {
1090 LPRECT pRect = (LPRECT) lParam;
1091
1092 if (pRect->right - pRect->left < 565)
1093 pRect->right = pRect->left + 565;
1094
1095 if (pRect->bottom - pRect->top < 300)
1096 pRect->bottom = pRect->top + 300;
1097
1098 return TRUE;
1099 }
1100
1101 case WM_SYSCOLORCHANGE:
1102 {
1103 /* Forward WM_SYSCOLORCHANGE to common controls */
1104 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1105 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1106 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1107 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1108 }
1109 break;
1110
1111 case WM_TIMER:
1112 if (wParam == SEARCH_TIMER_ID)
1113 {
1114 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1115 if (bSearchEnabled)
1116 UpdateApplicationsList(-1);
1117 }
1118 break;
1119 }
1120
1121 return FALSE;
1122 }
1123
1124 virtual VOID OnLink(ENLINK *Link)
1125 {
1126 switch (Link->msg)
1127 {
1128 case WM_LBUTTONUP:
1129 case WM_RBUTTONUP:
1130 {
1131 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1132
1133 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1134 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1135 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1136 if (!pLink)
1137 {
1138 /* TODO: Error message */
1139 return;
1140 }
1141
1142 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1143 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1144
1145 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1146 }
1147 break;
1148 }
1149 }
1150
1151 BOOL IsSelectedNodeInstalled()
1152 {
1153 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1154 TV_ITEM tItem;
1155
1156 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1157 tItem.hItem = hSelectedItem;
1158 m_TreeView->GetItem(&tItem);
1159 switch (tItem.lParam)
1160 {
1161 case IDS_INSTALLED:
1162 case IDS_APPLICATIONS:
1163 case IDS_UPDATES:
1164 return TRUE;
1165 default:
1166 return FALSE;
1167 }
1168 }
1169
1170 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1171 {
1172 WORD wCommand = LOWORD(wParam);
1173
1174 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1175 {
1176 ATL::CStringW szBuf;
1177
1178 switch (HIWORD(wParam))
1179 {
1180 case EN_SETFOCUS:
1181 {
1182 ATL::CStringW szWndText;
1183
1184 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1185 m_SearchBar->GetWindowTextW(szWndText);
1186 if (szBuf == szWndText)
1187 {
1188 bSearchEnabled = FALSE;
1189 m_SearchBar->SetWindowTextW(L"");
1190 }
1191 }
1192 break;
1193
1194 case EN_KILLFOCUS:
1195 {
1196 m_SearchBar->GetWindowTextW(szBuf);
1197 if (szBuf.IsEmpty())
1198 {
1199 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1200 bSearchEnabled = FALSE;
1201 m_SearchBar->SetWindowTextW(szBuf.GetString());
1202 }
1203 }
1204 break;
1205
1206 case EN_CHANGE:
1207 {
1208 ATL::CStringW szWndText;
1209
1210 if (!bSearchEnabled)
1211 {
1212 bSearchEnabled = TRUE;
1213 break;
1214 }
1215
1216 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1217 m_SearchBar->GetWindowTextW(szWndText);
1218 if (szBuf == szWndText)
1219 {
1220 szSearchPattern.Empty();
1221 }
1222 else
1223 {
1224 szSearchPattern = szWndText;
1225 }
1226
1227 DWORD dwDelay;
1228 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1229 SetTimer(SEARCH_TIMER_ID, dwDelay);
1230 }
1231 break;
1232 }
1233
1234 return;
1235 }
1236
1237 switch (wCommand)
1238 {
1239 case ID_OPEN_LINK:
1240 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1241 HeapFree(GetProcessHeap(), 0, pLink);
1242 break;
1243
1244 case ID_COPY_LINK:
1245 CopyTextToClipboard(pLink);
1246 HeapFree(GetProcessHeap(), 0, pLink);
1247 break;
1248
1249 case ID_SETTINGS:
1250 CreateSettingsDlg(m_hWnd);
1251 break;
1252
1253 case ID_EXIT:
1254 PostMessageW(WM_CLOSE, 0, 0);
1255 break;
1256
1257 case ID_INSTALL:
1258 if (DownloadApplication(-1))
1259 /* TODO: Implement install dialog
1260 * if (InstallApplication(-1))
1261 */
1262 UpdateApplicationsList(-1);
1263 break;
1264
1265 case ID_UNINSTALL:
1266 if (UninstallApplication(-1, FALSE))
1267 UpdateApplicationsList(-1);
1268 break;
1269
1270 case ID_MODIFY:
1271 if (UninstallApplication(-1, TRUE))
1272 UpdateApplicationsList(-1);
1273 break;
1274
1275 case ID_REGREMOVE:
1276 RemoveAppFromRegistry(-1);
1277 break;
1278
1279 case ID_REFRESH:
1280 UpdateApplicationsList(-1);
1281 break;
1282
1283 case ID_RESETDB:
1284 m_AvailableApps.UpdateAppsDB();
1285 UpdateApplicationsList(-1);
1286 break;
1287
1288 case ID_HELP:
1289 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1290 break;
1291
1292 case ID_ABOUT:
1293 ShowAboutDialog();
1294 break;
1295
1296 case ID_CHECK_ALL:
1297 m_ListView->CheckAll();
1298 break;
1299 }
1300 }
1301
1302 VOID FreeInstalledAppList()
1303 {
1304 INT Count = m_ListView->GetItemCount() - 1;
1305 PINSTALLED_INFO Info;
1306
1307 while (Count >= 0)
1308 {
1309 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1310 if (Info)
1311 {
1312 RegCloseKey(Info->hSubKey);
1313 delete Info;
1314 }
1315 Count--;
1316 }
1317 }
1318
1319 static BOOL SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
1320 {
1321 if (!*szNeedle)
1322 return TRUE;
1323 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1324 return StrStrIW(szHaystack, szNeedle) != NULL;
1325 }
1326
1327 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, LPWSTR lpName, PINSTALLED_INFO Info)
1328 {
1329 PINSTALLED_INFO ItemInfo;
1330 ATL::CStringW szText;
1331 INT Index;
1332
1333 if (!SearchPatternMatch(lpName, szSearchPattern))
1334 {
1335 RegCloseKey(Info->hSubKey);
1336 return TRUE;
1337 }
1338
1339 ItemInfo = (PINSTALLED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(INSTALLED_INFO));
1340 if (!ItemInfo)
1341 {
1342 RegCloseKey(Info->hSubKey);
1343 return FALSE;
1344 }
1345
1346 RtlCopyMemory(ItemInfo, Info, sizeof(INSTALLED_INFO));
1347
1348 Index = ListViewAddItem(ItemIndex, 0, lpName, (LPARAM) ItemInfo);
1349
1350 /* Get version info */
1351 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
1352 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(szText.GetString()));
1353
1354 /* Get comments */
1355 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
1356 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(szText.GetString()));
1357
1358 return TRUE;
1359 }
1360
1361 static BOOL CALLBACK s_EnumAvailableAppProc(PAPPLICATION_INFO Info, LPCWSTR szFolderPath)
1362 {
1363 INT Index;
1364 HICON hIcon = NULL;
1365
1366 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1367
1368 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
1369 !SearchPatternMatch(Info->szDesc, szSearchPattern))
1370 {
1371 return TRUE;
1372 }
1373
1374 /* Load icon from file */
1375 ATL::CStringW szIconPath;
1376 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->szName);
1377 hIcon = (HICON) LoadImageW(NULL,
1378 szIconPath.GetString(),
1379 IMAGE_ICON,
1380 LISTVIEW_ICON_SIZE,
1381 LISTVIEW_ICON_SIZE,
1382 LR_LOADFROMFILE);
1383
1384 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1385 {
1386 /* Load default icon */
1387 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1388 }
1389
1390 Index = ImageList_AddIcon(hImageListView, hIcon);
1391 DestroyIcon(hIcon);
1392
1393 Index = ListViewAddItem(Info->Category, Index, Info->szName, (LPARAM) Info);
1394 ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1395
1396 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(Info->szVersion.GetString()));
1397 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(Info->szDesc.GetString()));
1398
1399 return TRUE;
1400 }
1401
1402 VOID UpdateStatusBarText()
1403 {
1404 if (m_StatusBar)
1405 {
1406 ATL::CStringW szBuffer1, szBuffer2;
1407
1408 szBuffer2.LoadStringW(hInst, IDS_APPS_COUNT);
1409 szBuffer1.Format(szBuffer2, m_ListView->GetItemCount(), nSelectedApps);
1410 m_StatusBar->SetText(szBuffer1);
1411 }
1412 }
1413
1414 VOID UpdateApplicationsList(INT EnumType)
1415 {
1416 ATL::CStringW szBuffer1, szBuffer2;
1417 HIMAGELIST hImageListView;
1418 bUpdating = TRUE;
1419
1420 m_ListView->SetRedraw(FALSE);
1421
1422 nSelectedApps = 0;
1423 if (EnumType < 0) EnumType = SelectedEnumType;
1424
1425 if (IS_INSTALLED_ENUM(SelectedEnumType))
1426 FreeInstalledAppList();
1427
1428 m_ListView->DeleteAllItems();
1429
1430 /* Create new ImageList */
1431 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1432 LISTVIEW_ICON_SIZE,
1433 GetSystemColorDepth() | ILC_MASK,
1434 0, 1);
1435 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1436 if (hImageListBuf)
1437 {
1438 ImageList_Destroy(hImageListBuf);
1439 }
1440
1441 if (IS_AVAILABLE_ENUM(EnumType))
1442 {
1443 /* Enum available applications */
1444 m_AvailableApps.EnumAvailableApplications(EnumType, s_EnumAvailableAppProc);
1445 }
1446
1447 SelectedEnumType = EnumType;
1448
1449 UpdateStatusBarText();
1450
1451 SetWelcomeText();
1452
1453 /* set automatic column width for program names if the list is not empty */
1454 if (m_ListView->GetItemCount() > 0)
1455 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1456
1457 bUpdating = FALSE;
1458 m_ListView->SetRedraw(TRUE);
1459 }
1460
1461 public:
1462 static ATL::CWndClassInfo& GetWndClassInfo()
1463 {
1464 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1465 static ATL::CWndClassInfo wc =
1466 {
1467 {
1468 sizeof(WNDCLASSEX),
1469 csStyle,
1470 StartWindowProc,
1471 0,
1472 0,
1473 NULL,
1474 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1475 LoadCursorW(NULL, IDC_ARROW),
1476 (HBRUSH) (COLOR_BTNFACE + 1),
1477 MAKEINTRESOURCEW(IDR_MAINMENU),
1478 L"RAppsWnd",
1479 NULL
1480 },
1481 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1482 };
1483 return wc;
1484 }
1485
1486 HWND Create()
1487 {
1488 ATL::CStringW szWindowName;
1489 szWindowName.LoadStringW(hInst, IDS_APPTITLE);
1490
1491 RECT r = {
1492 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1493 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1494 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1495 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1496 };
1497 r.right += r.left;
1498 r.bottom += r.top;
1499
1500 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1501 }
1502
1503 CStatusBar * GetStatusBar()
1504 {
1505 return m_StatusBar;
1506 }
1507
1508 CAppsListView * GetListView()
1509 {
1510 return m_ListView;
1511 }
1512
1513 CRichEdit * GetRichEdit()
1514 {
1515 return m_RichEdit;
1516 }
1517
1518 CAvailableApps * GetAvailableApps()
1519 {
1520 return &m_AvailableApps;
1521 }
1522 };
1523
1524 // File interface
1525
1526 CMainWindow * g_MainWindow;
1527
1528 HWND CreateMainWindow()
1529 {
1530 g_MainWindow = new CMainWindow();
1531 return g_MainWindow->Create();
1532 }
1533
1534 DWORD_PTR ListViewGetlParam(INT item)
1535 {
1536 if (item < 0)
1537 {
1538 item = g_MainWindow->GetListView()->GetSelectionMark();
1539 }
1540 return g_MainWindow->GetListView()->GetItemData(item);
1541 }
1542
1543 VOID SetStatusBarText(LPCWSTR szText)
1544 {
1545 g_MainWindow->GetStatusBar()->SetText(szText);
1546 }
1547
1548 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1549 {
1550 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1551 }
1552
1553 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1554 {
1555 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1556 }
1557
1558 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1559 {
1560 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1561 }
1562
1563 /* ATL version of functions */
1564 VOID SetStatusBarText(const ATL::CStringW& szText)
1565 {
1566 SetStatusBarText(szText.GetString());
1567 }
1568
1569 INT ListViewAddItem(INT ItemIndex, INT IconIndex, ATL::CStringW & Name, LPARAM lParam)
1570 {
1571 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1572 }
1573
1574 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1575 {
1576 NewRichEditText(szText.GetString(), flags);
1577 }
1578
1579 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1580 {
1581 InsertRichEditText(szText.GetString(), flags);
1582 }
1583
1584 CAvailableApps* GetAvailableApps()
1585 {
1586 return g_MainWindow->GetAvailableApps();
1587 }