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