[RAPPS] Fixed multiple redraws of the apps list
[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(FALSE)
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 if(SearchEnabled)
1072 UpdateApplicationsList(-1);
1073 }
1074 break;
1075 }
1076
1077 return FALSE;
1078 }
1079
1080 virtual VOID OnLink(ENLINK *Link)
1081 {
1082 switch (Link->msg)
1083 {
1084 case WM_LBUTTONUP:
1085 case WM_RBUTTONUP:
1086 {
1087 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1088
1089 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1090 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1091 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1092 if (!pLink)
1093 {
1094 /* TODO: Error message */
1095 return;
1096 }
1097
1098 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1099 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1100
1101 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1102 }
1103 break;
1104 }
1105 }
1106
1107 BOOL IsSelectedNodeInstalled(void)
1108 {
1109 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1110 TV_ITEM tItem;
1111
1112 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1113 tItem.hItem = hSelectedItem;
1114 m_TreeView->GetItem(&tItem);
1115 switch (tItem.lParam)
1116 {
1117 case IDS_INSTALLED:
1118 case IDS_APPLICATIONS:
1119 case IDS_UPDATES:
1120 return TRUE;
1121 default:
1122 return FALSE;
1123 }
1124 }
1125
1126 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1127 {
1128 WORD wCommand = LOWORD(wParam);
1129
1130 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1131 {
1132 ATL::CStringW szBuf;
1133
1134 switch (HIWORD(wParam))
1135 {
1136 case EN_SETFOCUS:
1137 {
1138 ATL::CStringW szWndText;
1139
1140 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1141 m_SearchBar->GetWindowTextW(szWndText);
1142 if (szBuf == szWndText)
1143 {
1144 SearchEnabled = FALSE;
1145 m_SearchBar->SetWindowTextW(L"");
1146 }
1147 }
1148 break;
1149
1150 case EN_KILLFOCUS:
1151 {
1152 m_SearchBar->GetWindowTextW(szBuf);
1153 if (szBuf.IsEmpty())
1154 {
1155 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1156 SearchEnabled = FALSE;
1157 m_SearchBar->SetWindowTextW(szBuf.GetString());
1158 }
1159 }
1160 break;
1161
1162 case EN_CHANGE:
1163 {
1164 ATL::CStringW szWndText;
1165
1166 if (!SearchEnabled)
1167 {
1168 SearchEnabled = TRUE;
1169 break;
1170 }
1171
1172 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1173 m_SearchBar->GetWindowTextW(szWndText);
1174 if (szBuf == szWndText)
1175 {
1176 szSearchPattern.Empty();
1177 }
1178 else
1179 {
1180 szSearchPattern = szWndText;
1181 }
1182
1183 DWORD dwDelay;
1184 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1185 SetTimer(SEARCH_TIMER_ID, dwDelay);
1186 }
1187 break;
1188 }
1189
1190 return;
1191 }
1192
1193 switch (wCommand)
1194 {
1195 case ID_OPEN_LINK:
1196 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1197 HeapFree(GetProcessHeap(), 0, pLink);
1198 break;
1199
1200 case ID_COPY_LINK:
1201 CopyTextToClipboard(pLink);
1202 HeapFree(GetProcessHeap(), 0, pLink);
1203 break;
1204
1205 case ID_SETTINGS:
1206 CreateSettingsDlg(m_hWnd);
1207 break;
1208
1209 case ID_EXIT:
1210 PostMessageW(WM_CLOSE, 0, 0);
1211 break;
1212
1213 case ID_INSTALL:
1214 if (DownloadApplication(-1))
1215 /* TODO: Implement install dialog
1216 * if (InstallApplication(-1))
1217 */
1218 UpdateApplicationsList(-1);
1219 break;
1220
1221 case ID_UNINSTALL:
1222 if (UninstallApplication(-1, FALSE))
1223 UpdateApplicationsList(-1);
1224 break;
1225
1226 case ID_MODIFY:
1227 if (UninstallApplication(-1, TRUE))
1228 UpdateApplicationsList(-1);
1229 break;
1230
1231 case ID_REGREMOVE:
1232 RemoveAppFromRegistry(-1);
1233 break;
1234
1235 case ID_REFRESH:
1236 UpdateApplicationsList(-1);
1237 break;
1238
1239 case ID_RESETDB:
1240 m_AvailableApps.UpdateAppsDB();
1241 UpdateApplicationsList(-1);
1242 break;
1243
1244 case ID_HELP:
1245 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1246 break;
1247
1248 case ID_ABOUT:
1249 ShowAboutDialog();
1250 break;
1251 }
1252 }
1253
1254 VOID FreeInstalledAppList(VOID)
1255 {
1256 INT Count = ListView_GetItemCount(hListView) - 1;
1257 PINSTALLED_INFO Info;
1258
1259 while (Count >= 0)
1260 {
1261 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1262 if (Info)
1263 {
1264 RegCloseKey(Info->hSubKey);
1265 delete Info;
1266 }
1267 Count--;
1268 }
1269 }
1270
1271 static BOOL SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
1272 {
1273 if (!*szNeedle)
1274 return TRUE;
1275 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1276 return StrStrIW(szHaystack, szNeedle) != NULL;
1277 }
1278
1279 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, LPWSTR lpName, PINSTALLED_INFO Info)
1280 {
1281 PINSTALLED_INFO ItemInfo;
1282 ATL::CStringW szText;
1283 INT Index;
1284
1285 if (!SearchPatternMatch(lpName, szSearchPattern))
1286 {
1287 RegCloseKey(Info->hSubKey);
1288 return TRUE;
1289 }
1290
1291 ItemInfo = (PINSTALLED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(INSTALLED_INFO));
1292 if (!ItemInfo)
1293 {
1294 RegCloseKey(Info->hSubKey);
1295 return FALSE;
1296 }
1297
1298 RtlCopyMemory(ItemInfo, Info, sizeof(INSTALLED_INFO));
1299
1300 Index = ListViewAddItem(ItemIndex, 0, lpName, (LPARAM) ItemInfo);
1301
1302 /* Get version info */
1303 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
1304 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(szText.GetString()));
1305
1306 /* Get comments */
1307 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
1308 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(szText.GetString()));
1309
1310 return TRUE;
1311 }
1312
1313 static BOOL CALLBACK s_EnumAvailableAppProc(PAPPLICATION_INFO Info, LPCWSTR szFolderPath)
1314 {
1315 INT Index;
1316 HICON hIcon = NULL;
1317
1318 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1319
1320 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
1321 !SearchPatternMatch(Info->szDesc, szSearchPattern))
1322 {
1323 return TRUE;
1324 }
1325
1326 /* Load icon from file */
1327 ATL::CStringW szIconPath;
1328 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->szName);
1329 hIcon = (HICON) LoadImageW(NULL,
1330 szIconPath.GetString(),
1331 IMAGE_ICON,
1332 LISTVIEW_ICON_SIZE,
1333 LISTVIEW_ICON_SIZE,
1334 LR_LOADFROMFILE);
1335
1336 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1337 {
1338 /* Load default icon */
1339 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1340 }
1341
1342 Index = ImageList_AddIcon(hImageListView, hIcon);
1343 DestroyIcon(hIcon);
1344
1345 Index = ListViewAddItem(Info->Category, Index, Info->szName, (LPARAM) Info);
1346 ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1347
1348 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(Info->szVersion.GetString()));
1349 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(Info->szDesc.GetString()));
1350
1351 return TRUE;
1352 }
1353
1354
1355 VOID UpdateApplicationsList(INT EnumType)
1356 {
1357 ATL::CStringW szBuffer1, szBuffer2;
1358 HIMAGELIST hImageListView;
1359
1360 m_ListView->SendMessageW(WM_SETREDRAW, FALSE, 0);
1361
1362 if (EnumType < 0) EnumType = SelectedEnumType;
1363
1364 if (IS_INSTALLED_ENUM(SelectedEnumType))
1365 FreeInstalledAppList();
1366
1367 (VOID) ListView_DeleteAllItems(hListView);
1368
1369 /* Create new ImageList */
1370 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1371 LISTVIEW_ICON_SIZE,
1372 GetSystemColorDepth() | ILC_MASK,
1373 0, 1);
1374 HIMAGELIST hImageListBuf = ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1375 if (hImageListBuf)
1376 {
1377 ImageList_Destroy(hImageListBuf);
1378 }
1379
1380
1381 if (IS_AVAILABLE_ENUM(EnumType))
1382 {
1383 /* Enum available applications */
1384 m_AvailableApps.EnumAvailableApplications(EnumType, s_EnumAvailableAppProc);
1385 }
1386
1387 SelectedEnumType = EnumType;
1388
1389 szBuffer2.LoadStringW(hInst, IDS_APPS_COUNT);
1390 szBuffer1.Format(szBuffer2, ListView_GetItemCount(hListView));
1391 SetStatusBarText(szBuffer1);
1392
1393 SetWelcomeText();
1394
1395 /* set automatic column width for program names if the list is not empty */
1396 if (ListView_GetItemCount(hListView) > 0)
1397 ListView_SetColumnWidth(hListView, 0, LVSCW_AUTOSIZE);
1398
1399 SendMessageW(hListView, WM_SETREDRAW, TRUE, 0);
1400 }
1401
1402 public:
1403 static ATL::CWndClassInfo& GetWndClassInfo()
1404 {
1405 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1406 static ATL::CWndClassInfo wc =
1407 {
1408 {
1409 sizeof(WNDCLASSEX),
1410 csStyle,
1411 StartWindowProc,
1412 0,
1413 0,
1414 NULL,
1415 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1416 LoadCursorW(NULL, IDC_ARROW),
1417 (HBRUSH) (COLOR_BTNFACE + 1),
1418 MAKEINTRESOURCEW(IDR_MAINMENU),
1419 L"RAppsWnd",
1420 NULL
1421 },
1422 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1423 };
1424 return wc;
1425 }
1426
1427 HWND Create()
1428 {
1429 ATL::CStringW szWindowName;
1430 szWindowName.LoadStringW(hInst, IDS_APPTITLE);
1431
1432 RECT r = {
1433 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1434 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1435 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1436 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1437 };
1438 r.right += r.left;
1439 r.bottom += r.top;
1440
1441 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1442 }
1443
1444 CStatusBar * GetStatusBar()
1445 {
1446 return m_StatusBar;
1447 }
1448
1449 CAppsListView * GetListView()
1450 {
1451 return m_ListView;
1452 }
1453
1454 CRichEdit * GetRichEdit()
1455 {
1456 return m_RichEdit;
1457 }
1458
1459 CAvailableApps * GetAvailableApps()
1460 {
1461 return &m_AvailableApps;
1462 }
1463 };
1464
1465 // File interface
1466
1467 CMainWindow * g_MainWindow;
1468
1469 HWND CreateMainWindow()
1470 {
1471 g_MainWindow = new CMainWindow();
1472 return g_MainWindow->Create();
1473 }
1474
1475 DWORD_PTR ListViewGetlParam(INT item)
1476 {
1477 if (item < 0)
1478 {
1479 item = g_MainWindow->GetListView()->GetSelectionMark();
1480 }
1481 return g_MainWindow->GetListView()->GetItemData(item);
1482 }
1483
1484 VOID SetStatusBarText(LPCWSTR szText)
1485 {
1486 g_MainWindow->GetStatusBar()->SetText(szText);
1487 }
1488
1489 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1490 {
1491 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1492 }
1493
1494 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1495 {
1496 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1497 }
1498
1499 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1500 {
1501 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1502 }
1503
1504 /* ATL version of functions */
1505 VOID SetStatusBarText(const ATL::CStringW& szText)
1506 {
1507 SetStatusBarText(szText.GetString());
1508 }
1509
1510 INT ListViewAddItem(INT ItemIndex, INT IconIndex, ATL::CStringW & Name, LPARAM lParam)
1511 {
1512 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1513 }
1514
1515 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1516 {
1517 NewRichEditText(szText.GetString(), flags);
1518 }
1519
1520 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1521 {
1522 InsertRichEditText(szText.GetString(), flags);
1523 }
1524
1525 CAvailableApps* GetAvailableApps()
1526 {
1527 return g_MainWindow->GetAvailableApps();
1528 }