https://git.reactos.org/?p=reactos.git;a=commitdiff;h=10c0ff7416d6e8066c170…
commit 10c0ff7416d6e8066c170bb3abdfb22303c472ed
Author: He Yang <1160386205(a)qq.com>
AuthorDate: Tue Jul 21 22:13:39 2020 +0800
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sun Sep 6 17:09:20 2020 +0200
[RAPPS] listview refactor (#2970)
This makes it easier to maintain the listview, and better separates the application
list and listview.
* [RAPPS] fix memory leak when cleanup. some renaming are also done
* [RAPPS] move the code adding apps info inside class CAppsListView
* [RAPPS] add table view, create listview and AppInfoDisplay inside it
* [RAPPS] rename INSTALLED_INFO as CInstalledApplicationInfo
now it corresponds with CAvailableApplicationInfo
* [RAPPS] add CInstalledApps
* [RAPPS] optimize the speed when refreshing listview
* [RAPPS] correctly handle Enum for InstalledApps
* [RAPPS] make check all working properly (this also fixes some bugs)
the old version has some bugs when check all items after switching tags in tree-view
* [RAPPS] add handling for wow64
* [RAPPS] use an inline function to replace INSERT_TEXT macro
* [RAPPS] fix the bug that StatusBar won't update when switching tags
* [RAPPS] now TableView always reset bIsAscending in SetDisplayMode
* [RAPPS] rename TableView to ApplicationView
* [RAPPS] now bIsAscending would be reset when switching column in listview
---
base/applications/rapps/available.cpp | 169 ++--
base/applications/rapps/gui.cpp | 1335 ++++++++++++++++-----------
base/applications/rapps/include/available.h | 16 +-
base/applications/rapps/include/installed.h | 46 +-
base/applications/rapps/include/misc.h | 2 +
base/applications/rapps/include/rosui.h | 5 +-
base/applications/rapps/installed.cpp | 306 ++++--
base/applications/rapps/misc.cpp | 33 +
8 files changed, 1203 insertions(+), 709 deletions(-)
diff --git a/base/applications/rapps/available.cpp
b/base/applications/rapps/available.cpp
index 8af6c78a8b9..62d4585d3a5 100644
--- a/base/applications/rapps/available.cpp
+++ b/base/applications/rapps/available.cpp
@@ -19,7 +19,7 @@
// CAvailableApplicationInfo
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW&
sFileNameParam, AvailableStrings& AvlbStrings)
- : m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0),
m_sFileName(sFileNameParam),
+ : m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
{
RetrieveGeneralInfo(AvlbStrings);
@@ -400,71 +400,127 @@ BOOL CAvailableApps::ForceUpdateAppsDB()
BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
{
+ if (EnumType == ENUM_CAT_SELECTED)
+ {
+ CAvailableApplicationInfo *EnumAvlbInfo = NULL;
- HANDLE hFind = INVALID_HANDLE_VALUE;
- WIN32_FIND_DATAW FindFileData;
-
- hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
+ // enum all object in m_SelectedList and invoke callback
+ for(POSITION CurrentPosition = m_SelectedList.GetHeadPosition();
+ CurrentPosition && (EnumAvlbInfo =
m_SelectedList.GetAt(CurrentPosition));
+ m_SelectedList.GetNext(CurrentPosition))
+ {
+ EnumAvlbInfo->RefreshAppInfo(m_Strings);
- if (hFind == INVALID_HANDLE_VALUE)
- {
- //no db yet
- return FALSE;
+ if (lpEnumProc)
+ lpEnumProc(EnumAvlbInfo, TRUE, param);
+ }
+ return TRUE;
}
-
- do
+ else
{
- // loop for all the cached entries
- POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
- CAvailableApplicationInfo* Info = NULL;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAW FindFileData;
+
+ hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ //no db yet
+ return FALSE;
+ }
- while (CurrentListPosition != NULL)
+ do
{
- POSITION LastListPosition = CurrentListPosition;
- Info = m_InfoList.GetNext(CurrentListPosition);
+ // loop for all the cached entries
+ POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
+ CAvailableApplicationInfo *Info = NULL;
- // do we already have this entry in cache?
- if (Info->m_sFileName == FindFileData.cFileName)
+ while (CurrentListPosition != NULL)
{
- // is it current enough, or the file has been modified since our last
time here?
- if (CompareFileTime(&FindFileData.ftLastWriteTime,
&Info->m_ftCacheStamp) == 1)
- {
- // recreate our cache, this is the slow path
- m_InfoList.RemoveAt(LastListPosition);
+ POSITION LastListPosition = CurrentListPosition;
+ Info = m_InfoList.GetNext(CurrentListPosition);
- delete Info;
- Info = NULL;
- break;
+ // do we already have this entry in cache?
+ if (Info->m_sFileName == FindFileData.cFileName)
+ {
+ // is it current enough, or the file has been modified since our last
time here?
+ if (CompareFileTime(&FindFileData.ftLastWriteTime,
&Info->m_ftCacheStamp) == 1)
+ {
+ // recreate our cache, this is the slow path
+ m_InfoList.RemoveAt(LastListPosition);
+
+ // also remove this in selected list (if exist)
+ RemoveSelected(Info);
+
+ delete Info;
+ Info = NULL;
+ break;
+ }
+ else
+ {
+ // speedy path, compare directly, we already have the data
+ goto skip_if_cached;
+ }
}
- else
+ }
+
+ // create a new entry
+ Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
+
+ // set a timestamp for the next time
+ Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
+ m_InfoList.AddTail(Info);
+
+ skip_if_cached:
+ if (EnumType == Info->m_Category
+ || EnumType == ENUM_ALL_AVAILABLE)
+ {
+ Info->RefreshAppInfo(m_Strings);
+
+ if (lpEnumProc)
{
- // speedy path, compare directly, we already have the data
- goto skip_if_cached;
+ if (m_SelectedList.Find(Info))
+ {
+ lpEnumProc(Info, TRUE, param);
+ }
+ else
+ {
+ lpEnumProc(Info, FALSE, param);
+ }
}
}
- }
+ } while (FindNextFileW(hFind, &FindFileData));
- // create a new entry
- Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
+ FindClose(hFind);
+ return TRUE;
+ }
+}
- // set a timestamp for the next time
- Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
- m_InfoList.AddTail(Info);
+BOOL CAvailableApps::AddSelected(CAvailableApplicationInfo *AvlbInfo)
+{
+ return m_SelectedList.AddTail(AvlbInfo) != 0;
+}
-skip_if_cached:
- if (EnumType == Info->m_Category
- || EnumType == ENUM_ALL_AVAILABLE
- || (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
- {
- Info->RefreshAppInfo(m_Strings);
+BOOL CAvailableApps::RemoveSelected(CAvailableApplicationInfo *AvlbInfo)
+{
+ POSITION Position = m_SelectedList.Find(AvlbInfo);
+ if (Position)
+ {
+ m_SelectedList.RemoveAt(Position);
+ return TRUE;
+ }
+ return FALSE;
+}
- if (lpEnumProc)
- lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param);
- }
- } while (FindNextFileW(hFind, &FindFileData) != 0);
+VOID CAvailableApps::RemoveAllSelected()
+{
+ m_SelectedList.RemoveAll();
+ return;
+}
- FindClose(hFind);
- return TRUE;
+int CAvailableApps::GetSelectedCount()
+{
+ return m_SelectedList.GetCount();
}
CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName)
const
@@ -502,23 +558,6 @@ ATL::CSimpleArray<CAvailableApplicationInfo>
CAvailableApps::FindInfoList(const
return result;
}
-ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::GetSelected() const
-{
- ATL::CSimpleArray<CAvailableApplicationInfo> result;
- POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
- CAvailableApplicationInfo* Info;
-
- while (CurrentListPosition != NULL)
- {
- Info = m_InfoList.GetNext(CurrentListPosition);
- if (Info->m_IsSelected)
- {
- result.Add(*Info);
- }
- }
- return result;
-}
-
const ATL::CStringW& CAvailableApps::GetFolderPath() const
{
return m_Strings.szPath;
diff --git a/base/applications/rapps/gui.cpp b/base/applications/rapps/gui.cpp
index b0599074a47..e3aeccc579f 100644
--- a/base/applications/rapps/gui.cpp
+++ b/base/applications/rapps/gui.cpp
@@ -65,6 +65,21 @@ enum SCRNSHOT_STATUS
#define PI 3.1415927
+// retrieve the value using a mask
+#define STATEIMAGETOINDEX(x) (((x) & LVIS_STATEIMAGEMASK) >> 12)
+
+// for listview with extend style LVS_EX_CHECKBOXES, State image 1 is the unchecked box,
and state image 2 is the checked box.
+// see this:
https://docs.microsoft.com/en-us/windows/win32/controls/extended-list-view-…
+#define STATEIMAGE_UNCHECKED 1
+#define STATEIMAGE_CHECKED 2
+
+enum APPLICATION_VIEW_MODE
+{
+ ApplicationViewEmpty,
+ ApplicationViewAvailableApps,
+ ApplicationViewInstalledApps
+};
+
typedef struct __ScrnshotDownloadParam
{
LONGLONG ID;
@@ -73,6 +88,8 @@ typedef struct __ScrnshotDownloadParam
ATL::CStringW DownloadFileName;
} ScrnshotDownloadParam;
+class CMainWindow;
+
INT GetSystemColorDepth()
{
DEVMODEW pDevMode;
@@ -250,41 +267,37 @@ public:
return TRUE;
}
- BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
+ inline VOID InsertTextWithString(UINT StringID, DWORD StringFlags, const
ATL::CStringW& Text, DWORD TextFlags)
{
- ATL::CStringW szText;
- ATL::CStringW szInfo;
+ if (!Text.IsEmpty())
+ {
+ LoadAndInsertText(StringID, Text, StringFlags, TextFlags);
+ }
+ }
- if (!Info || !Info->hSubKey)
- return FALSE;
+ BOOL ShowInstalledAppInfo(CInstalledApplicationInfo * Info)
+ {
+ if (!Info) return FALSE;
- Info->GetApplicationString(L"DisplayName", szText);
- SetText(szText, CFE_BOLD);
+ SetText(Info->szDisplayName, CFE_BOLD);
InsertText(L"\n", 0);
-#define GET_INFO(a, b, c, d) \
- if (Info->GetApplicationString(a, szInfo)) \
- { \
- LoadAndInsertText(b, szInfo, c, d); \
- }
-
- GET_INFO(L"DisplayVersion", IDS_INFO_VERSION, CFE_BOLD, 0);
- GET_INFO(L"Publisher", IDS_INFO_PUBLISHER, CFE_BOLD, 0);
- GET_INFO(L"RegOwner", IDS_INFO_REGOWNER, CFE_BOLD, 0);
- GET_INFO(L"ProductID", IDS_INFO_PRODUCTID, CFE_BOLD, 0);
- GET_INFO(L"HelpLink", IDS_INFO_HELPLINK, CFE_BOLD, CFM_LINK);
- GET_INFO(L"HelpTelephone", IDS_INFO_HELPPHONE, CFE_BOLD, 0);
- GET_INFO(L"Readme", IDS_INFO_README, CFE_BOLD, 0);
- GET_INFO(L"Contact", IDS_INFO_CONTACT, CFE_BOLD, 0);
- GET_INFO(L"URLUpdateInfo", IDS_INFO_UPDATEINFO, CFE_BOLD, CFM_LINK);
- GET_INFO(L"URLInfoAbout", IDS_INFO_INFOABOUT, CFE_BOLD, CFM_LINK);
- GET_INFO(L"Comments", IDS_INFO_COMMENTS, CFE_BOLD, 0);
- GET_INFO(L"InstallDate", IDS_INFO_INSTALLDATE, CFE_BOLD, 0);
- GET_INFO(L"InstallLocation", IDS_INFO_INSTLOCATION, CFE_BOLD, 0);
- GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
- GET_INFO(L"UninstallString", IDS_INFO_UNINSTALLSTR, CFE_BOLD, 0);
- GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
- GET_INFO(L"ModifyPath", IDS_INFO_MODIFYPATH, CFE_BOLD, 0);
+ InsertTextWithString(IDS_INFO_VERSION, CFE_BOLD, Info->szDisplayVersion, 0);
+ InsertTextWithString(IDS_INFO_PUBLISHER, CFE_BOLD, Info->szPublisher, 0);
+ InsertTextWithString(IDS_INFO_REGOWNER, CFE_BOLD, Info->szRegOwner, 0);
+ InsertTextWithString(IDS_INFO_PRODUCTID, CFE_BOLD, Info->szProductID, 0);
+ InsertTextWithString(IDS_INFO_HELPLINK, CFE_BOLD, Info->szHelpLink,
CFM_LINK);
+ InsertTextWithString(IDS_INFO_HELPPHONE, CFE_BOLD, Info->szHelpTelephone, 0);
+ InsertTextWithString(IDS_INFO_README, CFE_BOLD, Info->szReadme, 0);
+ InsertTextWithString(IDS_INFO_CONTACT, CFE_BOLD, Info->szContact, 0);
+ InsertTextWithString(IDS_INFO_UPDATEINFO, CFE_BOLD, Info->szURLUpdateInfo,
CFM_LINK);
+ InsertTextWithString(IDS_INFO_INFOABOUT, CFE_BOLD, Info->szURLInfoAbout,
CFM_LINK);
+ InsertTextWithString(IDS_INFO_COMMENTS, CFE_BOLD, Info->szComments, 0);
+ InsertTextWithString(IDS_INFO_INSTALLDATE, CFE_BOLD, Info->szInstallDate, 0);
+ InsertTextWithString(IDS_INFO_INSTLOCATION, CFE_BOLD, Info->szInstallLocation,
0);
+ InsertTextWithString(IDS_INFO_INSTALLSRC, CFE_BOLD, Info->szInstallSource,
0);
+ InsertTextWithString(IDS_INFO_UNINSTALLSTR, CFE_BOLD, Info->szUninstallString,
0);
+ InsertTextWithString(IDS_INFO_MODIFYPATH, CFE_BOLD, Info->szModifyPath, 0);
return TRUE;
}
@@ -908,8 +921,8 @@ private:
public:
- CAppRichEdit * RichEdit;
- CAppScrnshotPreview * ScrnshotPrev;
+ CAppRichEdit * RichEdit = NULL;
+ CAppScrnshotPreview * ScrnshotPrev = NULL;
static ATL::CWndClassInfo& GetWndClassInfo()
{
@@ -957,7 +970,7 @@ public:
return RichEdit->ShowAvailableAppInfo(Info);
}
- BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
+ BOOL ShowInstalledAppInfo(CInstalledApplicationInfo * Info)
{
ScrnshotPrev->DisplayEmpty();
ResizeChildren();
@@ -993,6 +1006,11 @@ public:
}
}
+ ~CAppInfoDisplay()
+ {
+ delete RichEdit;
+ delete ScrnshotPrev;
+ }
};
class CMainToolbar :
@@ -1177,16 +1195,19 @@ class CAppsListView :
INT iSubItem;
};
- BOOL bHasAllChecked;
- BOOL bIsAscending;
+ BOOL bIsAscending = TRUE;
BOOL bHasCheckboxes;
+ INT ItemCount = 0;
+ INT CheckedItemCount = 0;
+ INT ColumnCount = 0;
+
INT nLastHeaderID;
+ APPLICATION_VIEW_MODE ApplicationViewMode = ApplicationViewEmpty;
+
public:
CAppsListView() :
- bHasAllChecked(FALSE),
- bIsAscending(TRUE),
bHasCheckboxes(FALSE),
nLastHeaderID(-1)
{
@@ -1221,6 +1242,7 @@ public:
/* If the sorting column changed, remove the sorting style from the old column
*/
if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
{
+ bIsAscending = TRUE; // also reset sorting method to ascending
hColumn.mask = HDI_FORMAT;
Header_GetItem(hHeader, nLastHeaderID, &hColumn);
hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
@@ -1249,7 +1271,7 @@ public:
return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width,
Format);
}
- BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
+ int AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
{
LVCOLUMNW Column;
@@ -1261,7 +1283,13 @@ public:
Column.cx = Width;
Column.fmt = Format;
- return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
+ return SendMessage(LVM_INSERTCOLUMN, Index, (LPARAM)(&Column));
+ }
+
+ void DeleteColumn(INT Index)
+ {
+ SendMessage(LVM_DELETECOLUMN, Index, 0);
+ return;
}
INT AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
@@ -1270,15 +1298,25 @@ public:
ZeroMemory(&Item, sizeof(Item));
- Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
+ Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
Item.pszText = const_cast<LPWSTR>(lpText);
Item.lParam = lParam;
Item.iItem = ItemIndex;
Item.iImage = IconIndex;
+ if (IconIndex >= 0)
+ {
+ Item.iImage = IconIndex;
+ Item.mask |= LVIF_IMAGE;
+ }
return InsertItem(&Item);
}
+ HIMAGELIST GetImageList(int iImageList)
+ {
+ return (HIMAGELIST)SendMessage(LVM_GETIMAGELIST, iImageList, 0);
+ }
+
static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
SortContext * ctx = ((SortContext*) lParamSort);
@@ -1319,6 +1357,12 @@ public:
SetCheckboxesVisible(FALSE);
}
+ HIMAGELIST hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
+ LISTVIEW_ICON_SIZE,
+ GetSystemColorDepth() | ILC_MASK,
+ 0, 1);
+ SetImageList(hImageListView, LVSIL_SMALL);
+
return hwnd;
}
@@ -1332,219 +1376,656 @@ public:
if (bHasCheckboxes)
{
SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1),
LVIS_STATEIMAGEMASK);
- SetSelected(item, fCheck);
}
}
- VOID SetSelected(INT item, BOOL value)
+ VOID CheckAll()
{
- if (item < 0)
+ if (bHasCheckboxes)
{
- for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
+ if (CheckedItemCount == ItemCount)
{
- CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*)
GetItemData(i);
- if (pAppInfo)
- {
- pAppInfo->m_IsSelected = value;
- }
+ // clear all
+ SetCheckState(-1, FALSE);
}
- }
- else
- {
- CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*)
GetItemData(item);
- if (pAppInfo)
+ else
{
- pAppInfo->m_IsSelected = value;
+ // check all
+ SetCheckState(-1, TRUE);
}
}
}
-
- VOID CheckAll()
+
+ PVOID GetFocusedItemData()
{
- if (bHasCheckboxes)
+ INT item = GetSelectionMark();
+ if (item == -1)
{
- bHasAllChecked = !bHasAllChecked;
- SetCheckState(-1, bHasAllChecked);
+ return (PVOID)0;
}
+ return (PVOID)GetItemData(item);
}
- ATL::CSimpleArray<CAvailableApplicationInfo> GetCheckedItems()
+ BOOL SetDisplayMode(APPLICATION_VIEW_MODE Mode)
{
- if (!bHasCheckboxes)
+ if (!DeleteAllItems()) return FALSE;
+ ApplicationViewMode = Mode;
+
+ bIsAscending = TRUE;
+
+ ItemCount = 0;
+ CheckedItemCount = 0;
+
+ // delete old columns
+ while (ColumnCount)
{
- return ATL::CSimpleArray<CAvailableApplicationInfo>();
+ DeleteColumn(--ColumnCount);
}
- ATL::CSimpleArray<CAvailableApplicationInfo> list;
- for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
+ ImageList_RemoveAll(GetImageList(LVSIL_SMALL));
+
+ // add new columns
+ ATL::CStringW szText;
+ switch (Mode)
{
- if (GetCheckState(i) != FALSE)
- {
- CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*)
GetItemData(i);
- list.Add(*pAppInfo);
- }
+ case ApplicationViewInstalledApps:
+
+ /* Add columns to ListView */
+ szText.LoadStringW(IDS_APP_NAME);
+ AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
+
+ szText.LoadStringW(IDS_APP_INST_VERSION);
+ AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
+
+ szText.LoadStringW(IDS_APP_DESCRIPTION);
+ AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
+
+ // disable checkboxes
+ SetCheckboxesVisible(FALSE);
+ break;
+
+ case ApplicationViewAvailableApps:
+
+ /* Add columns to ListView */
+ szText.LoadStringW(IDS_APP_NAME);
+ AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
+
+ szText.LoadStringW(IDS_APP_INST_VERSION);
+ AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
+
+ szText.LoadStringW(IDS_APP_DESCRIPTION);
+ AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
+
+ // enable checkboxes
+ SetCheckboxesVisible(TRUE);
+ break;
+
+ case ApplicationViewEmpty:
+ default:
+ break;
}
- return list;
+
+
+ return TRUE;
}
- CAvailableApplicationInfo* GetSelectedData()
+ BOOL AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID
CallbackParam)
{
- INT item = GetSelectionMark();
- return (CAvailableApplicationInfo*) GetItemData(item);
- }
-};
+ if (ApplicationViewMode != ApplicationViewInstalledApps)
+ {
+ return FALSE;
+ }
-class CSideTreeView :
- public CUiWindow<CTreeView>
-{
- HIMAGELIST hImageTreeView;
+ HICON hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
+ HIMAGELIST hImageList = GetImageList(LVSIL_SMALL);
+ int IconIndex = ImageList_AddIcon(hImageList, hIcon);
+ DestroyIcon(hIcon);
-public:
- CSideTreeView() :
- CUiWindow(),
- hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
- GetSystemColorDepth() | ILC_MASK,
- 0, 1))
- {
- }
+ int Index = AddItem(ItemCount, IconIndex, InstAppInfo->szDisplayName,
(LPARAM)CallbackParam);
+ SetItemText(Index, 1, InstAppInfo->szDisplayVersion.IsEmpty() ?
L"---" : InstAppInfo->szDisplayVersion);
+ SetItemText(Index, 2, InstAppInfo->szComments.IsEmpty() ? L"---" :
InstAppInfo->szComments);
- HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT
SelectedImage, LPARAM lParam)
- {
- return CUiWindow<CTreeView>::AddItem(hParent,
const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
+ ItemCount++;
+ return TRUE;
}
- HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
+ BOOL AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL
InitCheckState, LPVOID CallbackParam)
{
- ATL::CStringW szText;
- INT Index;
- HICON hIcon;
+ if (ApplicationViewMode != ApplicationViewAvailableApps)
+ {
+ return FALSE;
+ }
- hIcon = (HICON) LoadImageW(hInst,
- MAKEINTRESOURCE(IconIndex),
- IMAGE_ICON,
- TREEVIEW_ICON_SIZE,
- TREEVIEW_ICON_SIZE,
- LR_CREATEDIBSECTION);
- if (hIcon)
+ /* Load icon from file */
+ HICON hIcon = NULL;
+ ATL::CStringW szIconPath;
+ if (AvlbAppInfo->RetrieveIcon(szIconPath))
{
- Index = ImageList_AddIcon(hImageTreeView, hIcon);
- DestroyIcon(hIcon);
+ hIcon = (HICON)LoadImageW(NULL,
+ szIconPath.GetString(),
+ IMAGE_ICON,
+ LISTVIEW_ICON_SIZE,
+ LISTVIEW_ICON_SIZE,
+ LR_LOADFROMFILE);
}
- szText.LoadStringW(TextIndex);
- return AddItem(hRootItem, szText, Index, Index, TextIndex);
- }
+ if (!hIcon || GetLastError() != ERROR_SUCCESS)
+ {
+ /* Load default icon */
+ hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
+ }
- HIMAGELIST SetImageList()
- {
- return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
- }
+ HIMAGELIST hImageList = GetImageList(LVSIL_SMALL);
- VOID DestroyImageList()
- {
- if (hImageTreeView)
- ImageList_Destroy(hImageTreeView);
- }
+ int IconIndex = ImageList_AddIcon(hImageList, hIcon);
+ DestroyIcon(hIcon);
- ~CSideTreeView()
- {
- DestroyImageList();
- }
-};
+ int Index = AddItem(ItemCount, IconIndex, AvlbAppInfo->m_szName,
(LPARAM)CallbackParam);
-class CSearchBar :
- public CWindow
-{
-public:
- const INT m_Width;
- const INT m_Height;
+ if (InitCheckState)
+ {
+ SetCheckState(Index, TRUE);
+ }
- CSearchBar() : m_Width(200), m_Height(22)
- {
- }
+ SetItemText(Index, 1, AvlbAppInfo->m_szVersion);
+ SetItemText(Index, 2, AvlbAppInfo->m_szDesc);
- VOID SetText(LPCWSTR lpszText)
- {
- SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
+ ItemCount++;
+ return TRUE;
}
- HWND Create(HWND hwndParent)
+ // this function is called when parent window receiving an notification about
checkstate changing
+ VOID ItemCheckStateNotify(int iItem, BOOL bCheck)
{
- ATL::CStringW szBuf;
- m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
- WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
- 0, 0, m_Width, m_Height,
- hwndParent, (HMENU) NULL,
- hInst, 0);
-
- SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
- szBuf.LoadStringW(IDS_SEARCH_TEXT);
- SetWindowTextW(szBuf);
- return m_hWnd;
+ if (bCheck)
+ {
+ CheckedItemCount++;
+ }
+ else
+ {
+ CheckedItemCount--;
+ }
}
-
};
-class CMainWindow :
- public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
+class CApplicationView :
+ public CUiWindow<CWindowImpl<CApplicationView>>
{
- CUiPanel* m_ClientPanel;
- CUiSplitPanel* m_VSplitter;
- CUiSplitPanel* m_HSplitter;
+private:
+ CUiPanel *m_Panel = NULL;
- CMainToolbar* m_Toolbar;
- CAppsListView* m_ListView;
+ CAppsListView *m_ListView = NULL;
+ CAppInfoDisplay *m_AppsInfo = NULL;
+ CUiSplitPanel *m_HSplitter = NULL;
+ CMainWindow *m_MainWindow = NULL;
+ APPLICATION_VIEW_MODE ApplicationViewMode = ApplicationViewEmpty;
- CSideTreeView* m_TreeView;
- CUiWindow<CStatusBar>* m_StatusBar;
- CAppInfoDisplay* m_AppInfo;
+ BOOL ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
LRESULT& theResult, DWORD dwMapId)
+ {
+ theResult = 0;
+ switch (message)
+ {
+ case WM_CREATE:
+ {
+ BOOL bSuccess = TRUE;
+ m_Panel = new CUiPanel();
+ m_Panel->m_VerticalAlignment = UiAlign_Stretch;
+ m_Panel->m_HorizontalAlignment = UiAlign_Stretch;
- CUiWindow<CSearchBar>* m_SearchBar;
- CAvailableApps m_AvailableApps;
+ bSuccess &= CreateHSplitter();
+ bSuccess &= CreateListView();
+ bSuccess &= CreateAppInfoDisplay();
- INT nSelectedApps;
+ if (!bSuccess)
+ {
+ return -1; // creation failure
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ LPNMHDR pNotifyHeader = (LPNMHDR)lParam;
+ if (pNotifyHeader->hwndFrom == m_ListView->GetWindow())
+ {
+ switch (pNotifyHeader->code)
+ {
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW pnic = (LPNMLISTVIEW)lParam;
- BOOL bSearchEnabled;
- BOOL bUpdating;
+ /* Check if this is a valid item
+ * (technically, it can be also an unselect) */
+ INT ItemIndex = pnic->iItem;
+ if (ItemIndex == -1 ||
+ ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
+ {
+ break;
+ }
- ATL::CStringW szSearchPattern;
- INT SelectedEnumType;
+ /* Check if the focus has been moved to another item */
+ if ((pnic->uChanged & LVIF_STATE) &&
+ (pnic->uNewState & LVIS_FOCUSED) &&
+ !(pnic->uOldState & LVIS_FOCUSED))
+ {
+ ItemGetFocus((LPVOID)pnic->lParam);
+ }
-public:
- CMainWindow() :
- m_ClientPanel(NULL),
- bSearchEnabled(FALSE),
- SelectedEnumType(ENUM_ALL_INSTALLED)
- {
- }
+ /* Check if the item is checked/unchecked */
+ if (pnic->uChanged & LVIF_STATE)
+ {
+ int iOldState = STATEIMAGETOINDEX(pnic->uOldState);
+ int iNewState = STATEIMAGETOINDEX(pnic->uNewState);
+
+ if (iOldState == STATEIMAGE_UNCHECKED && iNewState ==
STATEIMAGE_CHECKED)
+ {
+ // this item is just checked
+ m_ListView->ItemCheckStateNotify(pnic->iItem, TRUE);
+ ItemCheckStateChanged(TRUE, (LPVOID)pnic->lParam);
+ }
+ else if (iOldState == STATEIMAGE_CHECKED && iNewState ==
STATEIMAGE_UNCHECKED)
+ {
+ // this item is just unchecked
+ m_ListView->ItemCheckStateNotify(pnic->iItem, FALSE);
+ ItemCheckStateChanged(FALSE, (LPVOID)pnic->lParam);
+ }
+ }
+ }
+ break;
-private:
- VOID InitApplicationsList()
- {
- ATL::CStringW szText;
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+
+ m_ListView->ColumnClick(pnmv);
+ }
+ break;
- /* Add columns to ListView */
- szText.LoadStringW(IDS_APP_NAME);
- m_ListView->AddColumn(0, szText, 250, LVCFMT_LEFT);
+ case NM_DBLCLK:
+ {
+ if (((LPNMLISTVIEW)lParam)->iItem != -1)
+ {
+ /* this won't do anything if the program is already installed
*/
+
+ // TODO: the same problem I've mentioned in NM_RCLICK
+ // I think if user double-click this app, then this app should be
installed, not those checked apps.
+ if (ApplicationViewMode == ApplicationViewAvailableApps)
+ {
+ SendMessageW(GetParent(), WM_COMMAND, ID_INSTALL, 0);
+ }
+ }
+ }
+ break;
- szText.LoadStringW(IDS_APP_INST_VERSION);
- m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
+ case NM_RCLICK:
+ {
+ if (((LPNMLISTVIEW)lParam)->iItem != -1)
+ {
+ // TODO: currently the menu will send WM_COMMAND directly to
MainWindow.
+ // possibly it should be handled by this application-view first
+ // and then forward to mainwindow.
+
+ // TODO: I think if user right-click on one item, and select
"Install"
+ // that means the user want install "this" application
+ // but if some apps are checked, this will lead to those checked
apps to be installed.
+ // this should be improved.
+ ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
- szText.LoadStringW(IDS_APP_DESCRIPTION);
- m_ListView->AddColumn(3, szText, 300, LVCFMT_LEFT);
+ case WM_SYSCOLORCHANGE:
+ {
+ /* Forward WM_SYSCOLORCHANGE to common controls */
+ m_ListView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
+ m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0,
GetSysColor(COLOR_BTNFACE));
+ }
+ break;
- // Unnesesary since the list updates on every TreeView selection
- // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
+ case WM_SIZE:
+ {
+ OnSize(hwnd, wParam, lParam);
+ break;
+ }
+ }
+ return FALSE;
}
- VOID InitCategoriesList()
+ BOOL CreateHSplitter()
{
- HTREEITEM hRootItemInstalled, hRootItemAvailable;
-
- hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED,
IDI_CATEGORY);
- m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
- m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
-
+ m_HSplitter = new CUiSplitPanel();
+ m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
+ m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
+ m_HSplitter->m_DynamicFirst = TRUE;
+ m_HSplitter->m_Horizontal = TRUE;
+ m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position
(m_MinSecond)
+ m_HSplitter->m_MinFirst = 10;
+ m_HSplitter->m_MinSecond = 140;
+ m_Panel->Children().Append(m_HSplitter);
+
+ return m_HSplitter->Create(m_hWnd) != NULL;
+ }
+
+ BOOL CreateListView()
+ {
+ m_ListView = new CAppsListView();
+ m_ListView->m_VerticalAlignment = UiAlign_Stretch;
+ m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
+ m_HSplitter->First().Append(m_ListView);
+
+ return m_ListView->Create(m_hWnd) != NULL;
+ }
+
+ BOOL CreateAppInfoDisplay()
+ {
+ m_AppsInfo = new CAppInfoDisplay();
+ m_AppsInfo->m_VerticalAlignment = UiAlign_Stretch;
+ m_AppsInfo->m_HorizontalAlignment = UiAlign_Stretch;
+ m_HSplitter->Second().Append(m_AppsInfo);
+
+ return m_AppsInfo->Create(m_hWnd) != NULL;
+ }
+
+ VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
+ {
+ if (wParam == SIZE_MINIMIZED)
+ return;
+
+ RECT r = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
+ HDWP hdwp = NULL;
+ INT count = m_Panel->CountSizableChildren();
+
+ hdwp = BeginDeferWindowPos(count);
+ if (hdwp)
+ {
+ hdwp = m_Panel->OnParentSize(r, hdwp);
+ if (hdwp)
+ {
+ EndDeferWindowPos(hdwp);
+ }
+ }
+ }
+
+public:
+
+ CApplicationView(CMainWindow *MainWindow)
+ : m_MainWindow(MainWindow)
+ {
+ }
+
+ ~CApplicationView()
+ {
+ delete m_ListView;
+ delete m_AppsInfo;
+ delete m_HSplitter;
+ }
+
+ static ATL::CWndClassInfo& GetWndClassInfo()
+ {
+ DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
+ static ATL::CWndClassInfo wc =
+ {
+ {
+ sizeof(WNDCLASSEX),
+ csStyle,
+ StartWindowProc,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ (HBRUSH)(COLOR_BTNFACE + 1),
+ NULL,
+ L"RAppsApplicationView",
+ NULL
+ },
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
+ };
+ return wc;
+ }
+
+ HWND Create(HWND hwndParent)
+ {
+ RECT r = { 0,0,0,0 };
+
+ return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ }
+
+ BOOL SetDisplayMode(APPLICATION_VIEW_MODE Mode)
+ {
+ if (!m_ListView->SetDisplayMode(Mode))
+ {
+ return FALSE;
+ }
+ ApplicationViewMode = Mode;
+ m_AppsInfo->SetWelcomeText();
+
+ HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
+ switch (Mode)
+ {
+ case ApplicationViewEmpty:
+ default:
+ EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
+ break;
+
+ case ApplicationViewInstalledApps:
+ EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
+ EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
+ EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
+ break;
+
+ case ApplicationViewAvailableApps:
+ EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
+ EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
+ EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
+ break;
+ }
+ return TRUE;
+ }
+
+ BOOL AddInstalledApplication(CInstalledApplicationInfo * InstAppInfo, LPVOID param)
+ {
+ if (ApplicationViewMode != ApplicationViewInstalledApps)
+ {
+ return FALSE;
+ }
+ return m_ListView->AddInstalledApplication(InstAppInfo, param);
+ }
+
+ BOOL AddAvailableApplication(CAvailableApplicationInfo * AvlbAppInfo, BOOL
InitCheckState, LPVOID param)
+ {
+ if (ApplicationViewMode != ApplicationViewAvailableApps)
+ {
+ return FALSE;
+ }
+ return m_ListView->AddAvailableApplication(AvlbAppInfo, InitCheckState,
param);
+ }
+
+ void CheckAll()
+ {
+ m_ListView->CheckAll();
+ return;
+ }
+
+ PVOID GetFocusedItemData()
+ {
+ return m_ListView->GetFocusedItemData();
+ }
+
+ int GetItemCount()
+ {
+ return m_ListView->GetItemCount();
+ }
+
+ // this function is called when a item of listview get focus.
+ // CallbackParam is the param passed to listview when adding the item (the one
getting focus now).
+ BOOL ItemGetFocus(LPVOID CallbackParam)
+ {
+ switch (ApplicationViewMode)
+ {
+ case ApplicationViewInstalledApps:
+ return m_AppsInfo->ShowInstalledAppInfo((CInstalledApplicationInfo
*)CallbackParam);
+
+ case ApplicationViewAvailableApps:
+ return m_AppsInfo->ShowAvailableAppInfo((CAvailableApplicationInfo
*)CallbackParam);
+
+ case ApplicationViewEmpty:
+ default:
+ m_AppsInfo->SetWelcomeText();
+ return FALSE;
+ }
+ }
+
+ // this function is called when a item of listview is checked/unchecked
+ // CallbackParam is the param passed to listview when adding the item (the one
getting focus now).
+ BOOL ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam);
+
+};
+
+class CSideTreeView :
+ public CUiWindow<CTreeView>
+{
+ HIMAGELIST hImageTreeView;
+
+public:
+ CSideTreeView() :
+ CUiWindow(),
+ hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
+ GetSystemColorDepth() | ILC_MASK,
+ 0, 1))
+ {
+ }
+
+ HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT
SelectedImage, LPARAM lParam)
+ {
+ return CUiWindow<CTreeView>::AddItem(hParent,
const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
+ }
+
+ HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
+ {
+ ATL::CStringW szText;
+ INT Index;
+ HICON hIcon;
+
+ hIcon = (HICON) LoadImageW(hInst,
+ MAKEINTRESOURCE(IconIndex),
+ IMAGE_ICON,
+ TREEVIEW_ICON_SIZE,
+ TREEVIEW_ICON_SIZE,
+ LR_CREATEDIBSECTION);
+ if (hIcon)
+ {
+ Index = ImageList_AddIcon(hImageTreeView, hIcon);
+ DestroyIcon(hIcon);
+ }
+
+ szText.LoadStringW(TextIndex);
+ return AddItem(hRootItem, szText, Index, Index, TextIndex);
+ }
+
+ HIMAGELIST SetImageList()
+ {
+ return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
+ }
+
+ VOID DestroyImageList()
+ {
+ if (hImageTreeView)
+ ImageList_Destroy(hImageTreeView);
+ }
+
+ ~CSideTreeView()
+ {
+ DestroyImageList();
+ }
+};
+
+class CSearchBar :
+ public CWindow
+{
+public:
+ const INT m_Width;
+ const INT m_Height;
+
+ CSearchBar() : m_Width(200), m_Height(22)
+ {
+ }
+
+ VOID SetText(LPCWSTR lpszText)
+ {
+ SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
+ }
+
+ HWND Create(HWND hwndParent)
+ {
+ ATL::CStringW szBuf;
+ m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
+ WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
+ 0, 0, m_Width, m_Height,
+ hwndParent, (HMENU) NULL,
+ hInst, 0);
+
+ SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
+ szBuf.LoadStringW(IDS_SEARCH_TEXT);
+ SetWindowTextW(szBuf);
+ return m_hWnd;
+ }
+
+};
+
+class CMainWindow :
+ public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
+{
+ CUiPanel* m_ClientPanel = NULL;
+ CUiSplitPanel* m_VSplitter = NULL;
+
+ CMainToolbar* m_Toolbar = NULL;
+
+ CSideTreeView* m_TreeView = NULL;
+ CUiWindow<CStatusBar>* m_StatusBar = NULL;
+
+ CApplicationView* m_ApplicationView = NULL;
+
+ CUiWindow<CSearchBar>* m_SearchBar = NULL;
+ CAvailableApps m_AvailableApps;
+ CInstalledApps m_InstalledApps;
+
+ BOOL bSearchEnabled;
+ BOOL bUpdating = FALSE;
+
+ ATL::CStringW szSearchPattern;
+ INT SelectedEnumType;
+
+public:
+ CMainWindow() :
+ m_ClientPanel(NULL),
+ bSearchEnabled(FALSE),
+ SelectedEnumType(ENUM_ALL_INSTALLED)
+ {
+ }
+
+ ~CMainWindow()
+ {
+ LayoutCleanup();
+ }
+private:
+
+ VOID InitCategoriesList()
+ {
+ HTREEITEM hRootItemInstalled, hRootItemAvailable;
+
+ hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED,
IDI_CATEGORY);
+ m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
+ m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
+
m_TreeView->AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST);
hRootItemAvailable = m_TreeView->AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST,
IDI_CATEGORY);
@@ -1601,24 +2082,14 @@ private:
return m_TreeView->Create(m_hWnd) != NULL;
}
- BOOL CreateListView()
+ BOOL CreateApplicationView()
{
- m_ListView = new CAppsListView();
- m_ListView->m_VerticalAlignment = UiAlign_Stretch;
- m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
- m_HSplitter->First().Append(m_ListView);
+ m_ApplicationView = new CApplicationView(this); // pass this to ApplicationView
for callback purpose
+ m_ApplicationView->m_VerticalAlignment = UiAlign_Stretch;
+ m_ApplicationView->m_HorizontalAlignment = UiAlign_Stretch;
+ m_VSplitter->Second().Append(m_ApplicationView);
- return m_ListView->Create(m_hWnd) != NULL;
- }
-
- BOOL CreateRichEdit()
- {
- m_AppInfo = new CAppInfoDisplay();
- m_AppInfo->m_VerticalAlignment = UiAlign_Stretch;
- m_AppInfo->m_HorizontalAlignment = UiAlign_Stretch;
- m_HSplitter->Second().Append(m_AppInfo);
-
- return m_AppInfo->Create(m_hWnd) != NULL;
+ return m_ApplicationView->Create(m_hWnd) != NULL;
}
BOOL CreateVSplitter()
@@ -1636,21 +2107,6 @@ private:
return m_VSplitter->Create(m_hWnd) != NULL;
}
- BOOL CreateHSplitter()
- {
- m_HSplitter = new CUiSplitPanel();
- m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
- m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
- m_HSplitter->m_DynamicFirst = TRUE;
- m_HSplitter->m_Horizontal = TRUE;
- m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position
(m_MinSecond)
- m_HSplitter->m_MinFirst = 10;
- m_HSplitter->m_MinSecond = 140;
- m_VSplitter->Second().Append(m_HSplitter);
-
- return m_HSplitter->Create(m_hWnd) != NULL;
- }
-
BOOL CreateSearchBar()
{
m_SearchBar = new CUiWindow<CSearchBar>();
@@ -1678,12 +2134,8 @@ private:
b = b && CreateVSplitter();
// Inside V Splitter
- b = b && CreateHSplitter();
b = b && CreateTreeView();
-
- // Inside H Splitter
- b = b && CreateListView();
- b = b && CreateRichEdit();
+ b = b && CreateApplicationView();
if (b)
{
@@ -1707,15 +2159,23 @@ private:
return b;
}
+ VOID LayoutCleanup()
+ {
+ delete m_TreeView;
+ delete m_ApplicationView;
+ delete m_VSplitter;
+ delete m_SearchBar;
+ delete m_Toolbar;
+ delete m_StatusBar;
+ return;
+ }
+
BOOL InitControls()
{
if (CreateLayout())
{
-
- InitApplicationsList();
InitCategoriesList();
- nSelectedApps = 0;
UpdateStatusBarText();
return TRUE;
@@ -1724,28 +2184,6 @@ private:
return FALSE;
}
- VOID ShowAppInfo(INT Index)
- {
- if (IsInstalledEnum(SelectedEnumType))
- {
- if (Index == -1)
- Index = m_ListView->GetSelectionMark();
-
- PINSTALLED_INFO Info = (PINSTALLED_INFO) m_ListView->GetItemData(Index);
-
- m_AppInfo->ShowInstalledAppInfo(Info);
- }
- else if (IsAvailableEnum(SelectedEnumType))
- {
- if (Index == -1)
- return;
-
- CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*)
m_ListView->GetItemData(Index);
-
- m_AppInfo->ShowAvailableAppInfo(Info);
- }
- }
-
VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
if (wParam == SIZE_MINIMIZED)
@@ -1782,7 +2220,6 @@ private:
{
EndDeferWindowPos(hdwp);
}
-
}
// TODO: Sub-layouts for children of children
@@ -1796,64 +2233,47 @@ private:
EndDeferWindowPos(hdwp);
}
}
-
}
- VOID RemoveSelectedAppFromRegistry()
+ BOOL RemoveSelectedAppFromRegistry()
{
- PINSTALLED_INFO Info;
- WCHAR szFullName[MAX_PATH] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
- ATL::CStringW szMsgText, szMsgTitle;
- INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
-
if (!IsInstalledEnum(SelectedEnumType))
- return;
+ return FALSE;
- Info =
reinterpret_cast<PINSTALLED_INFO>(m_ListView->GetItemData(ItemIndex));
- if (!Info || !Info->hSubKey || (ItemIndex == -1))
- return;
+ ATL::CStringW szMsgText, szMsgTitle;
if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) ||
!szMsgTitle.LoadStringW(IDS_INFORMATION))
- return;
+ return FALSE;
if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == IDYES)
{
- ATL::CStringW::CopyChars(szFullName,
- MAX_PATH,
- Info->szKeyName.GetString(),
- MAX_PATH - wcslen(szFullName));
-
- if (RegDeleteKeyW(Info->hRootKey, szFullName) == ERROR_SUCCESS)
+ CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo
*)m_ApplicationView->GetFocusedItemData();
+ LSTATUS Result = InstalledApp->RemoveFromRegistry();
+ if (Result != ERROR_SUCCESS)
{
- m_ListView->DeleteItem(ItemIndex);
- return;
+ // TODO: popup a messagebox telling user it fails somehow
+ return FALSE;
}
- if (!szMsgText.LoadStringW(IDS_UNABLE_TO_REMOVE))
- return;
-
- MessageBoxW(szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR);
+ // as it's already removed form registry, this will also remove it from
the list
+ UpdateApplicationsList(-1);
+ return TRUE;
}
+
+ return FALSE;
}
BOOL UninstallSelectedApp(BOOL bModify)
{
- WCHAR szAppName[MAX_STR_LEN];
-
if (!IsInstalledEnum(SelectedEnumType))
return FALSE;
- INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
- if (ItemIndex == -1)
- return FALSE;
-
- m_ListView->GetItemText(ItemIndex, 0, szAppName, _countof(szAppName));
- WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_REMOVE, szAppName);
+ CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo
*)m_ApplicationView->GetFocusedItemData();
- PINSTALLED_INFO ItemInfo =
(PINSTALLED_INFO)m_ListView->GetItemData(ItemIndex);
- return UninstallApplication(ItemInfo, bModify);
+ return InstalledApp->UninstallApplication(bModify);
}
+
BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam,
LRESULT& theResult, DWORD dwMapId)
{
theResult = 0;
@@ -1871,9 +2291,7 @@ private:
FreeLogs();
m_AvailableApps.FreeCachedEntries();
-
- if (IsInstalledEnum(SelectedEnumType))
- FreeInstalledAppList();
+ m_InstalledApps.FreeCachedEntries();
delete m_ClientPanel;
@@ -1984,7 +2402,6 @@ private:
}
HMENU mainMenu = ::GetMenu(hwnd);
- HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
/* Disable/enable items based on treeview selection */
if (IsSelectedNodeInstalled())
@@ -1994,11 +2411,6 @@ private:
EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
- EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
- EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
- EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
- EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
-
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
@@ -2011,11 +2423,6 @@ private:
EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
- EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
- EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
- EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
- EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
-
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
@@ -2024,91 +2431,6 @@ private:
}
break;
- case LVN_ITEMCHANGED:
- {
- LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
-
- if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
- {
- /* Check if this is a valid item
- * (technically, it can be also an unselect) */
- INT ItemIndex = pnic->iItem;
- if (ItemIndex == -1 ||
- ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
- {
- break;
- }
-
- /* Check if the focus has been moved to another item */
- if ((pnic->uChanged & LVIF_STATE) &&
- (pnic->uNewState & LVIS_FOCUSED) &&
- !(pnic->uOldState & LVIS_FOCUSED))
- {
- ShowAppInfo(ItemIndex);
- }
- /* Check if the item is checked */
- if ((pnic->uNewState & LVIS_STATEIMAGEMASK) &&
!bUpdating)
- {
- BOOL checked = m_ListView->GetCheckState(pnic->iItem);
- /* FIXME: HAX!
- - preventing decremention below zero as a safeguard for ReactOS
- In ReactOS this action is triggered whenever user changes
*selection*, but should be only when *checkbox* state toggled
- Maybe LVIS_STATEIMAGEMASK is set incorrectly
- */
- nSelectedApps +=
- (checked)
- ? 1
- : ((nSelectedApps > 0)
- ? -1
- : 0);
-
- /* Update item's selection status */
- m_ListView->SetSelected(pnic->iItem, checked);
-
- UpdateStatusBarText();
- }
- }
- }
- break;
-
- case LVN_COLUMNCLICK:
- {
- LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
-
- m_ListView->ColumnClick(pnmv);
- }
- break;
-
- case NM_CLICK:
- {
- if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW)
lParam)->iItem != -1)
- {
- ShowAppInfo(-1);
- }
- }
- break;
-
- case NM_DBLCLK:
- {
- if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW)
lParam)->iItem != -1)
- {
- /* this won't do anything if the program is already installed */
- SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
- }
- }
- break;
-
- case NM_RCLICK:
- {
- if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW)
lParam)->iItem != -1)
- {
- ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
- }
- }
- break;
-
-
-
case TTN_GETDISPINFO:
m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
break;
@@ -2136,10 +2458,9 @@ private:
case WM_SYSCOLORCHANGE:
{
/* Forward WM_SYSCOLORCHANGE to common controls */
- m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
- m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
+ m_ApplicationView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
+ m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
- m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0,
GetSysColor(COLOR_BTNFACE));
}
break;
@@ -2272,17 +2593,36 @@ private:
case ID_INSTALL:
if (IsAvailableEnum(SelectedEnumType))
{
- if (nSelectedApps > 0)
+ ATL::CSimpleArray<CAvailableApplicationInfo> AppsList;
+
+ // enum all selected apps
+ m_AvailableApps.Enum(ENUM_CAT_SELECTED, s_EnumSelectedAppForDownloadProc,
(PVOID)&AppsList);
+
+ if (AppsList.GetSize())
{
- DownloadListOfApplications(m_AvailableApps.GetSelected(), FALSE);
- UpdateApplicationsList(-1);
- m_ListView->SetSelected(-1, FALSE);
+ if (DownloadListOfApplications(AppsList, FALSE))
+ {
+ m_AvailableApps.RemoveAllSelected();
+ UpdateApplicationsList(-1);
+ }
}
- else if (DownloadApplication(m_ListView->GetSelectedData(), FALSE))
+ else
{
- UpdateApplicationsList(-1);
+ // use the currently focused item in application-view
+ CAvailableApplicationInfo *FocusedApps = (CAvailableApplicationInfo
*)m_ApplicationView->GetFocusedItemData();
+ if (FocusedApps)
+ {
+ if (DownloadApplication(FocusedApps, FALSE))
+ {
+ UpdateApplicationsList(-1);
+ }
+ }
+ else
+ {
+ // TODO: in this case, Install button in toolbar (and all other
places) should be disabled
+ // or at least popup a messagebox telling user to select/check
some app first
+ }
}
-
}
break;
@@ -2318,28 +2658,11 @@ private:
break;
case ID_CHECK_ALL:
- m_ListView->CheckAll();
+ m_ApplicationView->CheckAll();
break;
}
}
- VOID FreeInstalledAppList()
- {
- INT Count = m_ListView->GetItemCount() - 1;
- PINSTALLED_INFO Info;
-
- while (Count >= 0)
- {
- Info = (PINSTALLED_INFO) m_ListView->GetItemData(Count);
- if (Info)
- {
- RegCloseKey(Info->hSubKey);
- delete Info;
- }
- Count--;
- }
- }
-
static BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
{
if (!*szNeedle)
@@ -2348,91 +2671,42 @@ private:
return StrStrIW(szHaystack, szNeedle) != NULL;
}
- BOOL CALLBACK EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName,
PINSTALLED_INFO Info)
+ BOOL CALLBACK EnumInstalledAppProc(CInstalledApplicationInfo * Info)
{
- PINSTALLED_INFO ItemInfo;
- ATL::CStringW szText;
- INT Index;
-
- if (!SearchPatternMatch(m_szName.GetString(), szSearchPattern))
+ if (!SearchPatternMatch(Info->szDisplayName.GetString(), szSearchPattern))
{
- RegCloseKey(Info->hSubKey);
return TRUE;
}
-
- ItemInfo = new INSTALLED_INFO(*Info);
- if (!ItemInfo)
- {
- RegCloseKey(Info->hSubKey);
- return FALSE;
- }
-
- Index = m_ListView->AddItem(ItemIndex, 0, m_szName.GetString(), (LPARAM)
ItemInfo);
-
- /* Get version info */
- ItemInfo->GetApplicationString(L"DisplayVersion", szText);
- m_ListView->SetItemText(Index, 1, szText.GetString());
-
- /* Get comments */
- ItemInfo->GetApplicationString(L"Comments", szText);
- m_ListView->SetItemText(Index, 2, szText.GetString());
-
- return TRUE;
+ return m_ApplicationView->AddInstalledApplication(Info, Info); // currently,
the callback param is Info itself
}
- BOOL EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath)
+ BOOL CALLBACK EnumAvailableAppProc(CAvailableApplicationInfo * Info, BOOL
bInitialCheckState)
{
- INT Index;
- HICON hIcon = NULL;
-
- HIMAGELIST hImageListView =
(HIMAGELIST)m_ListView->SendMessage(LVM_GETIMAGELIST, LVSIL_SMALL, 0);
-
if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern)
&&
!SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
{
return TRUE;
}
-
- /* Load icon from file */
- ATL::CStringW szIconPath;
- if (Info->RetrieveIcon(szIconPath))
- {
- hIcon = (HICON)LoadImageW(NULL,
- szIconPath.GetString(),
- IMAGE_ICON,
- LISTVIEW_ICON_SIZE,
- LISTVIEW_ICON_SIZE,
- LR_LOADFROMFILE);
- }
-
- if (!hIcon || GetLastError() != ERROR_SUCCESS)
- {
- /* Load default icon */
- hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
- }
-
- Index = ImageList_AddIcon(hImageListView, hIcon);
- DestroyIcon(hIcon);
-
- Index = m_ListView->AddItem(Info->m_Category, Index,
Info->m_szName.GetString(), (LPARAM) Info);
- m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
- m_ListView->SetItemText(Index, 1, Info->m_szVersion.GetString());
- m_ListView->SetItemText(Index, 2, Info->m_szDesc.GetString());
- m_ListView->SetCheckState(Index, Info->m_IsSelected);
-
- return TRUE;
+ return m_ApplicationView->AddAvailableApplication(Info, bInitialCheckState,
Info); // currently, the callback param is Info itself
}
- static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW
&m_szName, PINSTALLED_INFO Info, PVOID param)
+ static BOOL CALLBACK s_EnumInstalledAppProc(CInstalledApplicationInfo * Info, PVOID
param)
{
CMainWindow* pThis = (CMainWindow*)param;
- return pThis->EnumInstalledAppProc(ItemIndex, m_szName, Info);
+ return pThis->EnumInstalledAppProc(Info);
}
- static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR
szFolderPath, PVOID param)
+ static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* Info, BOOL
bInitialCheckState, PVOID param)
{
CMainWindow* pThis = (CMainWindow*)param;
- return pThis->EnumAvailableAppProc(Info, szFolderPath);
+ return pThis->EnumAvailableAppProc(Info, bInitialCheckState);
+ }
+
+ static BOOL CALLBACK s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo
*Info, BOOL bInitialCheckState, PVOID param)
+ {
+ ATL::CSimpleArray<CAvailableApplicationInfo> *pAppList =
(ATL::CSimpleArray<CAvailableApplicationInfo> *)param;
+ pAppList->Add(*Info);
+ return TRUE;
}
VOID UpdateStatusBarText()
@@ -2441,83 +2715,46 @@ private:
{
ATL::CStringW szBuffer;
- szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(),
nSelectedApps);
+ szBuffer.Format(IDS_APPS_COUNT, m_ApplicationView->GetItemCount(),
m_AvailableApps.GetSelectedCount());
m_StatusBar->SetText(szBuffer);
}
}
VOID UpdateApplicationsList(INT EnumType)
{
- ATL::CStringW szBuffer1, szBuffer2;
- HIMAGELIST hImageListView;
- BOOL bWasInInstalled = IsInstalledEnum(SelectedEnumType);
-
bUpdating = TRUE;
- m_ListView->SetRedraw(FALSE);
- if (EnumType < 0)
+ if (EnumType == -1)
{
+ // keep the old enum type
EnumType = SelectedEnumType;
}
-
- //if previous one was INSTALLED purge the list
- //TODO: make the Installed category a separate class to avoid doing this
- if (bWasInInstalled)
- {
- FreeInstalledAppList();
- }
-
- m_ListView->DeleteAllItems();
-
- // Create new ImageList
- hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
- LISTVIEW_ICON_SIZE,
- GetSystemColorDepth() | ILC_MASK,
- 0, 1);
- HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView,
LVSIL_SMALL);
- if (hImageListBuf)
+ else
{
- ImageList_Destroy(hImageListBuf);
+ SelectedEnumType = EnumType;
}
+ m_ApplicationView->SetRedraw(FALSE);
if (IsInstalledEnum(EnumType))
{
- if (!bWasInInstalled)
- {
- m_ListView->SetCheckboxesVisible(FALSE);
- }
+ // set the display mode of application-view. this will remove all the item in
application-view too.
+ m_ApplicationView->SetDisplayMode(ApplicationViewInstalledApps);
- HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
- ImageList_AddIcon(hImageListView, hIcon);
- DestroyIcon(hIcon);
-
- // Enum installed applications and updates
- EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc, this);
- EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc, this);
+ // enum installed softwares
+ m_InstalledApps.Enum(EnumType, s_EnumInstalledAppProc, this);
}
else if (IsAvailableEnum(EnumType))
{
- if (bWasInInstalled)
- {
- m_ListView->SetCheckboxesVisible(TRUE);
- }
+ // set the display mode of application-view. this will remove all the item in
application-view too.
+ m_ApplicationView->SetDisplayMode(ApplicationViewAvailableApps);
- // Enum available applications
+ // enum available softwares
m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
}
-
- SelectedEnumType = EnumType;
+ m_ApplicationView->SetRedraw(TRUE);
+ m_ApplicationView->RedrawWindow(0, 0, RDW_INVALIDATE | RDW_ALLCHILDREN); //
force the child window to repaint
UpdateStatusBarText();
- m_AppInfo->SetWelcomeText();
-
- // Set automatic column width for program names if the list is not empty
- if (m_ListView->GetItemCount() > 0)
- {
- ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
- }
-
bUpdating = FALSE;
- m_ListView->SetRedraw(TRUE);
}
public:
@@ -2562,9 +2799,39 @@ public:
return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
}
+ // this function is called when a item of application-view is checked/unchecked
+ // CallbackParam is the param passed to application-view when adding the item (the
one getting focus now).
+ BOOL ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
+ {
+ if (!bUpdating)
+ {
+ if (bChecked)
+ {
+ if (!m_AvailableApps.AddSelected((CAvailableApplicationInfo
*)CallbackParam))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!m_AvailableApps.RemoveSelected((CAvailableApplicationInfo
*)CallbackParam))
+ {
+ return FALSE;
+ }
+ }
+
+ UpdateStatusBarText();
+ return TRUE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
void HandleTabOrder(int direction)
{
- HWND Controls[] = { m_Toolbar->m_hWnd, m_SearchBar->m_hWnd,
m_TreeView->m_hWnd, m_ListView->m_hWnd, m_AppInfo->m_hWnd };
+ HWND Controls[] = { m_Toolbar->m_hWnd, m_SearchBar->m_hWnd,
m_TreeView->m_hWnd, m_ApplicationView->m_hWnd};
// When there is no control found, go to the first or last (depending on tab vs
shift-tab)
int current = direction > 0 ? 0 : (_countof(Controls) - 1);
HWND hActive = ::GetFocus();
@@ -2586,6 +2853,12 @@ public:
}
};
+BOOL CApplicationView::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
+{
+ m_MainWindow->ItemCheckStateChanged(bChecked, CallbackParam);
+ return TRUE;
+}
+
VOID ShowMainWindow(INT nShowCmd)
{
HACCEL KeyBrd;
diff --git a/base/applications/rapps/include/available.h
b/base/applications/rapps/include/available.h
index 259b644dce1..2ee8136cc91 100644
--- a/base/applications/rapps/include/available.h
+++ b/base/applications/rapps/include/available.h
@@ -37,10 +37,11 @@ struct AvailableStrings
AvailableStrings();
};
-struct CAvailableApplicationInfo
+class CAvailableApplicationInfo
{
+public:
INT m_Category;
- BOOL m_IsSelected;
+ //BOOL m_IsSelected;
LicenseType m_LicenseType;
ATL::CStringW m_szName;
ATL::CStringW m_szRegName;
@@ -98,11 +99,12 @@ private:
inline BOOL FindInLanguages(LCID what) const;
};
-typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR
szFolderPath, PVOID param);
+typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, BOOL
bInitialCheckState, PVOID param);
class CAvailableApps
{
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
+ ATL::CAtlList< CAvailableApplicationInfo*> m_SelectedList;
public:
static AvailableStrings m_Strings;
@@ -116,9 +118,15 @@ public:
VOID FreeCachedEntries();
BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param);
+ BOOL AddSelected(CAvailableApplicationInfo *AvlbInfo);
+ BOOL RemoveSelected(CAvailableApplicationInfo *AvlbInfo);
+
+ VOID RemoveAllSelected();
+ int GetSelectedCount();
+
CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const;
ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const
ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const;
- ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
+ //ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
const ATL::CStringW& GetFolderPath() const;
const ATL::CStringW& GetAppPath() const;
diff --git a/base/applications/rapps/include/installed.h
b/base/applications/rapps/include/installed.h
index 76a12418c1c..f13e37e1b48 100644
--- a/base/applications/rapps/include/installed.h
+++ b/base/applications/rapps/include/installed.h
@@ -3,19 +3,51 @@
#include <windef.h>
#include <atlstr.h>
-struct INSTALLED_INFO
+class CInstalledApplicationInfo
{
- HKEY hRootKey;
+public:
+ BOOL IsUserKey;
+ REGSAM WowKey;
HKEY hSubKey;
+ BOOL bIsUpdate = FALSE;
+
ATL::CStringW szKeyName;
+ CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey);
BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String);
+ BOOL UninstallApplication(BOOL bModify);
+ LSTATUS RemoveFromRegistry();
+
+ ATL::CStringW szDisplayName;
+ ATL::CStringW szDisplayVersion;
+ ATL::CStringW szPublisher;
+ ATL::CStringW szRegOwner;
+ ATL::CStringW szProductID;
+ ATL::CStringW szHelpLink;
+ ATL::CStringW szHelpTelephone;
+ ATL::CStringW szReadme;
+ ATL::CStringW szContact;
+ ATL::CStringW szURLUpdateInfo;
+ ATL::CStringW szURLInfoAbout;
+ ATL::CStringW szComments;
+ ATL::CStringW szInstallDate;
+ ATL::CStringW szInstallLocation;
+ ATL::CStringW szInstallSource;
+ ATL::CStringW szUninstallString;
+ ATL::CStringW szModifyPath;
+
+ ~CInstalledApplicationInfo();
};
-typedef INSTALLED_INFO *PINSTALLED_INFO;
-typedef BOOL(CALLBACK *APPENUMPROC)(INT ItemIndex, ATL::CStringW &Name,
PINSTALLED_INFO Info, PVOID param);
+typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID param);
-BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc,
PVOID param);
-BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString);
+class CInstalledApps
+{
+ ATL::CAtlList<CInstalledApplicationInfo *> m_InfoList;
+
+public:
+ BOOL Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param);
+
+ VOID FreeCachedEntries();
+};
-BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify);
diff --git a/base/applications/rapps/include/misc.h
b/base/applications/rapps/include/misc.h
index 4c1fc6a4b1d..7e3b1567b65 100644
--- a/base/applications/rapps/include/misc.h
+++ b/base/applications/rapps/include/misc.h
@@ -46,3 +46,5 @@ public:
};
BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore);
+
+BOOL IsSystem64Bit();
diff --git a/base/applications/rapps/include/rosui.h
b/base/applications/rapps/include/rosui.h
index 378e677c053..19ba8d26f0d 100644
--- a/base/applications/rapps/include/rosui.h
+++ b/base/applications/rapps/include/rosui.h
@@ -495,7 +495,10 @@ public:
virtual ~CUiWindow()
{
- T::DestroyWindow();
+ if (T::IsWindow())
+ {
+ T::DestroyWindow();
+ }
}
VOID GetWindowTextW(ATL::CStringW& szText)
diff --git a/base/applications/rapps/installed.cpp
b/base/applications/rapps/installed.cpp
index c35f141f526..065422762ad 100644
--- a/base/applications/rapps/installed.cpp
+++ b/base/applications/rapps/installed.cpp
@@ -12,149 +12,253 @@
#include "misc.h"
-BOOL INSTALLED_INFO::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String)
+CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey,
HKEY hKey)
+ : IsUserKey(bIsUserKey), WowKey(RegWowKey), hSubKey(hKey)
{
- BOOL result = ::GetApplicationString(hSubKey, lpKeyName,
String.GetBuffer(MAX_PATH));
- String.ReleaseBuffer();
- return result;
+ // if Initialize failed, hSubKey will be closed automatically and set to zero
+
+ DWORD dwSize = MAX_PATH, dwType, dwValue;
+ BOOL bIsSystemComponent;
+ ATL::CStringW szParentKeyName;
+
+ dwType = REG_DWORD;
+ dwSize = sizeof(DWORD);
+
+ if (RegQueryValueExW(hSubKey,
+ L"SystemComponent",
+ NULL,
+ &dwType,
+ (LPBYTE)&dwValue,
+ &dwSize) == ERROR_SUCCESS)
+ {
+ bIsSystemComponent = (dwValue == 0x1);
+ }
+ else
+ {
+ bIsSystemComponent = FALSE;
+ }
+
+ dwType = REG_SZ;
+ dwSize = MAX_PATH * sizeof(WCHAR);
+ bIsUpdate = (RegQueryValueExW(hSubKey,
+ L"ParentKeyName",
+ NULL,
+ &dwType,
+ (LPBYTE)szParentKeyName.GetBuffer(MAX_PATH),
+ &dwSize) == ERROR_SUCCESS);
+ szParentKeyName.ReleaseBuffer();
+
+ if (bIsSystemComponent)
+ {
+ CloseHandle(hSubKey);
+ hSubKey = NULL;
+ }
+
}
-BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString)
+CInstalledApplicationInfo::~CInstalledApplicationInfo()
{
- DWORD dwSize = MAX_PATH * sizeof(WCHAR);
-
- if (RegQueryValueExW(hKey,
- lpKeyName,
- NULL,
- NULL,
- (LPBYTE) szString,
- &dwSize) == ERROR_SUCCESS)
+ if (hSubKey)
{
- return TRUE;
+ CloseHandle(hSubKey);
+ hSubKey = NULL;
}
-
- StringCchCopyW(szString, MAX_PATH, L"---");
- return FALSE;
}
-BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify)
+BOOL CInstalledApplicationInfo::GetApplicationString(LPCWSTR lpKeyName,
ATL::CStringW& String)
{
- LPCWSTR szModify = L"ModifyPath";
- LPCWSTR szUninstall = L"UninstallString";
- DWORD dwType, dwSize;
- WCHAR szPath[MAX_PATH];
+ DWORD dwSize = 0;
+ String.Empty();
+ DWORD dwType;
- dwType = REG_SZ;
- dwSize = MAX_PATH * sizeof(WCHAR);
- if (RegQueryValueExW(ItemInfo->hSubKey,
- bModify ? szModify : szUninstall,
- NULL,
- &dwType,
- (LPBYTE) szPath,
- &dwSize) != ERROR_SUCCESS)
+ // retrieve the size of value first.
+ if (RegQueryValueExW(hSubKey,
+ lpKeyName,
+ NULL,
+ &dwType,
+ NULL,
+ &dwSize) != ERROR_SUCCESS)
{
return FALSE;
}
- return StartProcess(szPath, TRUE);
+ // TODO: I assume the type as REG_SZ. but I think REG_EXPAND_SZ should be handled
correctly too.
+ if (dwType != REG_SZ)
+ {
+ return FALSE;
+ }
+
+ // allocate buffer.
+ // attention: dwSize is size in bytes, and RegQueryValueExW does not guarantee the
terminating null character.
+ String.GetBuffer(dwSize + sizeof(WCHAR));
+
+ // query the value
+ if (RegQueryValueExW(hSubKey,
+ lpKeyName,
+ NULL,
+ NULL,
+ (LPBYTE)String.GetBuffer(),
+ &dwSize) != ERROR_SUCCESS)
+ {
+ String.ReleaseBuffer();
+ String.Empty();
+ return FALSE;
+ }
+ String.GetBuffer()[dwSize / sizeof(WCHAR)] = L'\0'; // ensure zero
terminated
+ String.ReleaseBuffer();
+ return TRUE;
}
-BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc,
PVOID param)
+BOOL CInstalledApplicationInfo::UninstallApplication(BOOL bModify)
{
- DWORD dwSize = MAX_PATH, dwType, dwValue;
- BOOL bIsSystemComponent, bIsUpdate;
- ATL::CStringW szParentKeyName;
- ATL::CStringW szDisplayName;
- INSTALLED_INFO Info;
- HKEY hKey;
- LONG ItemIndex = 0;
+ return StartProcess(bModify ? szModifyPath : szUninstallString, TRUE);
+}
+
+LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
+{
+ ATL::CStringW szFullName =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + szKeyName;
- Info.hRootKey = IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+ // TODO: if there are subkeys inside, simply RegDeleteKeyExW will fail
+ // we don't have RegDeleteTree for ReactOS now. (It's a WinVista API)
+ // write a function to delete all subkeys recursively to solve this
+ // or consider letting ReactOS having this API
- if (RegOpenKeyW(Info.hRootKey,
-
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
- &hKey) != ERROR_SUCCESS)
+ return RegDeleteKeyExW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
szFullName, WowKey, 0);
+}
+
+BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
+{
+ FreeCachedEntries();
+
+ HKEY RootKeyEnum[3] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE
};
+ REGSAM RegSamEnum[3] = { KEY_WOW64_32KEY, KEY_WOW64_32KEY, KEY_WOW64_64KEY
};
+
+ int LoopTime;
+
+ // test if the OS is 64 bit.
+ if (IsSystem64Bit())
{
- return FALSE;
+ // loop for all 3 combination.
+ // note that HKEY_CURRENT_USER\Software don't have a redirect
+ //
https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-ke…
+ LoopTime = 3;
+ }
+ else
+ {
+ // loop for 2 combination for KEY_WOW64_32KEY only
+ LoopTime = 2;
}
- while (RegEnumKeyExW(hKey, ItemIndex, Info.szKeyName.GetBuffer(MAX_PATH),
&dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+ // loop for all combination
+ for (int i = 0; i < LoopTime; i++)
{
- Info.szKeyName.ReleaseBuffer();
- if (RegOpenKeyW(hKey, Info.szKeyName.GetString(), &Info.hSubKey) ==
ERROR_SUCCESS)
+ DWORD dwSize = MAX_PATH;
+ HKEY hKey, hSubKey;
+ LONG ItemIndex = 0;
+ ATL::CStringW szKeyName;
+
+ if (RegOpenKeyExW(RootKeyEnum[i],
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
+ NULL,
+ KEY_READ | RegSamEnum[i],
+ &hKey) != ERROR_SUCCESS)
{
- dwType = REG_DWORD;
- dwSize = sizeof(DWORD);
-
- if (RegQueryValueExW(Info.hSubKey,
- L"SystemComponent",
- NULL,
- &dwType,
- (LPBYTE) &dwValue,
- &dwSize) == ERROR_SUCCESS)
- {
- bIsSystemComponent = (dwValue == 0x1);
- }
- else
+ return FALSE;
+ }
+
+ while (1)
+ {
+ dwSize = MAX_PATH;
+ if (RegEnumKeyExW(hKey, ItemIndex, szKeyName.GetBuffer(MAX_PATH),
&dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{
- bIsSystemComponent = FALSE;
+ break;
}
- dwType = REG_SZ;
- dwSize = MAX_PATH * sizeof(WCHAR);
- bIsUpdate = (RegQueryValueExW(Info.hSubKey,
- L"ParentKeyName",
- NULL,
- &dwType,
- (LPBYTE) szParentKeyName.GetBuffer(MAX_PATH),
- &dwSize) == ERROR_SUCCESS);
- szParentKeyName.ReleaseBuffer();
-
- dwType = REG_SZ;
- dwSize = MAX_PATH * sizeof(WCHAR);
- if (RegQueryValueExW(Info.hSubKey,
- L"DisplayName",
- NULL,
- &dwType,
- (LPBYTE) szDisplayName.GetBuffer(MAX_PATH),
- &dwSize) == ERROR_SUCCESS)
+ ItemIndex++;
+
+ szKeyName.ReleaseBuffer();
+ if (RegOpenKeyW(hKey, szKeyName.GetString(), &hSubKey) == ERROR_SUCCESS)
{
- szDisplayName.ReleaseBuffer();
- if (EnumType < ENUM_ALL_INSTALLED || EnumType > ENUM_UPDATES)
- EnumType = ENUM_ALL_INSTALLED;
+ BOOL bSuccess = FALSE;
+ CInstalledApplicationInfo *Info = new
CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], hSubKey);
+ Info->szKeyName = szKeyName;
- if (!bIsSystemComponent)
+ // check for failure. if failed to init, Info->hSubKey will be set to
NULL
+ if (Info->hSubKey)
{
- if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */
- ((EnumType == ENUM_INSTALLED_APPLICATIONS) &&
(!bIsUpdate)) || /* Applications only */
- ((EnumType == ENUM_UPDATES) && (bIsUpdate))) /* Updates
only */
+ // those items without display name are ignored
+ if (Info->GetApplicationString(L"DisplayName",
Info->szDisplayName))
{
- if (!lpEnumProc(ItemIndex, szDisplayName, &Info, param))
- break;
+ Info->GetApplicationString(L"DisplayVersion",
Info->szDisplayVersion);
+ Info->GetApplicationString(L"Publisher",
Info->szPublisher);
+ Info->GetApplicationString(L"RegOwner",
Info->szRegOwner);
+ Info->GetApplicationString(L"ProductID",
Info->szProductID);
+ Info->GetApplicationString(L"HelpLink",
Info->szHelpLink);
+ Info->GetApplicationString(L"HelpTelephone",
Info->szHelpTelephone);
+ Info->GetApplicationString(L"Readme",
Info->szReadme);
+ Info->GetApplicationString(L"Contact",
Info->szContact);
+ Info->GetApplicationString(L"URLUpdateInfo",
Info->szURLUpdateInfo);
+ Info->GetApplicationString(L"URLInfoAbout",
Info->szURLInfoAbout);
+ Info->GetApplicationString(L"Comments",
Info->szComments);
+ Info->GetApplicationString(L"InstallDate",
Info->szInstallDate);
+ Info->GetApplicationString(L"InstallLocation",
Info->szInstallLocation);
+ Info->GetApplicationString(L"InstallSource",
Info->szInstallSource);
+ Info->GetApplicationString(L"UninstallString",
Info->szUninstallString);
+ Info->GetApplicationString(L"ModifyPath",
Info->szModifyPath);
+
+ bSuccess = TRUE;
}
- else
+ }
+
+ // close handle
+ if (Info->hSubKey)
+ {
+ CloseHandle(Info->hSubKey);
+ Info->hSubKey = NULL;
+ }
+
+ if (bSuccess)
+ {
+ // add to InfoList.
+ m_InfoList.AddTail(Info);
+
+ // invoke callback
+ if (lpEnumProc)
{
- RegCloseKey(Info.hSubKey);
+ if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */
+ ((EnumType == ENUM_INSTALLED_APPLICATIONS) &&
(!Info->bIsUpdate)) || /* Applications only */
+ ((EnumType == ENUM_UPDATES) && (Info->bIsUpdate)))
/* Updates only */
+ {
+ lpEnumProc(Info, param);
+ }
}
}
else
{
- RegCloseKey(Info.hSubKey);
+ // destory object
+ delete Info;
}
}
- else
- {
- szDisplayName.ReleaseBuffer();
- RegCloseKey(Info.hSubKey);
- }
}
- dwSize = MAX_PATH;
- ItemIndex++;
+ szKeyName.ReleaseBuffer();
+ RegCloseKey(hKey);
}
-
- Info.szKeyName.ReleaseBuffer();
- RegCloseKey(hKey);
+
return TRUE;
}
+
+VOID CInstalledApps::FreeCachedEntries()
+{
+ POSITION InfoListPosition = m_InfoList.GetHeadPosition();
+
+ /* loop and deallocate all the cached app infos in the list */
+ while (InfoListPosition)
+ {
+ CInstalledApplicationInfo *Info = m_InfoList.GetNext(InfoListPosition);
+ delete Info;
+ }
+
+ m_InfoList.RemoveAll();
+}
diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp
index 8e164db8648..90f4e88cd3c 100644
--- a/base/applications/rapps/misc.cpp
+++ b/base/applications/rapps/misc.cpp
@@ -13,6 +13,9 @@
static HANDLE hLog = NULL;
+static BOOL bIsSys64ResultCached = FALSE;
+static BOOL bIsSys64Result = FALSE;
+
INT GetWindowWidth(HWND hwnd)
{
RECT Rect;
@@ -453,3 +456,33 @@ BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore)
return TRUE;
}
+
+
+
+BOOL IsSystem64Bit()
+{
+ if (bIsSys64ResultCached)
+ {
+ // just return cached result
+ return bIsSys64Result;
+ }
+
+ SYSTEM_INFO si;
+ typedef void (WINAPI *LPFN_PGNSI)(LPSYSTEM_INFO);
+ LPFN_PGNSI pGetNativeSystemInfo =
(LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"GetNativeSystemInfo");
+ if (pGetNativeSystemInfo)
+ {
+ pGetNativeSystemInfo(&si);
+ if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ {
+ bIsSys64Result = TRUE;
+ }
+ }
+ else
+ {
+ bIsSys64Result = FALSE;
+ }
+
+ bIsSys64ResultCached = TRUE; // next time calling this function, it will directly
return bIsSys64Result
+ return bIsSys64Result;
+}