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