[RAPPS]
[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) >> 12) - 1;
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::CSimpleArray<PAPPLICATION_INFO> GetCheckedItems()
476 {
477 ATL::CSimpleArray<PAPPLICATION_INFO> list;
478 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
479 {
480 if (GetCheckState(i) != FALSE)
481 {
482 PAPPLICATION_INFO pAppInfo = (PAPPLICATION_INFO) GetItemData(i);
483 list.Add(pAppInfo);
484 }
485 }
486 return list;
487 }
488 };
489
490 class CSideTreeView :
491 public CUiWindow<CTreeView>
492 {
493 HIMAGELIST hImageTreeView = ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
494 GetSystemColorDepth() | ILC_MASK,
495 0, 1);
496
497 public:
498 HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
499 {
500 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
501 }
502
503 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
504 {
505 ATL::CStringW szText;
506 INT Index;
507 HICON hIcon;
508
509 hIcon = (HICON) LoadImage(hInst,
510 MAKEINTRESOURCE(IconIndex),
511 IMAGE_ICON,
512 TREEVIEW_ICON_SIZE,
513 TREEVIEW_ICON_SIZE,
514 LR_CREATEDIBSECTION);
515 if (hIcon)
516 {
517 Index = ImageList_AddIcon(hImageTreeView, hIcon);
518 DestroyIcon(hIcon);
519 }
520
521 szText.LoadStringW(hInst, TextIndex);
522 return AddItem(hRootItem, szText, Index, Index, TextIndex);
523 }
524
525 HIMAGELIST SetImageList()
526 {
527 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
528 }
529
530 VOID DestroyImageList()
531 {
532 if (hImageTreeView)
533 ImageList_Destroy(hImageTreeView);
534 }
535
536 ~CSideTreeView()
537 {
538 DestroyImageList();
539 CUiWindow<CTreeView>::~CUiWindow();
540 }
541 };
542
543 class CSearchBar :
544 public CWindow
545 {
546 public:
547 VOID SetText(LPCWSTR lpszText)
548 {
549 SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
550 }
551
552 HWND Create(HWND hwndParent)
553 {
554 ATL::CStringW szBuf;
555 m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
556 WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
557 0, 0, 200, 22,
558 hwndParent, (HMENU) NULL,
559 hInst, 0);
560
561 SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
562 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
563 SetWindowTextW(szBuf);
564 return m_hWnd;
565 }
566
567 };
568
569 class CMainWindow :
570 public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
571 {
572 CUiPanel * m_ClientPanel;
573 CUiSplitPanel * m_VSplitter;
574 CUiSplitPanel * m_HSplitter;
575
576 CMainToolbar * m_Toolbar;
577 CAppsListView * m_ListView;
578
579 CSideTreeView * m_TreeView;
580 CUiWindow<CStatusBar> * m_StatusBar;
581 CUiWindow<CRichEdit> * m_RichEdit;
582
583 CUiWindow<CSearchBar> * m_SearchBar;
584 CAvailableApps m_AvailableApps;
585
586 LPWSTR pLink;
587
588 INT nSelectedApps;
589
590 BOOL bSearchEnabled;
591 BOOL bUpdating;
592 public:
593 CMainWindow() :
594 m_ClientPanel(NULL),
595 pLink(NULL),
596 bSearchEnabled(FALSE)
597 {
598 }
599
600 private:
601 VOID InitApplicationsList()
602 {
603 ATL::CStringW szText;
604
605 /* Add columns to ListView */
606 szText.LoadStringW(hInst, IDS_APP_NAME);
607 m_ListView->AddColumn(0, szText, 200, LVCFMT_LEFT);
608
609 szText.LoadStringW(hInst, IDS_APP_INST_VERSION);
610 m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
611
612 szText.LoadStringW(hInst, IDS_APP_DESCRIPTION);
613 m_ListView->AddColumn(3, szText, 250, LVCFMT_LEFT);
614
615 // Unnesesary since the list updates on every TreeView selection
616 // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
617 }
618
619 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
620 {
621 return m_TreeView->AddCategory(hRootItem, TextIndex, IconIndex);
622 }
623
624 VOID InitCategoriesList()
625 {
626 HTREEITEM hRootItem;
627
628 hRootItem = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
629 AddCategory(hRootItem, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
630 AddCategory(hRootItem, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
631 AddCategory(hRootItem, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
632 AddCategory(hRootItem, IDS_CAT_GAMES, IDI_CAT_GAMES);
633 AddCategory(hRootItem, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
634 AddCategory(hRootItem, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
635 AddCategory(hRootItem, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
636 AddCategory(hRootItem, IDS_CAT_EDU, IDI_CAT_EDU);
637 AddCategory(hRootItem, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
638 AddCategory(hRootItem, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
639 AddCategory(hRootItem, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
640 AddCategory(hRootItem, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
641 AddCategory(hRootItem, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
642 AddCategory(hRootItem, IDS_CAT_LIBS, IDI_CAT_LIBS);
643 AddCategory(hRootItem, IDS_CAT_OTHER, IDI_CAT_OTHER);
644
645 m_TreeView->SetImageList();
646 m_TreeView->Expand(hRootItem, TVE_EXPAND);
647 m_TreeView->SelectItem(hRootItem);
648 }
649
650 BOOL CreateStatusBar()
651 {
652 m_StatusBar = new CUiWindow<CStatusBar>();
653 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
654 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
655 m_ClientPanel->Children().Append(m_StatusBar);
656
657 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
658 }
659
660 BOOL CreateToolbar()
661 {
662 m_Toolbar = new CMainToolbar();
663 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
664 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
665 m_ClientPanel->Children().Append(m_Toolbar);
666
667 return m_Toolbar->Create(m_hWnd) != NULL;
668 }
669
670 BOOL CreateTreeView()
671 {
672 m_TreeView = new CSideTreeView();
673 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
674 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
675 m_VSplitter->First().Append(m_TreeView);
676
677 return m_TreeView->Create(m_hWnd) != NULL;
678 }
679
680 BOOL CreateListView()
681 {
682 m_ListView = new CAppsListView();
683 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
684 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
685 m_HSplitter->First().Append(m_ListView);
686
687 hListView = m_ListView->Create(m_hWnd);
688 return hListView != NULL;
689 }
690
691 BOOL CreateRichEdit()
692 {
693 m_RichEdit = new CUiWindow<CRichEdit>();
694 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
695 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
696 m_HSplitter->Second().Append(m_RichEdit);
697
698 return m_RichEdit->Create(m_hWnd) != NULL;
699 }
700
701 BOOL CreateVSplitter()
702 {
703 m_VSplitter = new CUiSplitPanel();
704 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
705 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
706 m_VSplitter->m_DynamicFirst = FALSE;
707 m_VSplitter->m_Horizontal = FALSE;
708 m_VSplitter->m_MinFirst = 240;
709 m_VSplitter->m_MinSecond = 300;
710 m_ClientPanel->Children().Append(m_VSplitter);
711
712 return m_VSplitter->Create(m_hWnd) != NULL;
713 }
714
715 BOOL CreateHSplitter()
716 {
717 m_HSplitter = new CUiSplitPanel();
718 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
719 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
720 m_HSplitter->m_DynamicFirst = TRUE;
721 m_HSplitter->m_Horizontal = TRUE;
722 m_HSplitter->m_Pos = 32768;
723 m_HSplitter->m_MinFirst = 300;
724 m_HSplitter->m_MinSecond = 150;
725 m_VSplitter->Second().Append(m_HSplitter);
726
727 return m_HSplitter->Create(m_hWnd) != NULL;
728 }
729
730 BOOL CreateSearchBar()
731 {
732 m_SearchBar = new CUiWindow<CSearchBar>();
733 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
734 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
735 m_SearchBar->m_Margin.top = 6;
736 m_SearchBar->m_Margin.right = 6;
737
738 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
739 }
740
741 BOOL CreateLayout()
742 {
743 BOOL b = TRUE;
744 bUpdating = TRUE;
745
746 m_ClientPanel = new CUiPanel();
747 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
748 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
749
750 // Top level
751 b = b && CreateStatusBar();
752 b = b && CreateToolbar();
753 b = b && CreateSearchBar();
754 b = b && CreateVSplitter();
755
756 // Inside V Splitter
757 b = b && CreateHSplitter();
758 b = b && CreateTreeView();
759
760 // Inside H Splitter
761 b = b && CreateListView();
762 b = b && CreateRichEdit();
763
764 if (b)
765 {
766 RECT rTop;
767 RECT rBottom;
768
769 /* Size status bar */
770 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
771
772 /* Size tool bar */
773 m_Toolbar->AutoSize();
774
775 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
776 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
777
778 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
779 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
780 }
781
782 bUpdating = FALSE;
783 return b;
784 }
785
786 BOOL InitControls()
787 {
788 if (CreateLayout())
789 {
790
791 InitApplicationsList();
792 InitCategoriesList();
793
794 nSelectedApps = 0;
795 UpdateStatusBarText();
796
797 return TRUE;
798 }
799
800 return FALSE;
801 }
802
803 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
804 {
805 /* Size status bar */
806 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
807
808 /* Size tool bar */
809 m_Toolbar->AutoSize();
810
811 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
812 HDWP hdwp = NULL;
813 int count = m_ClientPanel->CountSizableChildren();
814
815 hdwp = BeginDeferWindowPos(count);
816 if (hdwp)
817 {
818 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
819 }
820 if (hdwp)
821 {
822 EndDeferWindowPos(hdwp);
823 }
824
825 // TODO: Sub-layouts for children of children
826 count = m_SearchBar->CountSizableChildren();
827 hdwp = BeginDeferWindowPos(count);
828 if (hdwp)
829 {
830 hdwp = m_SearchBar->OnParentSize(r, hdwp);
831 }
832 if (hdwp)
833 {
834 EndDeferWindowPos(hdwp);
835 }
836 }
837
838 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
839 {
840 theResult = 0;
841 switch (Msg)
842 {
843 case WM_CREATE:
844 if (!InitControls())
845 ::PostMessage(hwnd, WM_CLOSE, 0, 0);
846 break;
847
848 case WM_DESTROY:
849 {
850 ShowWindow(SW_HIDE);
851 SaveSettings(hwnd);
852
853 FreeLogs();
854
855 if (IS_INSTALLED_ENUM(SelectedEnumType))
856 FreeInstalledAppList();
857
858 delete m_ClientPanel;
859
860 PostQuitMessage(0);
861 return 0;
862 }
863
864 case WM_COMMAND:
865 OnCommand(wParam, lParam);
866 break;
867
868 case WM_NOTIFY:
869 {
870 LPNMHDR data = (LPNMHDR) lParam;
871
872 switch (data->code)
873 {
874 case TVN_SELCHANGED:
875 {
876 if (data->hwndFrom == m_TreeView->m_hWnd)
877 {
878 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
879 {
880 case IDS_INSTALLED:
881 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
882 break;
883
884 case IDS_APPLICATIONS:
885 UpdateApplicationsList(ENUM_APPLICATIONS);
886 break;
887
888 case IDS_UPDATES:
889 UpdateApplicationsList(ENUM_UPDATES);
890 break;
891
892 case IDS_AVAILABLEFORINST:
893 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
894 break;
895
896 case IDS_CAT_AUDIO:
897 UpdateApplicationsList(ENUM_CAT_AUDIO);
898 break;
899
900 case IDS_CAT_DEVEL:
901 UpdateApplicationsList(ENUM_CAT_DEVEL);
902 break;
903
904 case IDS_CAT_DRIVERS:
905 UpdateApplicationsList(ENUM_CAT_DRIVERS);
906 break;
907
908 case IDS_CAT_EDU:
909 UpdateApplicationsList(ENUM_CAT_EDU);
910 break;
911
912 case IDS_CAT_ENGINEER:
913 UpdateApplicationsList(ENUM_CAT_ENGINEER);
914 break;
915
916 case IDS_CAT_FINANCE:
917 UpdateApplicationsList(ENUM_CAT_FINANCE);
918 break;
919
920 case IDS_CAT_GAMES:
921 UpdateApplicationsList(ENUM_CAT_GAMES);
922 break;
923
924 case IDS_CAT_GRAPHICS:
925 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
926 break;
927
928 case IDS_CAT_INTERNET:
929 UpdateApplicationsList(ENUM_CAT_INTERNET);
930 break;
931
932 case IDS_CAT_LIBS:
933 UpdateApplicationsList(ENUM_CAT_LIBS);
934 break;
935
936 case IDS_CAT_OFFICE:
937 UpdateApplicationsList(ENUM_CAT_OFFICE);
938 break;
939
940 case IDS_CAT_OTHER:
941 UpdateApplicationsList(ENUM_CAT_OTHER);
942 break;
943
944 case IDS_CAT_SCIENCE:
945 UpdateApplicationsList(ENUM_CAT_SCIENCE);
946 break;
947
948 case IDS_CAT_TOOLS:
949 UpdateApplicationsList(ENUM_CAT_TOOLS);
950 break;
951
952 case IDS_CAT_VIDEO:
953 UpdateApplicationsList(ENUM_CAT_VIDEO);
954 break;
955 }
956 }
957
958 HMENU mainMenu = ::GetMenu(hwnd);
959 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
960
961 /* Disable/enable items based on treeview selection */
962 if (IsSelectedNodeInstalled())
963 {
964 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
965 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
966 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
967 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
968
969 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
970 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
971 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
972 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
973
974 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
975 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
976 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
977 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
978 }
979 else
980 {
981 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
982 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
983 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
984 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
985
986 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
987 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
988 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
989 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
990
991 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
992 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
993 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
994 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
995 }
996 }
997 break;
998
999 case LVN_ITEMCHANGED:
1000 {
1001 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1002
1003 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1004 {
1005 /* Check if this is a valid item
1006 * (technically, it can be also an unselect) */
1007 INT ItemIndex = pnic->iItem;
1008 if (ItemIndex == -1 ||
1009 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1010 {
1011 break;
1012 }
1013
1014 /* Check if the focus has been moved to another item */
1015 if ((pnic->uChanged & LVIF_STATE) &&
1016 (pnic->uNewState & LVIS_FOCUSED) &&
1017 !(pnic->uOldState & LVIS_FOCUSED))
1018 {
1019 if (IS_INSTALLED_ENUM(SelectedEnumType))
1020 ShowInstalledAppInfo(ItemIndex);
1021 if (IS_AVAILABLE_ENUM(SelectedEnumType))
1022 CAvailableAppView::ShowAvailableAppInfo(ItemIndex);
1023 }
1024 /* Check if the item is checked */
1025 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1026 {
1027 BOOL checked = ListView_GetCheckState(pnic->hdr.hwndFrom, pnic->iItem);
1028 nSelectedApps += (checked) ? 1 : -1;
1029 UpdateStatusBarText();
1030 }
1031 }
1032 }
1033 break;
1034
1035 case LVN_COLUMNCLICK:
1036 {
1037 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1038
1039 m_ListView->ColumnClick(pnmv);
1040 }
1041 break;
1042
1043 case NM_CLICK:
1044 {
1045 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1046 {
1047 if (IS_INSTALLED_ENUM(SelectedEnumType))
1048 ShowInstalledAppInfo(-1);
1049 if (IS_AVAILABLE_ENUM(SelectedEnumType))
1050 CAvailableAppView::ShowAvailableAppInfo(-1);
1051 }
1052 }
1053 break;
1054
1055 case NM_DBLCLK:
1056 {
1057 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1058 {
1059 /* this won't do anything if the program is already installed */
1060 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1061 }
1062 }
1063 break;
1064
1065 case NM_RCLICK:
1066 {
1067 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1068 {
1069 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1070 }
1071 }
1072 break;
1073
1074 case EN_LINK:
1075 OnLink((ENLINK*) lParam);
1076 break;
1077
1078 case TTN_GETDISPINFO:
1079 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1080 break;
1081 }
1082 }
1083 break;
1084
1085 case WM_SIZE:
1086 OnSize(hwnd, wParam, lParam);
1087 break;
1088
1089 case WM_SIZING:
1090 {
1091 LPRECT pRect = (LPRECT) lParam;
1092
1093 if (pRect->right - pRect->left < 565)
1094 pRect->right = pRect->left + 565;
1095
1096 if (pRect->bottom - pRect->top < 300)
1097 pRect->bottom = pRect->top + 300;
1098
1099 return TRUE;
1100 }
1101
1102 case WM_SYSCOLORCHANGE:
1103 {
1104 /* Forward WM_SYSCOLORCHANGE to common controls */
1105 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1106 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1107 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1108 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1109 }
1110 break;
1111
1112 case WM_TIMER:
1113 if (wParam == SEARCH_TIMER_ID)
1114 {
1115 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1116 if (bSearchEnabled)
1117 UpdateApplicationsList(-1);
1118 }
1119 break;
1120 }
1121
1122 return FALSE;
1123 }
1124
1125 virtual VOID OnLink(ENLINK *Link)
1126 {
1127 switch (Link->msg)
1128 {
1129 case WM_LBUTTONUP:
1130 case WM_RBUTTONUP:
1131 {
1132 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1133
1134 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1135 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1136 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1137 if (!pLink)
1138 {
1139 /* TODO: Error message */
1140 return;
1141 }
1142
1143 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1144 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1145
1146 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1147 }
1148 break;
1149 }
1150 }
1151
1152 BOOL IsSelectedNodeInstalled()
1153 {
1154 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1155 TV_ITEM tItem;
1156
1157 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1158 tItem.hItem = hSelectedItem;
1159 m_TreeView->GetItem(&tItem);
1160 switch (tItem.lParam)
1161 {
1162 case IDS_INSTALLED:
1163 case IDS_APPLICATIONS:
1164 case IDS_UPDATES:
1165 return TRUE;
1166 default:
1167 return FALSE;
1168 }
1169 }
1170
1171 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1172 {
1173 WORD wCommand = LOWORD(wParam);
1174
1175 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1176 {
1177 ATL::CStringW szBuf;
1178
1179 switch (HIWORD(wParam))
1180 {
1181 case EN_SETFOCUS:
1182 {
1183 ATL::CStringW szWndText;
1184
1185 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1186 m_SearchBar->GetWindowTextW(szWndText);
1187 if (szBuf == szWndText)
1188 {
1189 bSearchEnabled = FALSE;
1190 m_SearchBar->SetWindowTextW(L"");
1191 }
1192 }
1193 break;
1194
1195 case EN_KILLFOCUS:
1196 {
1197 m_SearchBar->GetWindowTextW(szBuf);
1198 if (szBuf.IsEmpty())
1199 {
1200 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1201 bSearchEnabled = FALSE;
1202 m_SearchBar->SetWindowTextW(szBuf.GetString());
1203 }
1204 }
1205 break;
1206
1207 case EN_CHANGE:
1208 {
1209 ATL::CStringW szWndText;
1210
1211 if (!bSearchEnabled)
1212 {
1213 bSearchEnabled = TRUE;
1214 break;
1215 }
1216
1217 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1218 m_SearchBar->GetWindowTextW(szWndText);
1219 if (szBuf == szWndText)
1220 {
1221 szSearchPattern.Empty();
1222 }
1223 else
1224 {
1225 szSearchPattern = szWndText;
1226 }
1227
1228 DWORD dwDelay;
1229 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1230 SetTimer(SEARCH_TIMER_ID, dwDelay);
1231 }
1232 break;
1233 }
1234
1235 return;
1236 }
1237
1238 switch (wCommand)
1239 {
1240 case ID_OPEN_LINK:
1241 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1242 HeapFree(GetProcessHeap(), 0, pLink);
1243 break;
1244
1245 case ID_COPY_LINK:
1246 CopyTextToClipboard(pLink);
1247 HeapFree(GetProcessHeap(), 0, pLink);
1248 break;
1249
1250 case ID_SETTINGS:
1251 CreateSettingsDlg(m_hWnd);
1252 break;
1253
1254 case ID_EXIT:
1255 PostMessageW(WM_CLOSE, 0, 0);
1256 break;
1257
1258 case ID_INSTALL:
1259 if (nSelectedApps)
1260 {
1261 DownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems());
1262 UpdateApplicationsList(-1);
1263 }
1264 else if(DownloadManager::DownloadApplication((PAPPLICATION_INFO) m_ListView->GetSelectionMark()))
1265 {
1266 UpdateApplicationsList(-1);
1267 }
1268
1269 break;
1270
1271 case ID_UNINSTALL:
1272 if (UninstallApplication(-1, FALSE))
1273 UpdateApplicationsList(-1);
1274 break;
1275
1276 case ID_MODIFY:
1277 if (UninstallApplication(-1, TRUE))
1278 UpdateApplicationsList(-1);
1279 break;
1280
1281 case ID_REGREMOVE:
1282 RemoveAppFromRegistry(-1);
1283 break;
1284
1285 case ID_REFRESH:
1286 UpdateApplicationsList(-1);
1287 break;
1288
1289 case ID_RESETDB:
1290 m_AvailableApps.UpdateAppsDB();
1291 UpdateApplicationsList(-1);
1292 break;
1293
1294 case ID_HELP:
1295 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1296 break;
1297
1298 case ID_ABOUT:
1299 ShowAboutDialog();
1300 break;
1301
1302 case ID_CHECK_ALL:
1303 m_ListView->CheckAll();
1304 break;
1305 }
1306 }
1307
1308 VOID FreeInstalledAppList()
1309 {
1310 INT Count = m_ListView->GetItemCount() - 1;
1311 PINSTALLED_INFO Info;
1312
1313 while (Count >= 0)
1314 {
1315 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1316 if (Info)
1317 {
1318 RegCloseKey(Info->hSubKey);
1319 delete Info;
1320 }
1321 Count--;
1322 }
1323 }
1324
1325 static BOOL SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
1326 {
1327 if (!*szNeedle)
1328 return TRUE;
1329 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1330 return StrStrIW(szHaystack, szNeedle) != NULL;
1331 }
1332
1333 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, LPWSTR lpName, PINSTALLED_INFO Info)
1334 {
1335 PINSTALLED_INFO ItemInfo;
1336 ATL::CStringW szText;
1337 INT Index;
1338
1339 if (!SearchPatternMatch(lpName, szSearchPattern))
1340 {
1341 RegCloseKey(Info->hSubKey);
1342 return TRUE;
1343 }
1344
1345 ItemInfo = (PINSTALLED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(INSTALLED_INFO));
1346 if (!ItemInfo)
1347 {
1348 RegCloseKey(Info->hSubKey);
1349 return FALSE;
1350 }
1351
1352 RtlCopyMemory(ItemInfo, Info, sizeof(INSTALLED_INFO));
1353
1354 Index = ListViewAddItem(ItemIndex, 0, lpName, (LPARAM) ItemInfo);
1355
1356 /* Get version info */
1357 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
1358 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(szText.GetString()));
1359
1360 /* Get comments */
1361 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
1362 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(szText.GetString()));
1363
1364 return TRUE;
1365 }
1366
1367 static BOOL CALLBACK s_EnumAvailableAppProc(PAPPLICATION_INFO Info, LPCWSTR szFolderPath)
1368 {
1369 INT Index;
1370 HICON hIcon = NULL;
1371
1372 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1373
1374 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
1375 !SearchPatternMatch(Info->szDesc, szSearchPattern))
1376 {
1377 return TRUE;
1378 }
1379
1380 /* Load icon from file */
1381 ATL::CStringW szIconPath;
1382 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->szName);
1383 hIcon = (HICON) LoadImageW(NULL,
1384 szIconPath.GetString(),
1385 IMAGE_ICON,
1386 LISTVIEW_ICON_SIZE,
1387 LISTVIEW_ICON_SIZE,
1388 LR_LOADFROMFILE);
1389
1390 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1391 {
1392 /* Load default icon */
1393 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1394 }
1395
1396 Index = ImageList_AddIcon(hImageListView, hIcon);
1397 DestroyIcon(hIcon);
1398
1399 Index = ListViewAddItem(Info->Category, Index, Info->szName, (LPARAM) Info);
1400 ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1401
1402 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(Info->szVersion.GetString()));
1403 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(Info->szDesc.GetString()));
1404
1405 return TRUE;
1406 }
1407
1408 VOID UpdateStatusBarText()
1409 {
1410 if (m_StatusBar)
1411 {
1412 ATL::CStringW szBuffer;
1413
1414 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1415 m_StatusBar->SetText(szBuffer);
1416 }
1417 }
1418
1419 VOID UpdateApplicationsList(INT EnumType)
1420 {
1421 ATL::CStringW szBuffer1, szBuffer2;
1422 HIMAGELIST hImageListView;
1423 bUpdating = TRUE;
1424
1425 m_ListView->SetRedraw(FALSE);
1426
1427 nSelectedApps = 0;
1428 if (EnumType < 0) EnumType = SelectedEnumType;
1429
1430 if (IS_INSTALLED_ENUM(SelectedEnumType))
1431 FreeInstalledAppList();
1432
1433 m_ListView->DeleteAllItems();
1434
1435 /* Create new ImageList */
1436 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1437 LISTVIEW_ICON_SIZE,
1438 GetSystemColorDepth() | ILC_MASK,
1439 0, 1);
1440 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1441 if (hImageListBuf)
1442 {
1443 ImageList_Destroy(hImageListBuf);
1444 }
1445
1446 if (IS_AVAILABLE_ENUM(EnumType))
1447 {
1448 /* Enum available applications */
1449 m_AvailableApps.EnumAvailableApplications(EnumType, s_EnumAvailableAppProc);
1450 }
1451
1452 SelectedEnumType = EnumType;
1453
1454 UpdateStatusBarText();
1455
1456 SetWelcomeText();
1457
1458 /* set automatic column width for program names if the list is not empty */
1459 if (m_ListView->GetItemCount() > 0)
1460 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1461
1462 bUpdating = FALSE;
1463 m_ListView->SetRedraw(TRUE);
1464 }
1465
1466 public:
1467 static ATL::CWndClassInfo& GetWndClassInfo()
1468 {
1469 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1470 static ATL::CWndClassInfo wc =
1471 {
1472 {
1473 sizeof(WNDCLASSEX),
1474 csStyle,
1475 StartWindowProc,
1476 0,
1477 0,
1478 NULL,
1479 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1480 LoadCursorW(NULL, IDC_ARROW),
1481 (HBRUSH) (COLOR_BTNFACE + 1),
1482 MAKEINTRESOURCEW(IDR_MAINMENU),
1483 L"RAppsWnd",
1484 NULL
1485 },
1486 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1487 };
1488 return wc;
1489 }
1490
1491 HWND Create()
1492 {
1493 ATL::CStringW szWindowName;
1494 szWindowName.LoadStringW(hInst, IDS_APPTITLE);
1495
1496 RECT r = {
1497 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1498 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1499 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1500 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1501 };
1502 r.right += r.left;
1503 r.bottom += r.top;
1504
1505 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1506 }
1507
1508 CStatusBar * GetStatusBar()
1509 {
1510 return m_StatusBar;
1511 }
1512
1513 CAppsListView * GetListView()
1514 {
1515 return m_ListView;
1516 }
1517
1518 CRichEdit * GetRichEdit()
1519 {
1520 return m_RichEdit;
1521 }
1522
1523 CAvailableApps * GetAvailableApps()
1524 {
1525 return &m_AvailableApps;
1526 }
1527 };
1528
1529 // File interface
1530
1531 CMainWindow * g_MainWindow;
1532
1533 HWND CreateMainWindow()
1534 {
1535 g_MainWindow = new CMainWindow();
1536 return g_MainWindow->Create();
1537 }
1538
1539 DWORD_PTR ListViewGetlParam(INT item)
1540 {
1541 if (item < 0)
1542 {
1543 item = g_MainWindow->GetListView()->GetSelectionMark();
1544 }
1545 return g_MainWindow->GetListView()->GetItemData(item);
1546 }
1547
1548 VOID SetStatusBarText(LPCWSTR szText)
1549 {
1550 g_MainWindow->GetStatusBar()->SetText(szText);
1551 }
1552
1553 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1554 {
1555 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1556 }
1557
1558 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1559 {
1560 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1561 }
1562
1563 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1564 {
1565 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1566 }
1567
1568 /* ATL version of functions */
1569 VOID SetStatusBarText(const ATL::CStringW& szText)
1570 {
1571 SetStatusBarText(szText.GetString());
1572 }
1573
1574 INT ListViewAddItem(INT ItemIndex, INT IconIndex, ATL::CStringW & Name, LPARAM lParam)
1575 {
1576 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1577 }
1578
1579 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1580 {
1581 NewRichEditText(szText.GetString(), flags);
1582 }
1583
1584 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1585 {
1586 InsertRichEditText(szText.GetString(), flags);
1587 }
1588
1589 CAvailableApps* GetAvailableApps()
1590 {
1591 return g_MainWindow->GetAvailableApps();
1592 }