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