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