[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()
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 /* FIXME: HAX!
1063 - preventing decremention below zero as a safeguard for ReactOS
1064 In ReactOS this action is triggered whenever user changes *selection*, but should be only when *checkbox* state toggled
1065 Maybe LVIS_STATEIMAGEMASK is set incorrectly
1066 */
1067 nSelectedApps +=
1068 (checked)
1069 ? 1
1070 :((nSelectedApps > 0)
1071 ? -1
1072 : 0);
1073 UpdateStatusBarText();
1074 }
1075 }
1076 }
1077 break;
1078
1079 case LVN_COLUMNCLICK:
1080 {
1081 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1082
1083 m_ListView->ColumnClick(pnmv);
1084 }
1085 break;
1086
1087 case NM_CLICK:
1088 {
1089 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1090 {
1091 if (IS_INSTALLED_ENUM(SelectedEnumType))
1092 ShowInstalledAppInfo(-1);
1093 if (isAvailableEnum(SelectedEnumType))
1094 CAvailableAppView::ShowAvailableAppInfo(-1);
1095 }
1096 }
1097 break;
1098
1099 case NM_DBLCLK:
1100 {
1101 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1102 {
1103 /* this won't do anything if the program is already installed */
1104 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1105 }
1106 }
1107 break;
1108
1109 case NM_RCLICK:
1110 {
1111 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1112 {
1113 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1114 }
1115 }
1116 break;
1117
1118 case EN_LINK:
1119 OnLink((ENLINK*) lParam);
1120 break;
1121
1122 case TTN_GETDISPINFO:
1123 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1124 break;
1125 }
1126 }
1127 break;
1128
1129 case WM_SIZE:
1130 OnSize(hwnd, wParam, lParam);
1131 break;
1132
1133 case WM_SIZING:
1134 {
1135 LPRECT pRect = (LPRECT) lParam;
1136
1137 if (pRect->right - pRect->left < 565)
1138 pRect->right = pRect->left + 565;
1139
1140 if (pRect->bottom - pRect->top < 300)
1141 pRect->bottom = pRect->top + 300;
1142
1143 return TRUE;
1144 }
1145
1146 case WM_SYSCOLORCHANGE:
1147 {
1148 /* Forward WM_SYSCOLORCHANGE to common controls */
1149 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1150 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1151 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1152 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1153 }
1154 break;
1155
1156 case WM_TIMER:
1157 if (wParam == SEARCH_TIMER_ID)
1158 {
1159 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1160 if (bSearchEnabled)
1161 UpdateApplicationsList(-1);
1162 }
1163 break;
1164 }
1165
1166 return FALSE;
1167 }
1168
1169 virtual VOID OnLink(ENLINK *Link)
1170 {
1171 switch (Link->msg)
1172 {
1173 case WM_LBUTTONUP:
1174 case WM_RBUTTONUP:
1175 {
1176 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1177
1178 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1179 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1180 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1181 if (!pLink)
1182 {
1183 /* TODO: Error message */
1184 return;
1185 }
1186
1187 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1188 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1189
1190 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1191 }
1192 break;
1193 }
1194 }
1195
1196 BOOL IsSelectedNodeInstalled()
1197 {
1198 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1199 TV_ITEM tItem;
1200
1201 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1202 tItem.hItem = hSelectedItem;
1203 m_TreeView->GetItem(&tItem);
1204 switch (tItem.lParam)
1205 {
1206 case IDS_INSTALLED:
1207 case IDS_APPLICATIONS:
1208 case IDS_UPDATES:
1209 return TRUE;
1210 default:
1211 return FALSE;
1212 }
1213 }
1214
1215 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1216 {
1217 WORD wCommand = LOWORD(wParam);
1218
1219 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1220 {
1221 ATL::CStringW szBuf;
1222
1223 switch (HIWORD(wParam))
1224 {
1225 case EN_SETFOCUS:
1226 {
1227 ATL::CStringW szWndText;
1228
1229 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1230 m_SearchBar->GetWindowTextW(szWndText);
1231 if (szBuf == szWndText)
1232 {
1233 bSearchEnabled = FALSE;
1234 m_SearchBar->SetWindowTextW(L"");
1235 }
1236 }
1237 break;
1238
1239 case EN_KILLFOCUS:
1240 {
1241 m_SearchBar->GetWindowTextW(szBuf);
1242 if (szBuf.IsEmpty())
1243 {
1244 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1245 bSearchEnabled = FALSE;
1246 m_SearchBar->SetWindowTextW(szBuf.GetString());
1247 }
1248 }
1249 break;
1250
1251 case EN_CHANGE:
1252 {
1253 ATL::CStringW szWndText;
1254
1255 if (!bSearchEnabled)
1256 {
1257 bSearchEnabled = TRUE;
1258 break;
1259 }
1260
1261 szBuf.LoadStringW(hInst, IDS_SEARCH_TEXT);
1262 m_SearchBar->GetWindowTextW(szWndText);
1263 if (szBuf == szWndText)
1264 {
1265 szSearchPattern.Empty();
1266 }
1267 else
1268 {
1269 szSearchPattern = szWndText;
1270 }
1271
1272 DWORD dwDelay;
1273 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1274 SetTimer(SEARCH_TIMER_ID, dwDelay);
1275 }
1276 break;
1277 }
1278
1279 return;
1280 }
1281
1282 switch (wCommand)
1283 {
1284 case ID_OPEN_LINK:
1285 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1286 HeapFree(GetProcessHeap(), 0, pLink);
1287 break;
1288
1289 case ID_COPY_LINK:
1290 CopyTextToClipboard(pLink);
1291 HeapFree(GetProcessHeap(), 0, pLink);
1292 break;
1293
1294 case ID_SETTINGS:
1295 CreateSettingsDlg(m_hWnd);
1296 break;
1297
1298 case ID_EXIT:
1299 PostMessageW(WM_CLOSE, 0, 0);
1300 break;
1301
1302 case ID_INSTALL:
1303 if (nSelectedApps > 0)
1304 {
1305 CDownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems());
1306 UpdateApplicationsList(-1);
1307 }
1308 else if(CDownloadManager::DownloadApplication(m_ListView->GetSelectedData()))
1309 {
1310 UpdateApplicationsList(-1);
1311 }
1312
1313 break;
1314
1315 case ID_UNINSTALL:
1316 if (UninstallApplication(-1, FALSE))
1317 UpdateApplicationsList(-1);
1318 break;
1319
1320 case ID_MODIFY:
1321 if (UninstallApplication(-1, TRUE))
1322 UpdateApplicationsList(-1);
1323 break;
1324
1325 case ID_REGREMOVE:
1326 RemoveAppFromRegistry(-1);
1327 break;
1328
1329 case ID_REFRESH:
1330 UpdateApplicationsList(-1);
1331 break;
1332
1333 case ID_RESETDB:
1334 CAvailableApps::ForceUpdateAppsDB();
1335 UpdateApplicationsList(-1);
1336 break;
1337
1338 case ID_HELP:
1339 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1340 break;
1341
1342 case ID_ABOUT:
1343 ShowAboutDialog();
1344 break;
1345
1346 case ID_CHECK_ALL:
1347 m_ListView->CheckAll();
1348 break;
1349 }
1350 }
1351
1352 VOID FreeInstalledAppList()
1353 {
1354 INT Count = m_ListView->GetItemCount() - 1;
1355 PINSTALLED_INFO Info;
1356
1357 while (Count >= 0)
1358 {
1359 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1360 if (Info)
1361 {
1362 RegCloseKey(Info->hSubKey);
1363 delete Info;
1364 }
1365 Count--;
1366 }
1367 }
1368
1369 static BOOL SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
1370 {
1371 if (!*szNeedle)
1372 return TRUE;
1373 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1374 return StrStrIW(szHaystack, szNeedle) != NULL;
1375 }
1376
1377 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, LPWSTR lpName, PINSTALLED_INFO Info)
1378 {
1379 PINSTALLED_INFO ItemInfo;
1380 ATL::CStringW szText;
1381 INT Index;
1382
1383 if (!SearchPatternMatch(lpName, szSearchPattern))
1384 {
1385 RegCloseKey(Info->hSubKey);
1386 return TRUE;
1387 }
1388
1389 ItemInfo = (PINSTALLED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(INSTALLED_INFO));
1390 if (!ItemInfo)
1391 {
1392 RegCloseKey(Info->hSubKey);
1393 return FALSE;
1394 }
1395
1396 RtlCopyMemory(ItemInfo, Info, sizeof(INSTALLED_INFO));
1397
1398 Index = ListViewAddItem(ItemIndex, 0, lpName, (LPARAM) ItemInfo);
1399
1400 /* Get version info */
1401 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
1402 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(szText.GetString()));
1403
1404 /* Get comments */
1405 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
1406 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(szText.GetString()));
1407
1408 return TRUE;
1409 }
1410
1411 static BOOL CALLBACK s_EnumAvailableAppProc(PAPPLICATION_INFO Info, LPCWSTR szFolderPath)
1412 {
1413 INT Index;
1414 HICON hIcon = NULL;
1415
1416 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1417
1418 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
1419 !SearchPatternMatch(Info->szDesc, szSearchPattern))
1420 {
1421 return TRUE;
1422 }
1423
1424 /* Load icon from file */
1425 ATL::CStringW szIconPath;
1426 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->szName);
1427 hIcon = (HICON) LoadImageW(NULL,
1428 szIconPath.GetString(),
1429 IMAGE_ICON,
1430 LISTVIEW_ICON_SIZE,
1431 LISTVIEW_ICON_SIZE,
1432 LR_LOADFROMFILE);
1433
1434 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1435 {
1436 /* Load default icon */
1437 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1438 }
1439
1440 Index = ImageList_AddIcon(hImageListView, hIcon);
1441 DestroyIcon(hIcon);
1442
1443 Index = ListViewAddItem(Info->Category, Index, Info->szName, (LPARAM) Info);
1444 ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1445
1446 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(Info->szVersion.GetString()));
1447 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(Info->szDesc.GetString()));
1448
1449 return TRUE;
1450 }
1451
1452 VOID UpdateStatusBarText()
1453 {
1454 if (m_StatusBar)
1455 {
1456 ATL::CStringW szBuffer;
1457
1458 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1459 m_StatusBar->SetText(szBuffer);
1460 }
1461 }
1462
1463 VOID UpdateApplicationsList(INT EnumType)
1464 {
1465 ATL::CStringW szBuffer1, szBuffer2;
1466 HIMAGELIST hImageListView;
1467 bUpdating = TRUE;
1468
1469 m_ListView->SetRedraw(FALSE);
1470
1471 nSelectedApps = 0;
1472 if (EnumType < 0) EnumType = SelectedEnumType;
1473
1474 if (IS_INSTALLED_ENUM(EnumType))
1475 {
1476 FreeInstalledAppList();
1477 }
1478
1479 m_ListView->DeleteAllItems();
1480
1481 /* Create new ImageList */
1482 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1483 LISTVIEW_ICON_SIZE,
1484 GetSystemColorDepth() | ILC_MASK,
1485 0, 1);
1486 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1487 if (hImageListBuf)
1488 {
1489 ImageList_Destroy(hImageListBuf);
1490 }
1491
1492 if (isAvailableEnum(EnumType))
1493 {
1494 /* Enum available applications */
1495 if (!m_AvailableApps.EnumAvailableApplications(EnumType, s_EnumAvailableAppProc))
1496 {
1497 return;
1498 }
1499 }
1500
1501 SelectedEnumType = EnumType;
1502 UpdateStatusBarText();
1503 SetWelcomeText();
1504
1505 /* Set automatic column width for program names if the list is not empty */
1506 if (m_ListView->GetItemCount() > 0)
1507 {
1508 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1509 }
1510
1511 bUpdating = FALSE;
1512 m_ListView->SetRedraw(TRUE);
1513 }
1514
1515 public:
1516 static ATL::CWndClassInfo& GetWndClassInfo()
1517 {
1518 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1519 static ATL::CWndClassInfo wc =
1520 {
1521 {
1522 sizeof(WNDCLASSEX),
1523 csStyle,
1524 StartWindowProc,
1525 0,
1526 0,
1527 NULL,
1528 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1529 LoadCursorW(NULL, IDC_ARROW),
1530 (HBRUSH) (COLOR_BTNFACE + 1),
1531 MAKEINTRESOURCEW(IDR_MAINMENU),
1532 L"RAppsWnd",
1533 NULL
1534 },
1535 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1536 };
1537 return wc;
1538 }
1539
1540 HWND Create()
1541 {
1542 ATL::CStringW szWindowName;
1543 szWindowName.LoadStringW(hInst, IDS_APPTITLE);
1544
1545 RECT r = {
1546 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1547 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1548 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1549 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1550 };
1551 r.right += r.left;
1552 r.bottom += r.top;
1553
1554 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1555 }
1556
1557 CStatusBar * GetStatusBar()
1558 {
1559 return m_StatusBar;
1560 }
1561
1562 CAppsListView * GetListView()
1563 {
1564 return m_ListView;
1565 }
1566
1567 CRichEdit * GetRichEdit()
1568 {
1569 return m_RichEdit;
1570 }
1571
1572 CAvailableApps * GetAvailableApps()
1573 {
1574 return &m_AvailableApps;
1575 }
1576 };
1577
1578 // File interface
1579
1580 CMainWindow * g_MainWindow;
1581
1582 HWND CreateMainWindow()
1583 {
1584 g_MainWindow = new CMainWindow();
1585 return g_MainWindow->Create();
1586 }
1587
1588 DWORD_PTR ListViewGetlParam(INT item)
1589 {
1590 if (item < 0)
1591 {
1592 item = g_MainWindow->GetListView()->GetSelectionMark();
1593 }
1594 return g_MainWindow->GetListView()->GetItemData(item);
1595 }
1596
1597 VOID SetStatusBarText(LPCWSTR szText)
1598 {
1599 g_MainWindow->GetStatusBar()->SetText(szText);
1600 }
1601
1602 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1603 {
1604 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1605 }
1606
1607 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1608 {
1609 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1610 }
1611
1612 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1613 {
1614 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1615 }
1616
1617 /* ATL version of functions */
1618 VOID SetStatusBarText(const ATL::CStringW& szText)
1619 {
1620 SetStatusBarText(szText.GetString());
1621 }
1622
1623 INT ListViewAddItem(INT ItemIndex, INT IconIndex, ATL::CStringW & Name, LPARAM lParam)
1624 {
1625 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1626 }
1627
1628 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1629 {
1630 NewRichEditText(szText.GetString(), flags);
1631 }
1632
1633 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1634 {
1635 InsertRichEditText(szText.GetString(), flags);
1636 }
1637
1638 CAvailableApps* GetAvailableApps()
1639 {
1640 return g_MainWindow->GetAvailableApps();
1641 }