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