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