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