e9071a6b99621914bc94b962695376f7387d1660
[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(buf, 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 hRootItem1, hRootItem2;
665
666 hRootItem1 = AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
667 AddCategory(hRootItem1, IDS_APPLICATIONS, IDI_APPS);
668 AddCategory(hRootItem1, IDS_UPDATES, IDI_APPUPD);
669
670 hRootItem2 = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
671 AddCategory(hRootItem2, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
672 AddCategory(hRootItem2, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
673 AddCategory(hRootItem2, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
674 AddCategory(hRootItem2, IDS_CAT_GAMES, IDI_CAT_GAMES);
675 AddCategory(hRootItem2, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
676 AddCategory(hRootItem2, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
677 AddCategory(hRootItem2, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
678 AddCategory(hRootItem2, IDS_CAT_EDU, IDI_CAT_EDU);
679 AddCategory(hRootItem2, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
680 AddCategory(hRootItem2, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
681 AddCategory(hRootItem2, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
682 AddCategory(hRootItem2, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
683 AddCategory(hRootItem2, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
684 AddCategory(hRootItem2, IDS_CAT_LIBS, IDI_CAT_LIBS);
685 AddCategory(hRootItem2, IDS_CAT_OTHER, IDI_CAT_OTHER);
686
687 m_TreeView->SetImageList();
688 m_TreeView->Expand(hRootItem1, TVE_EXPAND);
689 m_TreeView->Expand(hRootItem2, TVE_EXPAND);
690 m_TreeView->SelectItem(hRootItem1);
691 }
692
693 BOOL CreateStatusBar()
694 {
695 m_StatusBar = new CUiWindow<CStatusBar>();
696 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
697 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
698 m_ClientPanel->Children().Append(m_StatusBar);
699
700 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
701 }
702
703 BOOL CreateToolbar()
704 {
705 m_Toolbar = new CMainToolbar();
706 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
707 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
708 m_ClientPanel->Children().Append(m_Toolbar);
709
710 return m_Toolbar->Create(m_hWnd) != NULL;
711 }
712
713 BOOL CreateTreeView()
714 {
715 m_TreeView = new CSideTreeView();
716 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
717 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
718 m_VSplitter->First().Append(m_TreeView);
719
720 return m_TreeView->Create(m_hWnd) != NULL;
721 }
722
723 BOOL CreateListView()
724 {
725 m_ListView = new CAppsListView();
726 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
727 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
728 m_HSplitter->First().Append(m_ListView);
729
730 hListView = m_ListView->Create(m_hWnd);
731 return hListView != NULL;
732 }
733
734 BOOL CreateRichEdit()
735 {
736 m_RichEdit = new CUiWindow<CRichEdit>();
737 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
738 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
739 m_HSplitter->Second().Append(m_RichEdit);
740
741 return m_RichEdit->Create(m_hWnd) != NULL;
742 }
743
744 BOOL CreateVSplitter()
745 {
746 m_VSplitter = new CUiSplitPanel();
747 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
748 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
749 m_VSplitter->m_DynamicFirst = FALSE;
750 m_VSplitter->m_Horizontal = FALSE;
751 m_VSplitter->m_MinFirst = 240;
752 m_VSplitter->m_MinSecond = 300;
753 m_ClientPanel->Children().Append(m_VSplitter);
754
755 return m_VSplitter->Create(m_hWnd) != NULL;
756 }
757
758 BOOL CreateHSplitter()
759 {
760 m_HSplitter = new CUiSplitPanel();
761 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
762 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
763 m_HSplitter->m_DynamicFirst = TRUE;
764 m_HSplitter->m_Horizontal = TRUE;
765 m_HSplitter->m_Pos = 32768;
766 m_HSplitter->m_MinFirst = 300;
767 m_HSplitter->m_MinSecond = 150;
768 m_VSplitter->Second().Append(m_HSplitter);
769
770 return m_HSplitter->Create(m_hWnd) != NULL;
771 }
772
773 BOOL CreateSearchBar()
774 {
775 m_SearchBar = new CUiWindow<CSearchBar>();
776 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
777 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
778 m_SearchBar->m_Margin.top = 6;
779 m_SearchBar->m_Margin.right = 6;
780
781 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
782 }
783
784 BOOL CreateLayout()
785 {
786 BOOL b = TRUE;
787 bUpdating = TRUE;
788
789 m_ClientPanel = new CUiPanel();
790 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
791 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
792
793 // Top level
794 b = b && CreateStatusBar();
795 b = b && CreateToolbar();
796 b = b && CreateSearchBar();
797 b = b && CreateVSplitter();
798
799 // Inside V Splitter
800 b = b && CreateHSplitter();
801 b = b && CreateTreeView();
802
803 // Inside H Splitter
804 b = b && CreateListView();
805 b = b && CreateRichEdit();
806
807 if (b)
808 {
809 RECT rTop;
810 RECT rBottom;
811
812 /* Size status bar */
813 m_StatusBar->SendMessageW(WM_SIZE, 0, 0);
814
815 /* Size tool bar */
816 m_Toolbar->AutoSize();
817
818 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
819 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
820
821 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
822 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
823 }
824
825 bUpdating = FALSE;
826 return b;
827 }
828
829 BOOL InitControls()
830 {
831 if (CreateLayout())
832 {
833
834 InitApplicationsList();
835 InitCategoriesList();
836
837 nSelectedApps = 0;
838 UpdateStatusBarText();
839
840 return TRUE;
841 }
842
843 return FALSE;
844 }
845
846 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
847 {
848 /* Size status bar */
849 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
850
851 /* Size tool bar */
852 m_Toolbar->AutoSize();
853
854 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
855 HDWP hdwp = NULL;
856 INT count = m_ClientPanel->CountSizableChildren();
857
858 hdwp = BeginDeferWindowPos(count);
859 if (hdwp)
860 {
861 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
862 }
863 if (hdwp)
864 {
865 EndDeferWindowPos(hdwp);
866 }
867
868 // TODO: Sub-layouts for children of children
869 count = m_SearchBar->CountSizableChildren();
870 hdwp = BeginDeferWindowPos(count);
871 if (hdwp)
872 {
873 hdwp = m_SearchBar->OnParentSize(r, hdwp);
874 }
875 if (hdwp)
876 {
877 EndDeferWindowPos(hdwp);
878 }
879 }
880
881 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
882 {
883 theResult = 0;
884 switch (Msg)
885 {
886 case WM_CREATE:
887 if (!InitControls())
888 ::PostMessage(hwnd, WM_CLOSE, 0, 0);
889 break;
890
891 case WM_DESTROY:
892 {
893 ShowWindow(SW_HIDE);
894 SaveSettings(hwnd);
895
896 FreeLogs();
897 m_AvailableApps.FreeCachedEntries();
898
899 if (IS_INSTALLED_ENUM(SelectedEnumType))
900 FreeInstalledAppList();
901
902 delete m_ClientPanel;
903
904 PostQuitMessage(0);
905 return 0;
906 }
907
908 case WM_COMMAND:
909 OnCommand(wParam, lParam);
910 break;
911
912 case WM_NOTIFY:
913 {
914 LPNMHDR data = (LPNMHDR) lParam;
915
916 switch (data->code)
917 {
918 case TVN_SELCHANGED:
919 {
920 if (data->hwndFrom == m_TreeView->m_hWnd)
921 {
922 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
923 {
924 case IDS_INSTALLED:
925 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
926 break;
927
928 case IDS_APPLICATIONS:
929 UpdateApplicationsList(ENUM_APPLICATIONS);
930 break;
931
932 case IDS_UPDATES:
933 UpdateApplicationsList(ENUM_UPDATES);
934 break;
935
936 case IDS_AVAILABLEFORINST:
937 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
938 break;
939
940 case IDS_CAT_AUDIO:
941 UpdateApplicationsList(ENUM_CAT_AUDIO);
942 break;
943
944 case IDS_CAT_DEVEL:
945 UpdateApplicationsList(ENUM_CAT_DEVEL);
946 break;
947
948 case IDS_CAT_DRIVERS:
949 UpdateApplicationsList(ENUM_CAT_DRIVERS);
950 break;
951
952 case IDS_CAT_EDU:
953 UpdateApplicationsList(ENUM_CAT_EDU);
954 break;
955
956 case IDS_CAT_ENGINEER:
957 UpdateApplicationsList(ENUM_CAT_ENGINEER);
958 break;
959
960 case IDS_CAT_FINANCE:
961 UpdateApplicationsList(ENUM_CAT_FINANCE);
962 break;
963
964 case IDS_CAT_GAMES:
965 UpdateApplicationsList(ENUM_CAT_GAMES);
966 break;
967
968 case IDS_CAT_GRAPHICS:
969 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
970 break;
971
972 case IDS_CAT_INTERNET:
973 UpdateApplicationsList(ENUM_CAT_INTERNET);
974 break;
975
976 case IDS_CAT_LIBS:
977 UpdateApplicationsList(ENUM_CAT_LIBS);
978 break;
979
980 case IDS_CAT_OFFICE:
981 UpdateApplicationsList(ENUM_CAT_OFFICE);
982 break;
983
984 case IDS_CAT_OTHER:
985 UpdateApplicationsList(ENUM_CAT_OTHER);
986 break;
987
988 case IDS_CAT_SCIENCE:
989 UpdateApplicationsList(ENUM_CAT_SCIENCE);
990 break;
991
992 case IDS_CAT_TOOLS:
993 UpdateApplicationsList(ENUM_CAT_TOOLS);
994 break;
995
996 case IDS_CAT_VIDEO:
997 UpdateApplicationsList(ENUM_CAT_VIDEO);
998 break;
999 }
1000 }
1001
1002 HMENU mainMenu = ::GetMenu(hwnd);
1003 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
1004
1005 /* Disable/enable items based on treeview selection */
1006 if (IsSelectedNodeInstalled())
1007 {
1008 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
1009 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
1010 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
1011 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
1012
1013 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
1014 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
1015 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
1016 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
1017
1018 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1019 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1020 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1021 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1022 }
1023 else
1024 {
1025 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
1026 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
1027 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
1028 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
1029
1030 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
1031 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
1032 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
1033 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
1034
1035 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
1036 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
1037 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
1038 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
1039 }
1040 }
1041 break;
1042
1043 case LVN_ITEMCHANGED:
1044 {
1045 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1046
1047 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1048 {
1049 /* Check if this is a valid item
1050 * (technically, it can be also an unselect) */
1051 INT ItemIndex = pnic->iItem;
1052 if (ItemIndex == -1 ||
1053 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1054 {
1055 break;
1056 }
1057
1058 /* Check if the focus has been moved to another item */
1059 if ((pnic->uChanged & LVIF_STATE) &&
1060 (pnic->uNewState & LVIS_FOCUSED) &&
1061 !(pnic->uOldState & LVIS_FOCUSED))
1062 {
1063 if (IS_INSTALLED_ENUM(SelectedEnumType))
1064 ShowInstalledAppInfo(ItemIndex);
1065 if (isAvailableEnum(SelectedEnumType))
1066 CAvailableAppView::ShowAvailableAppInfo(ItemIndex);
1067 }
1068 /* Check if the item is checked */
1069 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1070 {
1071 BOOL checked = ListView_GetCheckState(pnic->hdr.hwndFrom, pnic->iItem);
1072 /* FIXME: HAX!
1073 - preventing decremention below zero as a safeguard for ReactOS
1074 In ReactOS this action is triggered whenever user changes *selection*, but should be only when *checkbox* state toggled
1075 Maybe LVIS_STATEIMAGEMASK is set incorrectly
1076 */
1077 nSelectedApps +=
1078 (checked)
1079 ? 1
1080 : ((nSelectedApps > 0)
1081 ? -1
1082 : 0);
1083 UpdateStatusBarText();
1084 }
1085 }
1086 }
1087 break;
1088
1089 case LVN_COLUMNCLICK:
1090 {
1091 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1092
1093 m_ListView->ColumnClick(pnmv);
1094 }
1095 break;
1096
1097 case NM_CLICK:
1098 {
1099 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1100 {
1101 if (IS_INSTALLED_ENUM(SelectedEnumType))
1102 ShowInstalledAppInfo(-1);
1103 if (isAvailableEnum(SelectedEnumType))
1104 CAvailableAppView::ShowAvailableAppInfo(-1);
1105 }
1106 }
1107 break;
1108
1109 case NM_DBLCLK:
1110 {
1111 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1112 {
1113 /* this won't do anything if the program is already installed */
1114 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1115 }
1116 }
1117 break;
1118
1119 case NM_RCLICK:
1120 {
1121 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1122 {
1123 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1124 }
1125 }
1126 break;
1127
1128 case EN_LINK:
1129 OnLink((ENLINK*) lParam);
1130 break;
1131
1132 case TTN_GETDISPINFO:
1133 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1134 break;
1135 }
1136 }
1137 break;
1138
1139 case WM_SIZE:
1140 OnSize(hwnd, wParam, lParam);
1141 break;
1142
1143 case WM_SIZING:
1144 {
1145 LPRECT pRect = (LPRECT) lParam;
1146
1147 if (pRect->right - pRect->left < 565)
1148 pRect->right = pRect->left + 565;
1149
1150 if (pRect->bottom - pRect->top < 300)
1151 pRect->bottom = pRect->top + 300;
1152
1153 return TRUE;
1154 }
1155
1156 case WM_SYSCOLORCHANGE:
1157 {
1158 /* Forward WM_SYSCOLORCHANGE to common controls */
1159 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1160 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1161 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1162 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1163 }
1164 break;
1165
1166 case WM_TIMER:
1167 if (wParam == SEARCH_TIMER_ID)
1168 {
1169 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1170 if (bSearchEnabled)
1171 UpdateApplicationsList(-1);
1172 }
1173 break;
1174 }
1175
1176 return FALSE;
1177 }
1178
1179 virtual VOID OnLink(ENLINK *Link)
1180 {
1181 switch (Link->msg)
1182 {
1183 case WM_LBUTTONUP:
1184 case WM_RBUTTONUP:
1185 {
1186 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1187
1188 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1189 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1190 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1191 if (!pLink)
1192 {
1193 /* TODO: Error message */
1194 return;
1195 }
1196
1197 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1198 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1199
1200 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1201 }
1202 break;
1203 }
1204 }
1205
1206 BOOL IsSelectedNodeInstalled()
1207 {
1208 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1209 TV_ITEM tItem;
1210
1211 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1212 tItem.hItem = hSelectedItem;
1213 m_TreeView->GetItem(&tItem);
1214 switch (tItem.lParam)
1215 {
1216 case IDS_INSTALLED:
1217 case IDS_APPLICATIONS:
1218 case IDS_UPDATES:
1219 return TRUE;
1220 default:
1221 return FALSE;
1222 }
1223 }
1224
1225 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1226 {
1227 WORD wCommand = LOWORD(wParam);
1228
1229 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1230 {
1231 ATL::CStringW szBuf;
1232
1233 switch (HIWORD(wParam))
1234 {
1235 case EN_SETFOCUS:
1236 {
1237 ATL::CStringW szWndText;
1238
1239 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1240 m_SearchBar->GetWindowTextW(szWndText);
1241 if (szBuf == szWndText)
1242 {
1243 bSearchEnabled = FALSE;
1244 m_SearchBar->SetWindowTextW(L"");
1245 }
1246 }
1247 break;
1248
1249 case EN_KILLFOCUS:
1250 {
1251 m_SearchBar->GetWindowTextW(szBuf);
1252 if (szBuf.IsEmpty())
1253 {
1254 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1255 bSearchEnabled = FALSE;
1256 m_SearchBar->SetWindowTextW(szBuf.GetString());
1257 }
1258 }
1259 break;
1260
1261 case EN_CHANGE:
1262 {
1263 ATL::CStringW szWndText;
1264
1265 if (!bSearchEnabled)
1266 {
1267 bSearchEnabled = TRUE;
1268 break;
1269 }
1270
1271 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1272 m_SearchBar->GetWindowTextW(szWndText);
1273 if (szBuf == szWndText)
1274 {
1275 szSearchPattern.Empty();
1276 }
1277 else
1278 {
1279 szSearchPattern = szWndText;
1280 }
1281
1282 DWORD dwDelay;
1283 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1284 SetTimer(SEARCH_TIMER_ID, dwDelay);
1285 }
1286 break;
1287 }
1288
1289 return;
1290 }
1291
1292 switch (wCommand)
1293 {
1294 case ID_OPEN_LINK:
1295 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1296 HeapFree(GetProcessHeap(), 0, pLink);
1297 break;
1298
1299 case ID_COPY_LINK:
1300 CopyTextToClipboard(pLink);
1301 HeapFree(GetProcessHeap(), 0, pLink);
1302 break;
1303
1304 case ID_SETTINGS:
1305 CreateSettingsDlg(m_hWnd);
1306 break;
1307
1308 case ID_EXIT:
1309 PostMessageW(WM_CLOSE, 0, 0);
1310 break;
1311
1312 case ID_INSTALL:
1313 if (nSelectedApps > 0)
1314 {
1315 CDownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems());
1316 UpdateApplicationsList(-1);
1317 }
1318 else if (CDownloadManager::DownloadApplication(m_ListView->GetSelectedData()))
1319 {
1320 UpdateApplicationsList(-1);
1321 }
1322
1323 break;
1324
1325 case ID_UNINSTALL:
1326 if (UninstallApplication(-1, FALSE))
1327 UpdateApplicationsList(-1);
1328 break;
1329
1330 case ID_MODIFY:
1331 if (UninstallApplication(-1, TRUE))
1332 UpdateApplicationsList(-1);
1333 break;
1334
1335 case ID_REGREMOVE:
1336 RemoveAppFromRegistry(-1);
1337 break;
1338
1339 case ID_REFRESH:
1340 UpdateApplicationsList(-1);
1341 break;
1342
1343 case ID_RESETDB:
1344 CAvailableApps::ForceUpdateAppsDB();
1345 UpdateApplicationsList(-1);
1346 break;
1347
1348 case ID_HELP:
1349 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1350 break;
1351
1352 case ID_ABOUT:
1353 ShowAboutDialog();
1354 break;
1355
1356 case ID_CHECK_ALL:
1357 m_ListView->CheckAll();
1358 break;
1359 }
1360 }
1361
1362 VOID FreeInstalledAppList()
1363 {
1364 INT Count = m_ListView->GetItemCount() - 1;
1365 PINSTALLED_INFO Info;
1366
1367 while (Count >= 0)
1368 {
1369 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1370 if (Info)
1371 {
1372 RegCloseKey(Info->hSubKey);
1373 delete Info;
1374 }
1375 Count--;
1376 }
1377 }
1378
1379 static BOOL SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
1380 {
1381 if (!*szNeedle)
1382 return TRUE;
1383 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1384 return StrStrIW(szHaystack, szNeedle) != NULL;
1385 }
1386
1387 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &szName, PINSTALLED_INFO Info)
1388 {
1389 PINSTALLED_INFO ItemInfo;
1390 ATL::CStringW szText;
1391 INT Index;
1392
1393 if (!SearchPatternMatch(szName.GetString(), szSearchPattern))
1394 {
1395 RegCloseKey(Info->hSubKey);
1396 return TRUE;
1397 }
1398
1399 ItemInfo = new INSTALLED_INFO(*Info);
1400 if (!ItemInfo)
1401 {
1402 RegCloseKey(Info->hSubKey);
1403 return FALSE;
1404 }
1405
1406 Index = ListViewAddItem(ItemIndex, 0, szName, (LPARAM) ItemInfo);
1407
1408 /* Get version info */
1409 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
1410 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(szText.GetString()));
1411
1412 /* Get comments */
1413 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
1414 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(szText.GetString()));
1415
1416 return TRUE;
1417 }
1418
1419 static BOOL CALLBACK s_EnumAvailableAppProc(PAPPLICATION_INFO Info, LPCWSTR szFolderPath)
1420 {
1421 INT Index;
1422 HICON hIcon = NULL;
1423
1424 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1425
1426 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
1427 !SearchPatternMatch(Info->szDesc, szSearchPattern))
1428 {
1429 return TRUE;
1430 }
1431
1432 /* Load icon from file */
1433 ATL::CStringW szIconPath;
1434 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->szName);
1435 hIcon = (HICON) LoadImageW(NULL,
1436 szIconPath.GetString(),
1437 IMAGE_ICON,
1438 LISTVIEW_ICON_SIZE,
1439 LISTVIEW_ICON_SIZE,
1440 LR_LOADFROMFILE);
1441
1442 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1443 {
1444 /* Load default icon */
1445 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1446 }
1447
1448 Index = ImageList_AddIcon(hImageListView, hIcon);
1449 DestroyIcon(hIcon);
1450
1451 Index = ListViewAddItem(Info->Category, Index, Info->szName, (LPARAM) Info);
1452 ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
1453
1454 ListView_SetItemText(hListView, Index, 1, const_cast<LPWSTR>(Info->szVersion.GetString()));
1455 ListView_SetItemText(hListView, Index, 2, const_cast<LPWSTR>(Info->szDesc.GetString()));
1456
1457 return TRUE;
1458 }
1459
1460 VOID UpdateStatusBarText()
1461 {
1462 if (m_StatusBar)
1463 {
1464 ATL::CStringW szBuffer;
1465
1466 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1467 m_StatusBar->SetText(szBuffer);
1468 }
1469 }
1470
1471 VOID UpdateApplicationsList(INT EnumType)
1472 {
1473 ATL::CStringW szBuffer1, szBuffer2;
1474 HIMAGELIST hImageListView;
1475 bUpdating = TRUE;
1476
1477 m_ListView->SetRedraw(FALSE);
1478
1479 nSelectedApps = 0;
1480 if (EnumType < 0) EnumType = SelectedEnumType;
1481
1482 if (IS_INSTALLED_ENUM(SelectedEnumType))
1483 {
1484 FreeInstalledAppList();
1485 }
1486
1487 m_ListView->DeleteAllItems();
1488
1489 /* Create new ImageList */
1490 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1491 LISTVIEW_ICON_SIZE,
1492 GetSystemColorDepth() | ILC_MASK,
1493 0, 1);
1494 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1495 if (hImageListBuf)
1496 {
1497 ImageList_Destroy(hImageListBuf);
1498 }
1499
1500 if (IS_INSTALLED_ENUM(EnumType))
1501 {
1502 HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1503 ImageList_AddIcon(hImageListView, hIcon);
1504 DestroyIcon(hIcon);
1505 /* Enum installed applications and updates */
1506 EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc);
1507 EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc);
1508 }
1509 else if (isAvailableEnum(EnumType))
1510 {
1511 /* Enum available applications */
1512 m_AvailableApps.EnumAvailableApplications(EnumType, s_EnumAvailableAppProc);
1513 }
1514
1515 SelectedEnumType = EnumType;
1516 UpdateStatusBarText();
1517 SetWelcomeText();
1518
1519 /* Set automatic column width for program names if the list is not empty */
1520 if (m_ListView->GetItemCount() > 0)
1521 {
1522 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1523 }
1524
1525 bUpdating = FALSE;
1526 m_ListView->SetRedraw(TRUE);
1527 }
1528
1529 public:
1530 static ATL::CWndClassInfo& GetWndClassInfo()
1531 {
1532 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1533 static ATL::CWndClassInfo wc =
1534 {
1535 {
1536 sizeof(WNDCLASSEX),
1537 csStyle,
1538 StartWindowProc,
1539 0,
1540 0,
1541 NULL,
1542 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1543 LoadCursorW(NULL, IDC_ARROW),
1544 (HBRUSH) (COLOR_BTNFACE + 1),
1545 MAKEINTRESOURCEW(IDR_MAINMENU),
1546 L"RAppsWnd",
1547 NULL
1548 },
1549 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1550 };
1551 return wc;
1552 }
1553
1554 HWND Create()
1555 {
1556 ATL::CStringW szWindowName;
1557 szWindowName.LoadStringW(IDS_APPTITLE);
1558
1559 RECT r = {
1560 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1561 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1562 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1563 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1564 };
1565 r.right += r.left;
1566 r.bottom += r.top;
1567
1568 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1569 }
1570
1571 CStatusBar * GetStatusBar()
1572 {
1573 return m_StatusBar;
1574 }
1575
1576 CAppsListView * GetListView()
1577 {
1578 return m_ListView;
1579 }
1580
1581 CRichEdit * GetRichEdit()
1582 {
1583 return m_RichEdit;
1584 }
1585
1586 CAvailableApps * GetAvailableApps()
1587 {
1588 return &m_AvailableApps;
1589 }
1590 };
1591
1592 // File interface
1593
1594 CMainWindow * g_MainWindow;
1595
1596 HWND CreateMainWindow()
1597 {
1598 g_MainWindow = new CMainWindow();
1599 return g_MainWindow->Create();
1600 }
1601
1602 DWORD_PTR ListViewGetlParam(INT item)
1603 {
1604 if (item < 0)
1605 {
1606 item = g_MainWindow->GetListView()->GetSelectionMark();
1607 }
1608 return g_MainWindow->GetListView()->GetItemData(item);
1609 }
1610
1611 VOID SetStatusBarText(LPCWSTR szText)
1612 {
1613 g_MainWindow->GetStatusBar()->SetText(szText);
1614 }
1615
1616 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1617 {
1618 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1619 }
1620
1621 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1622 {
1623 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1624 }
1625
1626 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1627 {
1628 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1629 }
1630
1631 /* ATL version of functions */
1632 VOID SetStatusBarText(const ATL::CStringW& szText)
1633 {
1634 SetStatusBarText(szText.GetString());
1635 }
1636
1637 INT ListViewAddItem(INT ItemIndex, INT IconIndex, const ATL::CStringW& Name, LPARAM lParam)
1638 {
1639 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1640 }
1641
1642 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1643 {
1644 NewRichEditText(szText.GetString(), flags);
1645 }
1646
1647 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1648 {
1649 InsertRichEditText(szText.GetString(), flags);
1650 }
1651
1652 CAvailableApps* GetAvailableApps()
1653 {
1654 return g_MainWindow->GetAvailableApps();
1655 }