837 lines
22 KiB
C++
837 lines
22 KiB
C++
|
#include "private.h"
|
||
|
#include "offline.h"
|
||
|
#include "updateui.h"
|
||
|
|
||
|
//xnotfmgr - most of this file can probably get nuked
|
||
|
|
||
|
#define MAX_CAPTION 128
|
||
|
|
||
|
#undef TF_THISMODULE
|
||
|
#define TF_THISMODULE TF_UPDATEAGENT
|
||
|
|
||
|
typedef CLSID COOKIE, *PCOOKIE;
|
||
|
|
||
|
#define SUBITEM_SIZE 4
|
||
|
#define SUBITEM_URL 3
|
||
|
#define SUBITEM_STATUS 2
|
||
|
#define SUBITEM_IMAGE 1
|
||
|
|
||
|
ColInfoType colDlg[] = {
|
||
|
{0, IDS_NAME_COL, 30, LVCFMT_LEFT},
|
||
|
{1, 0, 3, LVCFMT_LEFT},
|
||
|
{2, IDS_STATUS_COL, 10, LVCFMT_LEFT},
|
||
|
{3, IDS_URL_COL, 40, LVCFMT_LEFT},
|
||
|
{4, IDS_SIZE_COL, 7, LVCFMT_RIGHT}
|
||
|
};
|
||
|
|
||
|
#define ILI_SUCCEEDED 0
|
||
|
#define ILI_FAILED 1
|
||
|
#define ILI_UPDATING 2
|
||
|
#define ILI_PENDING 3
|
||
|
#define ILI_SKIPPED 4
|
||
|
#define ILI_SITE 5
|
||
|
#define ILI_CHANNEL 6
|
||
|
#define ILI_DESKTOP 7
|
||
|
|
||
|
const int g_aIconResourceID[] = {
|
||
|
IDI_STAT_SUCCEEDED,
|
||
|
IDI_STAT_FAILED,
|
||
|
IDI_STAT_UPDATING,
|
||
|
IDI_STAT_PENDING,
|
||
|
IDI_STAT_SKIPPED,
|
||
|
IDI_WEBDOC,
|
||
|
IDI_CHANNEL,
|
||
|
IDI_DESKTOPITEM
|
||
|
};
|
||
|
|
||
|
#define MAX_DLG_COL ARRAYSIZE(colDlg)
|
||
|
|
||
|
//struct for saving window state in registry
|
||
|
typedef struct _PROG_PERSIST_STATE
|
||
|
{
|
||
|
short cbSize;
|
||
|
char bDetails;
|
||
|
char bAdjustWindowPos;
|
||
|
RECT rWindow;
|
||
|
int colOrder [MAX_DLG_COL];
|
||
|
int colWidth [MAX_DLG_COL];
|
||
|
} PROG_PERSIST_STATE;
|
||
|
extern void ResizeDialog(HWND hDlg, BOOL bShowDetail); //in update.cpp
|
||
|
|
||
|
const TCHAR c_szProgressWindowSettings[] = TEXT("Progress Preferences");
|
||
|
|
||
|
const UINT CookieSeg = 32;
|
||
|
|
||
|
CCookieItemMap::CCookieItemMap()
|
||
|
{
|
||
|
_map = NULL;
|
||
|
}
|
||
|
|
||
|
CCookieItemMap::~CCookieItemMap()
|
||
|
{
|
||
|
SAFELOCALFREE (_map);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::Init(UINT size)
|
||
|
{
|
||
|
// Free old junk.
|
||
|
SAFELOCALFREE (_map);
|
||
|
|
||
|
_lParamNext = 0;
|
||
|
_count = 0;
|
||
|
|
||
|
if (size == 0)
|
||
|
_capacity = CookieSeg;
|
||
|
else
|
||
|
_capacity = size;
|
||
|
|
||
|
|
||
|
_map = (CookieItemMapEntry * )MemAlloc(LPTR, sizeof (CookieItemMapEntry) * _capacity);
|
||
|
if (!_map) {
|
||
|
DBG("Failed to allocate memory");
|
||
|
_capacity = 0;
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::ResetMap(void)
|
||
|
{
|
||
|
_count = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::FindCookie(LPARAM lParam, CLSID * pCookie)
|
||
|
{
|
||
|
ASSERT(pCookie);
|
||
|
|
||
|
UINT i;
|
||
|
for (i = 0; i < _count; i ++) {
|
||
|
if (_map[i]._id == lParam) {
|
||
|
* pCookie = _map[i]._cookie;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pCookie = CLSID_NULL;
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::FindLParam(CLSID * pCookie, LPARAM * pLParam)
|
||
|
{
|
||
|
ASSERT(pCookie && pLParam);
|
||
|
|
||
|
UINT i;
|
||
|
for (i = 0; i < _count; i ++) {
|
||
|
if (_map[i]._cookie == *pCookie) {
|
||
|
* pLParam = _map[i]._id;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pLParam = (LPARAM)-1;
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::AddCookie(CLSID * pCookie, LPARAM * pLParam)
|
||
|
{
|
||
|
HRESULT hr = FindLParam(pCookie, pLParam);
|
||
|
if (S_OK == hr)
|
||
|
return S_FALSE;
|
||
|
|
||
|
ASSERT(_count <= _capacity);
|
||
|
ASSERT(CookieSeg);
|
||
|
|
||
|
if (_count == _capacity) {
|
||
|
UINT newSize = CookieSeg + _capacity;
|
||
|
void * newBuf = MemReAlloc(_map, newSize * sizeof(CookieItemMapEntry), LHND);
|
||
|
|
||
|
if (!newBuf) {
|
||
|
DBG("AddCookie::Failed to reallocate buffer");
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
_map = (CookieItemMapEntry *)newBuf;
|
||
|
_capacity = newSize;
|
||
|
}
|
||
|
|
||
|
_map[_count]._cookie = *pCookie;
|
||
|
_map[_count]._id = _lParamNext;
|
||
|
_count ++;
|
||
|
|
||
|
*pLParam = _lParamNext;
|
||
|
_lParamNext ++;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CCookieItemMap::DelCookie(CLSID * pCookie)
|
||
|
{
|
||
|
ASSERT(pCookie);
|
||
|
|
||
|
UINT i;
|
||
|
for (i = 0; i < _count; i ++) {
|
||
|
if (_map[i]._cookie == *pCookie) {
|
||
|
if (i == (_count - 1)) {
|
||
|
_count --;
|
||
|
return S_OK;
|
||
|
} else {
|
||
|
_count --;
|
||
|
_map[i]._cookie = _map[_count]._cookie;
|
||
|
_map[i]._id = _map[_count]._id;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Other members
|
||
|
//
|
||
|
|
||
|
int CALLBACK CUpdateDialog::SortUpdatingToTop (LPARAM lParam1,
|
||
|
LPARAM lParam2,
|
||
|
LPARAM lParamSort)
|
||
|
{
|
||
|
//lparams are cookies; lparamsort is source object
|
||
|
CUpdateDialog * pUpdater = (CUpdateDialog*)lParamSort;
|
||
|
if (!pUpdater)
|
||
|
return 0;
|
||
|
if (!pUpdater->m_pController)
|
||
|
return 0;
|
||
|
|
||
|
CLSID cookie;
|
||
|
pUpdater->cookieMap.FindCookie (lParam1, &cookie);
|
||
|
PReportMap pEntry1 = pUpdater->m_pController->FindReportEntry (&cookie);
|
||
|
pUpdater->cookieMap.FindCookie (lParam2, &cookie);
|
||
|
PReportMap pEntry2 = pUpdater->m_pController->FindReportEntry (&cookie);
|
||
|
|
||
|
//in progress precedes all else
|
||
|
if (pEntry1->status == ITEM_STAT_UPDATING)
|
||
|
return (pEntry2->status == ITEM_STAT_UPDATING ? 0 : -1);
|
||
|
|
||
|
if (pEntry2->status == ITEM_STAT_UPDATING)
|
||
|
return 1;
|
||
|
|
||
|
//queued precedes succeeded or skipped
|
||
|
if (pEntry1->status == ITEM_STAT_QUEUED || pEntry1->status == ITEM_STAT_PENDING)
|
||
|
return ((pEntry2->status == ITEM_STAT_QUEUED
|
||
|
|| pEntry2->status == ITEM_STAT_PENDING) ? 0 : -1);
|
||
|
|
||
|
if (pEntry2->status == ITEM_STAT_QUEUED || pEntry2->status == ITEM_STAT_PENDING)
|
||
|
return 1;
|
||
|
|
||
|
return 0; //don't care
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CUpdateDialog::SelectFirstUpdatingSubscription()
|
||
|
{
|
||
|
LV_ITEM lvi = {0};
|
||
|
lvi.iSubItem = SUBITEM_IMAGE;
|
||
|
lvi.mask = LVIF_IMAGE;
|
||
|
|
||
|
int cItems = ListView_GetItemCount (m_hLV);
|
||
|
for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++)
|
||
|
{
|
||
|
ListView_GetItem (m_hLV, &lvi);
|
||
|
if (lvi.iImage == ILI_UPDATING)
|
||
|
{
|
||
|
ListView_SetItemState (m_hLV, lvi.iItem, LVIS_SELECTED, LVIS_SELECTED);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD CUpdateDialog::SetSiteDownloadSize (PCOOKIE pCookie, DWORD dwNewSize)
|
||
|
{
|
||
|
//returns previous size, for bookkeeping purposes
|
||
|
HRESULT hr;
|
||
|
|
||
|
TCHAR szKSuffix[10];
|
||
|
// Need enough room for DWORD as string + K suffix
|
||
|
TCHAR szBuf[ARRAYSIZE(szKSuffix) + 11];
|
||
|
|
||
|
if (dwNewSize == -1) //shouldn't happen anymore but if it does,
|
||
|
return -1; //deal gracefully
|
||
|
|
||
|
ASSERT(pCookie);
|
||
|
LPARAM itemParam;
|
||
|
hr = cookieMap.FindLParam(pCookie, &itemParam);
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return dwNewSize;
|
||
|
}
|
||
|
|
||
|
LV_ITEM lvi = {0};
|
||
|
LV_FINDINFO lvfi = {0};
|
||
|
|
||
|
lvfi.flags = LVFI_PARAM;
|
||
|
lvfi.lParam = itemParam;
|
||
|
|
||
|
lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
|
||
|
if (lvi.iItem == -1)
|
||
|
return dwNewSize;
|
||
|
|
||
|
lvi.iSubItem = SUBITEM_SIZE;
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.pszText = szBuf;
|
||
|
lvi.cchTextMax = sizeof(szBuf);
|
||
|
|
||
|
ListView_GetItem(m_hLV, &lvi);
|
||
|
DWORD dwOldSize = StrToInt (szBuf);
|
||
|
|
||
|
MLLoadString (IDS_SIZE_KB, szKSuffix, ARRAYSIZE(szKSuffix));
|
||
|
wnsprintf (szBuf, ARRAYSIZE(szBuf), "%d%s", dwNewSize, szKSuffix);
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
return dwOldSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
// This method is actually called from the second thread(only). So far
|
||
|
// I haven't found any sync problem yet. We only change the internal state
|
||
|
// of this object after it's creation in this method, so we won't mess
|
||
|
// it up. About UI, there is a chance when we try to disable 'Skip'
|
||
|
// button, we may come across another request from the primary thread. Since
|
||
|
// these 2 requests are both designated to disable the button, it won't
|
||
|
// matter anyway.
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::RefreshStatus(PCOOKIE pCookie, LPTSTR name, STATUS newStat, LPTSTR extraInfo)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
TCHAR szBuf[MAX_URL];
|
||
|
|
||
|
ASSERT(pCookie);
|
||
|
LPARAM itemParam;
|
||
|
hr = cookieMap.FindLParam(pCookie, &itemParam);
|
||
|
if (S_OK != hr) {
|
||
|
if (name) {
|
||
|
hr = AddItem(pCookie, name, newStat);
|
||
|
if (S_OK != hr) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
hr = cookieMap.FindLParam(pCookie, &itemParam);
|
||
|
if (S_OK != hr) {
|
||
|
ASSERT(0);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
} else {
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LV_ITEM lvi = {0};
|
||
|
LV_FINDINFO lvfi = {0};
|
||
|
|
||
|
lvfi.flags = LVFI_PARAM;
|
||
|
lvfi.lParam = itemParam;
|
||
|
|
||
|
lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
|
||
|
if (lvi.iItem == -1)
|
||
|
return E_FAIL;
|
||
|
|
||
|
lvi.iSubItem = SUBITEM_STATUS;
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
|
||
|
ASSERT ((UINT)newStat <= ITEM_STAT_ABORTED);
|
||
|
if (newStat == ITEM_STAT_UPDATING && extraInfo != NULL) //url available, use it
|
||
|
{
|
||
|
TCHAR szFormat[MAX_URL];
|
||
|
MLLoadString (IDS_ITEM_STAT_UPDATING_URL, szFormat, ARRAYSIZE(szFormat));
|
||
|
wnsprintf (szBuf, ARRAYSIZE(szBuf), szFormat, extraInfo);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MLLoadString(IDS_ITEM_STAT_IDLE + newStat, szBuf, ARRAYSIZE(szBuf));
|
||
|
}
|
||
|
|
||
|
lvi.pszText = szBuf;
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
lvi.iSubItem = SUBITEM_IMAGE;
|
||
|
lvi.mask = LVIF_IMAGE;
|
||
|
|
||
|
switch (newStat) {
|
||
|
case ITEM_STAT_QUEUED:
|
||
|
case ITEM_STAT_PENDING:
|
||
|
lvi.iImage = ILI_PENDING;
|
||
|
break;
|
||
|
case ITEM_STAT_UPDATING:
|
||
|
lvi.iImage = ILI_UPDATING;
|
||
|
//move to top of list -- t-mattgi
|
||
|
//this happens in sort callback function -- just force resort
|
||
|
//after we update the LV control
|
||
|
break;
|
||
|
case ITEM_STAT_SUCCEEDED:
|
||
|
lvi.iImage = ILI_SUCCEEDED;
|
||
|
if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
|
||
|
Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
|
||
|
break;
|
||
|
case ITEM_STAT_SKIPPED:
|
||
|
if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
|
||
|
Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
|
||
|
lvi.iImage = ILI_SKIPPED;
|
||
|
break;
|
||
|
default:
|
||
|
lvi.iImage = ILI_FAILED;
|
||
|
break;
|
||
|
}
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
//force resort since item statuses changed
|
||
|
ListView_SortItems (m_hLV, SortUpdatingToTop, this);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CUpdateDialog::CUpdateDialog()
|
||
|
{
|
||
|
m_bInitialized = FALSE;
|
||
|
}
|
||
|
|
||
|
CUpdateDialog::~CUpdateDialog()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::CleanUp()
|
||
|
{
|
||
|
if (! m_ThreadID || !m_bInitialized)
|
||
|
return S_OK;
|
||
|
|
||
|
if (m_hDlg)
|
||
|
{
|
||
|
PersistStateToRegistry (m_hDlg);
|
||
|
|
||
|
DestroyWindow(m_hDlg);
|
||
|
m_hDlg = NULL;
|
||
|
}
|
||
|
PostThreadMessage(m_ThreadID, WM_QUIT, 0, 0);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::Init(HWND hParent, CUpdateController * pController)
|
||
|
{
|
||
|
ASSERT(m_ThreadID);
|
||
|
ASSERT(g_hInst);
|
||
|
ASSERT(pController);
|
||
|
if (m_bInitialized) {
|
||
|
ASSERT(0);
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cookieMap.Init()))
|
||
|
return E_FAIL;
|
||
|
|
||
|
HWND hDlg, hLV;
|
||
|
|
||
|
m_pController = pController;
|
||
|
hDlg = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(IDD_PROGRESS), hParent, UpdateDlgProc, (LPARAM)this);
|
||
|
if (!hDlg)
|
||
|
return E_FAIL;
|
||
|
|
||
|
hLV = GetDlgItem(hDlg, IDL_SUBSCRIPTION);
|
||
|
if (!hLV) {
|
||
|
EndDialog(hDlg, FALSE);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
HIMAGELIST hImage;
|
||
|
HICON hIcon;
|
||
|
|
||
|
hImage = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
|
||
|
GetSystemMetrics(SM_CXSMICON),
|
||
|
ILC_MASK,
|
||
|
ARRAYSIZE(g_aIconResourceID),
|
||
|
0);
|
||
|
|
||
|
if (hImage == NULL) {
|
||
|
TraceMsg(TF_ALWAYS, TEXT("CUpdateDialog::Init - Failed to create ImageList"));
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < ARRAYSIZE(g_aIconResourceID); i ++) {
|
||
|
if (g_aIconResourceID[i] == IDI_DESKTOPITEM)
|
||
|
{
|
||
|
hinstSrc = MLGetHinst();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hinstSrc = g_hInst;
|
||
|
}
|
||
|
|
||
|
hIcon = LoadIcon(hinstSrc, MAKEINTRESOURCE(g_aIconResourceID[i]));
|
||
|
if (hIcon == NULL) {
|
||
|
ImageList_Destroy(hImage);
|
||
|
DBG("CUpdateDialog::Init - Failed to load icon");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
ImageList_AddIcon(hImage, hIcon);
|
||
|
DestroyIcon(hIcon);
|
||
|
}
|
||
|
|
||
|
ListView_SetImageList(hLV, hImage, LVSIL_SMALL);
|
||
|
|
||
|
LV_COLUMN lvc;
|
||
|
TEXTMETRIC tm;
|
||
|
HDC hdc;
|
||
|
|
||
|
hdc = GetDC(hDlg);
|
||
|
if (!hdc) {
|
||
|
EndDialog(hDlg, FALSE);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
GetTextMetrics(hdc, &tm);
|
||
|
ReleaseDC(hDlg, hdc);
|
||
|
|
||
|
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
|
||
|
|
||
|
PROG_PERSIST_STATE state;
|
||
|
GetPersistentStateFromRegistry(state, tm.tmAveCharWidth);
|
||
|
|
||
|
for (UINT ui = 0; ui < MAX_DLG_COL; ui ++)
|
||
|
{
|
||
|
int colIndex;
|
||
|
|
||
|
TCHAR szCaption[MAX_CAPTION];
|
||
|
if (colDlg[ui].ids)
|
||
|
MLLoadString(colDlg[ui].ids, szCaption, MAX_CAPTION);
|
||
|
else
|
||
|
szCaption[0] = (TCHAR)0;
|
||
|
|
||
|
lvc.pszText = szCaption;
|
||
|
lvc.cx = state.colWidth[ui];
|
||
|
lvc.fmt = colDlg[ui].iFmt;
|
||
|
colIndex = ListView_InsertColumn(hLV, ui, & lvc);
|
||
|
if ( -1 == colIndex) {
|
||
|
ASSERT(0);
|
||
|
EndDialog(hDlg, FALSE);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ListView_SetColumnOrderArray(hLV, MAX_DLG_COL, state.colOrder);
|
||
|
|
||
|
SendMessage (hLV, LVM_SETEXTENDEDLISTVIEWSTYLE,
|
||
|
LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES,
|
||
|
LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES);
|
||
|
|
||
|
SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon (g_hInst, MAKEINTRESOURCE (IDI_DOWNLOAD)));
|
||
|
SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon (g_hInst, MAKEINTRESOURCE (IDI_DOWNLOAD)));
|
||
|
|
||
|
if (state.bAdjustWindowPos)
|
||
|
{
|
||
|
//adjust size of *details view* to stored state; if we're not in
|
||
|
//details view, we have to go there temporarily. (The non-details
|
||
|
//view will pick up the position from the details view when we switch back.)
|
||
|
m_bDetail = TRUE;
|
||
|
ResizeDialog (hDlg, m_bDetail);
|
||
|
|
||
|
//don't move dialog, just resize it and center it
|
||
|
//convert right, bottom coordinates to width, height
|
||
|
state.rWindow.right -= state.rWindow.left;
|
||
|
state.rWindow.bottom -= state.rWindow.top;
|
||
|
//calculate left, top to center dialog
|
||
|
state.rWindow.left = (GetSystemMetrics (SM_CXSCREEN) - state.rWindow.right) / 2;
|
||
|
state.rWindow.top = (GetSystemMetrics (SM_CYSCREEN) - state.rWindow.bottom) / 2;
|
||
|
MoveWindow (hDlg, state.rWindow.left, state.rWindow.top,
|
||
|
state.rWindow.right, state.rWindow.bottom, TRUE);
|
||
|
|
||
|
//REVIEW: this centers the details view, then if they don't want details,
|
||
|
//leaves the small dialog with its upper left where the upper left of the
|
||
|
//big dialog is when it's centered. I could center it in whatever view
|
||
|
//it's really in, but if the details view is resized to a fairly large window
|
||
|
//and we bring it up centered in non-details, then when they click details
|
||
|
//the position will be the same and the window will potentially extend offscreen
|
||
|
//to the right and bottom.
|
||
|
|
||
|
//set back to non-details view if that was how it was last used
|
||
|
if (!state.bDetails)
|
||
|
{
|
||
|
m_bDetail = state.bDetails;
|
||
|
ResizeDialog (hDlg, m_bDetail);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_bInitialized = TRUE;
|
||
|
m_hDlg = hDlg;
|
||
|
m_hLV = hLV;
|
||
|
m_hParent = hParent;
|
||
|
m_cDlKBytes = 0;
|
||
|
m_cDlDocs = 0;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CUpdateDialog::PersistStateToRegistry (HWND hDlg)
|
||
|
{
|
||
|
PROG_PERSIST_STATE state;
|
||
|
|
||
|
state.cbSize = sizeof(state);
|
||
|
state.bDetails = m_bDetail;
|
||
|
state.bAdjustWindowPos = TRUE;
|
||
|
//save position and size from *details view* -- if we're not there,
|
||
|
//we'll have to switch temporarily.
|
||
|
BOOL bTempDetail = m_bDetail;
|
||
|
if (!bTempDetail)
|
||
|
{
|
||
|
ShowWindow (hDlg, SW_HIDE);
|
||
|
m_bDetail = TRUE;
|
||
|
ResizeDialog (hDlg, m_bDetail);
|
||
|
}
|
||
|
GetWindowRect (hDlg, &state.rWindow);
|
||
|
if (!bTempDetail)
|
||
|
{
|
||
|
m_bDetail = FALSE;
|
||
|
ResizeDialog (hDlg, m_bDetail);
|
||
|
ShowWindow (hDlg, SW_SHOW);
|
||
|
}
|
||
|
|
||
|
HWND hLV = GetDlgItem (hDlg, IDL_SUBSCRIPTION);
|
||
|
ListView_GetColumnOrderArray (hLV, MAX_DLG_COL, state.colOrder);
|
||
|
for (int i=0; i<MAX_DLG_COL; i++)
|
||
|
state.colWidth[i] = ListView_GetColumnWidth (hLV, i);
|
||
|
|
||
|
HKEY key;
|
||
|
DWORD dwDisposition;
|
||
|
if (ERROR_SUCCESS != RegCreateKeyEx (HKEY_CURRENT_USER, c_szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE,
|
||
|
KEY_WRITE, NULL, &key, &dwDisposition))
|
||
|
return FALSE;
|
||
|
|
||
|
RegSetValueEx (key, c_szProgressWindowSettings, 0, REG_BINARY, (LPBYTE)&state, sizeof(state));
|
||
|
|
||
|
RegCloseKey (key);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL CUpdateDialog::GetPersistentStateFromRegistry (PROG_PERSIST_STATE& state, int iCharWidth)
|
||
|
{
|
||
|
HKEY key;
|
||
|
DWORD dwType;
|
||
|
DWORD dwSize = sizeof(state);
|
||
|
RegOpenKeyEx (HKEY_CURRENT_USER, c_szRegKey, 0, KEY_READ, &key);
|
||
|
|
||
|
LONG result = RegQueryValueEx (key, c_szProgressWindowSettings,
|
||
|
0, &dwType, (LPBYTE)&state, &dwSize);
|
||
|
|
||
|
if (ERROR_SUCCESS != result || dwType != REG_BINARY || dwSize != sizeof(state))
|
||
|
{
|
||
|
state.cbSize = 0; //flag as error
|
||
|
}
|
||
|
|
||
|
if (state.cbSize != sizeof(state)) //error or incorrect registry format/version
|
||
|
{ //state not saved in registry; use defaults
|
||
|
int i;
|
||
|
|
||
|
state.bDetails = FALSE;
|
||
|
state.bAdjustWindowPos = FALSE;
|
||
|
|
||
|
state.colOrder[0] = 1;
|
||
|
state.colOrder[1] = 0;
|
||
|
for (i=2; i<MAX_DLG_COL; i++)
|
||
|
state.colOrder[i] = i;
|
||
|
|
||
|
for (i=0; i<MAX_DLG_COL; i++)
|
||
|
state.colWidth[i] = colDlg[i].cchCol * iCharWidth;
|
||
|
}
|
||
|
|
||
|
RegCloseKey (key);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::Show(BOOL bShow)
|
||
|
{
|
||
|
if (!m_bInitialized) {
|
||
|
ASSERT(0);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
ASSERT(m_hDlg);
|
||
|
|
||
|
ShowWindow(m_hDlg, (bShow)?SW_SHOW:SW_HIDE);
|
||
|
ShowWindow(m_hLV, (bShow)?SW_SHOW:SW_HIDE);
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::ResetDialog(void)
|
||
|
{
|
||
|
if (!m_bInitialized) {
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ASSERT(m_hLV);
|
||
|
ListView_DeleteAllItems(m_hLV);
|
||
|
cookieMap.ResetMap();
|
||
|
m_bInitialized = FALSE;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::IItem2Cookie(const int iItem, CLSID * pCookie)
|
||
|
{
|
||
|
LV_ITEM item = {0};
|
||
|
HRESULT hr;
|
||
|
ASSERT(pCookie);
|
||
|
|
||
|
item.iItem = iItem;
|
||
|
item.iSubItem = 0;
|
||
|
item.mask = LVIF_PARAM;
|
||
|
|
||
|
if (!ListView_GetItem(m_hLV, &item)) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
hr = cookieMap.FindCookie(item.lParam, pCookie);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::GetSelectedCookies(CLSID * pCookies, UINT * pCount)
|
||
|
{
|
||
|
if (!m_bInitialized)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
ASSERT(pCookies && pCount);
|
||
|
int index = -1;
|
||
|
|
||
|
*pCount = 0;
|
||
|
|
||
|
index = ListView_GetNextItem(m_hLV, index, LVNI_ALL | LVNI_SELECTED);
|
||
|
while (-1 != index) {
|
||
|
if (FAILED(IItem2Cookie(index, pCookies + *pCount))) {
|
||
|
ASSERT(0);
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
index = ListView_GetNextItem(m_hLV, index, LVNI_ALL | LVNI_SELECTED);
|
||
|
*pCount = *pCount + 1;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::GetSelectionCount(UINT * pCount)
|
||
|
{
|
||
|
if (!m_bInitialized)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
ASSERT(pCount);
|
||
|
* pCount = ListView_GetSelectedCount(m_hLV);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUpdateDialog::AddItem(CLSID * pCookie, LPTSTR name, STATUS stat)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
TCHAR szBuf[MAX_URL];
|
||
|
|
||
|
LV_ITEM lvi = {0};
|
||
|
BOOL bNew;
|
||
|
|
||
|
lvi.iSubItem = 0;
|
||
|
hr = cookieMap.AddCookie(pCookie, &(lvi.lParam));
|
||
|
if (S_OK == hr) {
|
||
|
bNew = TRUE;
|
||
|
} else if (S_FALSE == hr) {
|
||
|
bNew = FALSE;
|
||
|
} else {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
lvi.pszText = name;
|
||
|
if (bNew) {
|
||
|
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
||
|
switch (m_pController->GetSubscriptionType(pCookie))
|
||
|
{
|
||
|
case SUBSTYPE_CHANNEL:
|
||
|
lvi.iImage = ILI_CHANNEL;
|
||
|
break;
|
||
|
case SUBSTYPE_DESKTOPURL:
|
||
|
case SUBSTYPE_DESKTOPCHANNEL:
|
||
|
lvi.iImage = ILI_DESKTOP;
|
||
|
break;
|
||
|
case SUBSTYPE_URL:
|
||
|
default:
|
||
|
lvi.iImage = ILI_SITE;
|
||
|
break;
|
||
|
}
|
||
|
lvi.iItem = ListView_InsertItem(m_hLV, &lvi);
|
||
|
if (lvi.iItem == -1)
|
||
|
return E_FAIL;
|
||
|
if (lvi.iItem == 0) {
|
||
|
ListView_SetItemState(m_hLV, 0, LVIS_SELECTED, LVIS_SELECTED);
|
||
|
}
|
||
|
} else {
|
||
|
LV_FINDINFO lvfi = {0};
|
||
|
|
||
|
lvfi.flags = LVFI_PARAM;
|
||
|
lvfi.lParam = lvi.lParam;
|
||
|
|
||
|
lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
|
||
|
if (lvi.iItem == -1)
|
||
|
return E_FAIL;
|
||
|
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
}
|
||
|
|
||
|
//add subitem for status icon
|
||
|
lvi.mask = LVIF_IMAGE;
|
||
|
lvi.iSubItem ++; // Icon field.
|
||
|
switch (stat) {
|
||
|
case ITEM_STAT_QUEUED:
|
||
|
case ITEM_STAT_PENDING:
|
||
|
lvi.iImage = ILI_PENDING;
|
||
|
break;
|
||
|
case ITEM_STAT_UPDATING:
|
||
|
lvi.iImage = ILI_UPDATING;
|
||
|
break;
|
||
|
case ITEM_STAT_SUCCEEDED:
|
||
|
lvi.iImage = ILI_SUCCEEDED;
|
||
|
if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
|
||
|
Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
|
||
|
break;
|
||
|
case ITEM_STAT_SKIPPED:
|
||
|
lvi.iImage = ILI_SKIPPED;
|
||
|
if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
|
||
|
Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
|
||
|
default:
|
||
|
lvi.iImage = ILI_FAILED;
|
||
|
break;
|
||
|
}
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
//add subitem for status text
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
ASSERT ((UINT)stat <= ITEM_STAT_SUCCEEDED);
|
||
|
MLLoadString(IDS_ITEM_STAT_IDLE + stat, szBuf, ARRAYSIZE(szBuf));
|
||
|
lvi.pszText = szBuf;
|
||
|
lvi.iSubItem ++;
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
//add subitem for URL
|
||
|
PReportMap prm = m_pController->FindReportEntry (pCookie);
|
||
|
lvi.pszText = prm->url;
|
||
|
lvi.iSubItem++;
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
//add subitem for size
|
||
|
lvi.pszText = TEXT("");
|
||
|
lvi.iSubItem++;
|
||
|
ListView_SetItem(m_hLV, &lvi);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|