Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

836 lines
22 KiB

  1. #include "private.h"
  2. #include "offline.h"
  3. #include "updateui.h"
  4. //xnotfmgr - most of this file can probably get nuked
  5. #define MAX_CAPTION 128
  6. #undef TF_THISMODULE
  7. #define TF_THISMODULE TF_UPDATEAGENT
  8. typedef CLSID COOKIE, *PCOOKIE;
  9. #define SUBITEM_SIZE 4
  10. #define SUBITEM_URL 3
  11. #define SUBITEM_STATUS 2
  12. #define SUBITEM_IMAGE 1
  13. ColInfoType colDlg[] = {
  14. {0, IDS_NAME_COL, 30, LVCFMT_LEFT},
  15. {1, 0, 3, LVCFMT_LEFT},
  16. {2, IDS_STATUS_COL, 10, LVCFMT_LEFT},
  17. {3, IDS_URL_COL, 40, LVCFMT_LEFT},
  18. {4, IDS_SIZE_COL, 7, LVCFMT_RIGHT}
  19. };
  20. #define ILI_SUCCEEDED 0
  21. #define ILI_FAILED 1
  22. #define ILI_UPDATING 2
  23. #define ILI_PENDING 3
  24. #define ILI_SKIPPED 4
  25. #define ILI_SITE 5
  26. #define ILI_CHANNEL 6
  27. #define ILI_DESKTOP 7
  28. const int g_aIconResourceID[] = {
  29. IDI_STAT_SUCCEEDED,
  30. IDI_STAT_FAILED,
  31. IDI_STAT_UPDATING,
  32. IDI_STAT_PENDING,
  33. IDI_STAT_SKIPPED,
  34. IDI_WEBDOC,
  35. IDI_CHANNEL,
  36. IDI_DESKTOPITEM
  37. };
  38. #define MAX_DLG_COL ARRAYSIZE(colDlg)
  39. //struct for saving window state in registry
  40. typedef struct _PROG_PERSIST_STATE
  41. {
  42. short cbSize;
  43. char bDetails;
  44. char bAdjustWindowPos;
  45. RECT rWindow;
  46. int colOrder [MAX_DLG_COL];
  47. int colWidth [MAX_DLG_COL];
  48. } PROG_PERSIST_STATE;
  49. extern void ResizeDialog(HWND hDlg, BOOL bShowDetail); //in update.cpp
  50. const TCHAR c_szProgressWindowSettings[] = TEXT("Progress Preferences");
  51. const UINT CookieSeg = 32;
  52. CCookieItemMap::CCookieItemMap()
  53. {
  54. _map = NULL;
  55. }
  56. CCookieItemMap::~CCookieItemMap()
  57. {
  58. SAFELOCALFREE (_map);
  59. }
  60. STDMETHODIMP CCookieItemMap::Init(UINT size)
  61. {
  62. // Free old junk.
  63. SAFELOCALFREE (_map);
  64. _lParamNext = 0;
  65. _count = 0;
  66. if (size == 0)
  67. _capacity = CookieSeg;
  68. else
  69. _capacity = size;
  70. _map = (CookieItemMapEntry * )MemAlloc(LPTR, sizeof (CookieItemMapEntry) * _capacity);
  71. if (!_map) {
  72. DBG("Failed to allocate memory");
  73. _capacity = 0;
  74. return E_OUTOFMEMORY;
  75. }
  76. return S_OK;
  77. }
  78. STDMETHODIMP CCookieItemMap::ResetMap(void)
  79. {
  80. _count = 0;
  81. return S_OK;
  82. }
  83. STDMETHODIMP CCookieItemMap::FindCookie(LPARAM lParam, CLSID * pCookie)
  84. {
  85. ASSERT(pCookie);
  86. UINT i;
  87. for (i = 0; i < _count; i ++) {
  88. if (_map[i]._id == lParam) {
  89. * pCookie = _map[i]._cookie;
  90. return S_OK;
  91. }
  92. }
  93. *pCookie = CLSID_NULL;
  94. return E_FAIL;
  95. }
  96. STDMETHODIMP CCookieItemMap::FindLParam(CLSID * pCookie, LPARAM * pLParam)
  97. {
  98. ASSERT(pCookie && pLParam);
  99. UINT i;
  100. for (i = 0; i < _count; i ++) {
  101. if (_map[i]._cookie == *pCookie) {
  102. * pLParam = _map[i]._id;
  103. return S_OK;
  104. }
  105. }
  106. *pLParam = (LPARAM)-1;
  107. return E_FAIL;
  108. }
  109. STDMETHODIMP CCookieItemMap::AddCookie(CLSID * pCookie, LPARAM * pLParam)
  110. {
  111. HRESULT hr = FindLParam(pCookie, pLParam);
  112. if (S_OK == hr)
  113. return S_FALSE;
  114. ASSERT(_count <= _capacity);
  115. ASSERT(CookieSeg);
  116. if (_count == _capacity) {
  117. UINT newSize = CookieSeg + _capacity;
  118. void * newBuf = MemReAlloc(_map, newSize * sizeof(CookieItemMapEntry), LHND);
  119. if (!newBuf) {
  120. DBG("AddCookie::Failed to reallocate buffer");
  121. return E_OUTOFMEMORY;
  122. }
  123. _map = (CookieItemMapEntry *)newBuf;
  124. _capacity = newSize;
  125. }
  126. _map[_count]._cookie = *pCookie;
  127. _map[_count]._id = _lParamNext;
  128. _count ++;
  129. *pLParam = _lParamNext;
  130. _lParamNext ++;
  131. return S_OK;
  132. }
  133. STDMETHODIMP CCookieItemMap::DelCookie(CLSID * pCookie)
  134. {
  135. ASSERT(pCookie);
  136. UINT i;
  137. for (i = 0; i < _count; i ++) {
  138. if (_map[i]._cookie == *pCookie) {
  139. if (i == (_count - 1)) {
  140. _count --;
  141. return S_OK;
  142. } else {
  143. _count --;
  144. _map[i]._cookie = _map[_count]._cookie;
  145. _map[i]._id = _map[_count]._id;
  146. return S_OK;
  147. }
  148. }
  149. }
  150. return S_FALSE;
  151. }
  152. ///////////////////////////////////////////////////////////////////////////
  153. //
  154. // Other members
  155. //
  156. int CALLBACK CUpdateDialog::SortUpdatingToTop (LPARAM lParam1,
  157. LPARAM lParam2,
  158. LPARAM lParamSort)
  159. {
  160. //lparams are cookies; lparamsort is source object
  161. CUpdateDialog * pUpdater = (CUpdateDialog*)lParamSort;
  162. if (!pUpdater)
  163. return 0;
  164. if (!pUpdater->m_pController)
  165. return 0;
  166. CLSID cookie;
  167. pUpdater->cookieMap.FindCookie (lParam1, &cookie);
  168. PReportMap pEntry1 = pUpdater->m_pController->FindReportEntry (&cookie);
  169. pUpdater->cookieMap.FindCookie (lParam2, &cookie);
  170. PReportMap pEntry2 = pUpdater->m_pController->FindReportEntry (&cookie);
  171. //in progress precedes all else
  172. if (pEntry1->status == ITEM_STAT_UPDATING)
  173. return (pEntry2->status == ITEM_STAT_UPDATING ? 0 : -1);
  174. if (pEntry2->status == ITEM_STAT_UPDATING)
  175. return 1;
  176. //queued precedes succeeded or skipped
  177. if (pEntry1->status == ITEM_STAT_QUEUED || pEntry1->status == ITEM_STAT_PENDING)
  178. return ((pEntry2->status == ITEM_STAT_QUEUED
  179. || pEntry2->status == ITEM_STAT_PENDING) ? 0 : -1);
  180. if (pEntry2->status == ITEM_STAT_QUEUED || pEntry2->status == ITEM_STAT_PENDING)
  181. return 1;
  182. return 0; //don't care
  183. }
  184. BOOL CUpdateDialog::SelectFirstUpdatingSubscription()
  185. {
  186. LV_ITEM lvi = {0};
  187. lvi.iSubItem = SUBITEM_IMAGE;
  188. lvi.mask = LVIF_IMAGE;
  189. int cItems = ListView_GetItemCount (m_hLV);
  190. for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++)
  191. {
  192. ListView_GetItem (m_hLV, &lvi);
  193. if (lvi.iImage == ILI_UPDATING)
  194. {
  195. ListView_SetItemState (m_hLV, lvi.iItem, LVIS_SELECTED, LVIS_SELECTED);
  196. return TRUE;
  197. }
  198. }
  199. return FALSE;
  200. }
  201. DWORD CUpdateDialog::SetSiteDownloadSize (PCOOKIE pCookie, DWORD dwNewSize)
  202. {
  203. //returns previous size, for bookkeeping purposes
  204. HRESULT hr;
  205. TCHAR szKSuffix[10];
  206. // Need enough room for DWORD as string + K suffix
  207. TCHAR szBuf[ARRAYSIZE(szKSuffix) + 11];
  208. if (dwNewSize == -1) //shouldn't happen anymore but if it does,
  209. return -1; //deal gracefully
  210. ASSERT(pCookie);
  211. LPARAM itemParam;
  212. hr = cookieMap.FindLParam(pCookie, &itemParam);
  213. if (S_OK != hr)
  214. {
  215. return dwNewSize;
  216. }
  217. LV_ITEM lvi = {0};
  218. LV_FINDINFO lvfi = {0};
  219. lvfi.flags = LVFI_PARAM;
  220. lvfi.lParam = itemParam;
  221. lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
  222. if (lvi.iItem == -1)
  223. return dwNewSize;
  224. lvi.iSubItem = SUBITEM_SIZE;
  225. lvi.mask = LVIF_TEXT;
  226. lvi.pszText = szBuf;
  227. lvi.cchTextMax = sizeof(szBuf);
  228. ListView_GetItem(m_hLV, &lvi);
  229. DWORD dwOldSize = StrToInt (szBuf);
  230. MLLoadString (IDS_SIZE_KB, szKSuffix, ARRAYSIZE(szKSuffix));
  231. wnsprintf (szBuf, ARRAYSIZE(szBuf), "%d%s", dwNewSize, szKSuffix);
  232. ListView_SetItem(m_hLV, &lvi);
  233. return dwOldSize;
  234. }
  235. // This method is actually called from the second thread(only). So far
  236. // I haven't found any sync problem yet. We only change the internal state
  237. // of this object after it's creation in this method, so we won't mess
  238. // it up. About UI, there is a chance when we try to disable 'Skip'
  239. // button, we may come across another request from the primary thread. Since
  240. // these 2 requests are both designated to disable the button, it won't
  241. // matter anyway.
  242. STDMETHODIMP CUpdateDialog::RefreshStatus(PCOOKIE pCookie, LPTSTR name, STATUS newStat, LPTSTR extraInfo)
  243. {
  244. HRESULT hr;
  245. TCHAR szBuf[MAX_URL];
  246. ASSERT(pCookie);
  247. LPARAM itemParam;
  248. hr = cookieMap.FindLParam(pCookie, &itemParam);
  249. if (S_OK != hr) {
  250. if (name) {
  251. hr = AddItem(pCookie, name, newStat);
  252. if (S_OK != hr) {
  253. return E_FAIL;
  254. }
  255. hr = cookieMap.FindLParam(pCookie, &itemParam);
  256. if (S_OK != hr) {
  257. ASSERT(0);
  258. return E_FAIL;
  259. }
  260. } else {
  261. return hr;
  262. }
  263. }
  264. LV_ITEM lvi = {0};
  265. LV_FINDINFO lvfi = {0};
  266. lvfi.flags = LVFI_PARAM;
  267. lvfi.lParam = itemParam;
  268. lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
  269. if (lvi.iItem == -1)
  270. return E_FAIL;
  271. lvi.iSubItem = SUBITEM_STATUS;
  272. lvi.mask = LVIF_TEXT;
  273. ASSERT ((UINT)newStat <= ITEM_STAT_ABORTED);
  274. if (newStat == ITEM_STAT_UPDATING && extraInfo != NULL) //url available, use it
  275. {
  276. TCHAR szFormat[MAX_URL];
  277. MLLoadString (IDS_ITEM_STAT_UPDATING_URL, szFormat, ARRAYSIZE(szFormat));
  278. wnsprintf (szBuf, ARRAYSIZE(szBuf), szFormat, extraInfo);
  279. }
  280. else
  281. {
  282. MLLoadString(IDS_ITEM_STAT_IDLE + newStat, szBuf, ARRAYSIZE(szBuf));
  283. }
  284. lvi.pszText = szBuf;
  285. ListView_SetItem(m_hLV, &lvi);
  286. lvi.iSubItem = SUBITEM_IMAGE;
  287. lvi.mask = LVIF_IMAGE;
  288. switch (newStat) {
  289. case ITEM_STAT_QUEUED:
  290. case ITEM_STAT_PENDING:
  291. lvi.iImage = ILI_PENDING;
  292. break;
  293. case ITEM_STAT_UPDATING:
  294. lvi.iImage = ILI_UPDATING;
  295. //move to top of list -- t-mattgi
  296. //this happens in sort callback function -- just force resort
  297. //after we update the LV control
  298. break;
  299. case ITEM_STAT_SUCCEEDED:
  300. lvi.iImage = ILI_SUCCEEDED;
  301. if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
  302. Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
  303. break;
  304. case ITEM_STAT_SKIPPED:
  305. if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
  306. Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
  307. lvi.iImage = ILI_SKIPPED;
  308. break;
  309. default:
  310. lvi.iImage = ILI_FAILED;
  311. break;
  312. }
  313. ListView_SetItem(m_hLV, &lvi);
  314. //force resort since item statuses changed
  315. ListView_SortItems (m_hLV, SortUpdatingToTop, this);
  316. return hr;
  317. }
  318. CUpdateDialog::CUpdateDialog()
  319. {
  320. m_bInitialized = FALSE;
  321. }
  322. CUpdateDialog::~CUpdateDialog()
  323. {
  324. }
  325. STDMETHODIMP CUpdateDialog::CleanUp()
  326. {
  327. if (! m_ThreadID || !m_bInitialized)
  328. return S_OK;
  329. if (m_hDlg)
  330. {
  331. PersistStateToRegistry (m_hDlg);
  332. DestroyWindow(m_hDlg);
  333. m_hDlg = NULL;
  334. }
  335. PostThreadMessage(m_ThreadID, WM_QUIT, 0, 0);
  336. return S_OK;
  337. }
  338. STDMETHODIMP CUpdateDialog::Init(HWND hParent, CUpdateController * pController)
  339. {
  340. ASSERT(m_ThreadID);
  341. ASSERT(g_hInst);
  342. ASSERT(pController);
  343. if (m_bInitialized) {
  344. ASSERT(0);
  345. return S_FALSE;
  346. }
  347. if (FAILED(cookieMap.Init()))
  348. return E_FAIL;
  349. HWND hDlg, hLV;
  350. m_pController = pController;
  351. hDlg = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(IDD_PROGRESS), hParent, UpdateDlgProc, (LPARAM)this);
  352. if (!hDlg)
  353. return E_FAIL;
  354. hLV = GetDlgItem(hDlg, IDL_SUBSCRIPTION);
  355. if (!hLV) {
  356. EndDialog(hDlg, FALSE);
  357. return E_FAIL;
  358. }
  359. HIMAGELIST hImage;
  360. HICON hIcon;
  361. hImage = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  362. GetSystemMetrics(SM_CXSMICON),
  363. ILC_MASK,
  364. ARRAYSIZE(g_aIconResourceID),
  365. 0);
  366. if (hImage == NULL) {
  367. TraceMsg(TF_ALWAYS, TEXT("CUpdateDialog::Init - Failed to create ImageList"));
  368. return E_FAIL;
  369. }
  370. for (int i = 0; i < ARRAYSIZE(g_aIconResourceID); i ++) {
  371. if (g_aIconResourceID[i] == IDI_DESKTOPITEM)
  372. {
  373. hinstSrc = MLGetHinst();
  374. }
  375. else
  376. {
  377. hinstSrc = g_hInst;
  378. }
  379. hIcon = LoadIcon(hinstSrc, MAKEINTRESOURCE(g_aIconResourceID[i]));
  380. if (hIcon == NULL) {
  381. ImageList_Destroy(hImage);
  382. DBG("CUpdateDialog::Init - Failed to load icon");
  383. return E_FAIL;
  384. }
  385. ImageList_AddIcon(hImage, hIcon);
  386. DestroyIcon(hIcon);
  387. }
  388. ListView_SetImageList(hLV, hImage, LVSIL_SMALL);
  389. LV_COLUMN lvc;
  390. TEXTMETRIC tm;
  391. HDC hdc;
  392. hdc = GetDC(hDlg);
  393. if (!hdc) {
  394. EndDialog(hDlg, FALSE);
  395. return E_FAIL;
  396. }
  397. GetTextMetrics(hdc, &tm);
  398. ReleaseDC(hDlg, hdc);
  399. lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
  400. PROG_PERSIST_STATE state;
  401. GetPersistentStateFromRegistry(state, tm.tmAveCharWidth);
  402. for (UINT ui = 0; ui < MAX_DLG_COL; ui ++)
  403. {
  404. int colIndex;
  405. TCHAR szCaption[MAX_CAPTION];
  406. if (colDlg[ui].ids)
  407. MLLoadString(colDlg[ui].ids, szCaption, MAX_CAPTION);
  408. else
  409. szCaption[0] = (TCHAR)0;
  410. lvc.pszText = szCaption;
  411. lvc.cx = state.colWidth[ui];
  412. lvc.fmt = colDlg[ui].iFmt;
  413. colIndex = ListView_InsertColumn(hLV, ui, & lvc);
  414. if ( -1 == colIndex) {
  415. ASSERT(0);
  416. EndDialog(hDlg, FALSE);
  417. return E_FAIL;
  418. }
  419. }
  420. ListView_SetColumnOrderArray(hLV, MAX_DLG_COL, state.colOrder);
  421. SendMessage (hLV, LVM_SETEXTENDEDLISTVIEWSTYLE,
  422. LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES,
  423. LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES);
  424. SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon (g_hInst, MAKEINTRESOURCE (IDI_DOWNLOAD)));
  425. SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon (g_hInst, MAKEINTRESOURCE (IDI_DOWNLOAD)));
  426. if (state.bAdjustWindowPos)
  427. {
  428. //adjust size of *details view* to stored state; if we're not in
  429. //details view, we have to go there temporarily. (The non-details
  430. //view will pick up the position from the details view when we switch back.)
  431. m_bDetail = TRUE;
  432. ResizeDialog (hDlg, m_bDetail);
  433. //don't move dialog, just resize it and center it
  434. //convert right, bottom coordinates to width, height
  435. state.rWindow.right -= state.rWindow.left;
  436. state.rWindow.bottom -= state.rWindow.top;
  437. //calculate left, top to center dialog
  438. state.rWindow.left = (GetSystemMetrics (SM_CXSCREEN) - state.rWindow.right) / 2;
  439. state.rWindow.top = (GetSystemMetrics (SM_CYSCREEN) - state.rWindow.bottom) / 2;
  440. MoveWindow (hDlg, state.rWindow.left, state.rWindow.top,
  441. state.rWindow.right, state.rWindow.bottom, TRUE);
  442. //REVIEW: this centers the details view, then if they don't want details,
  443. //leaves the small dialog with its upper left where the upper left of the
  444. //big dialog is when it's centered. I could center it in whatever view
  445. //it's really in, but if the details view is resized to a fairly large window
  446. //and we bring it up centered in non-details, then when they click details
  447. //the position will be the same and the window will potentially extend offscreen
  448. //to the right and bottom.
  449. //set back to non-details view if that was how it was last used
  450. if (!state.bDetails)
  451. {
  452. m_bDetail = state.bDetails;
  453. ResizeDialog (hDlg, m_bDetail);
  454. }
  455. }
  456. m_bInitialized = TRUE;
  457. m_hDlg = hDlg;
  458. m_hLV = hLV;
  459. m_hParent = hParent;
  460. m_cDlKBytes = 0;
  461. m_cDlDocs = 0;
  462. return S_OK;
  463. }
  464. BOOL CUpdateDialog::PersistStateToRegistry (HWND hDlg)
  465. {
  466. PROG_PERSIST_STATE state;
  467. state.cbSize = sizeof(state);
  468. state.bDetails = m_bDetail;
  469. state.bAdjustWindowPos = TRUE;
  470. //save position and size from *details view* -- if we're not there,
  471. //we'll have to switch temporarily.
  472. BOOL bTempDetail = m_bDetail;
  473. if (!bTempDetail)
  474. {
  475. ShowWindow (hDlg, SW_HIDE);
  476. m_bDetail = TRUE;
  477. ResizeDialog (hDlg, m_bDetail);
  478. }
  479. GetWindowRect (hDlg, &state.rWindow);
  480. if (!bTempDetail)
  481. {
  482. m_bDetail = FALSE;
  483. ResizeDialog (hDlg, m_bDetail);
  484. ShowWindow (hDlg, SW_SHOW);
  485. }
  486. HWND hLV = GetDlgItem (hDlg, IDL_SUBSCRIPTION);
  487. ListView_GetColumnOrderArray (hLV, MAX_DLG_COL, state.colOrder);
  488. for (int i=0; i<MAX_DLG_COL; i++)
  489. state.colWidth[i] = ListView_GetColumnWidth (hLV, i);
  490. HKEY key;
  491. DWORD dwDisposition;
  492. if (ERROR_SUCCESS != RegCreateKeyEx (HKEY_CURRENT_USER, c_szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE,
  493. KEY_WRITE, NULL, &key, &dwDisposition))
  494. return FALSE;
  495. RegSetValueEx (key, c_szProgressWindowSettings, 0, REG_BINARY, (LPBYTE)&state, sizeof(state));
  496. RegCloseKey (key);
  497. return TRUE;
  498. }
  499. BOOL CUpdateDialog::GetPersistentStateFromRegistry (PROG_PERSIST_STATE& state, int iCharWidth)
  500. {
  501. HKEY key;
  502. DWORD dwType;
  503. DWORD dwSize = sizeof(state);
  504. RegOpenKeyEx (HKEY_CURRENT_USER, c_szRegKey, 0, KEY_READ, &key);
  505. LONG result = RegQueryValueEx (key, c_szProgressWindowSettings,
  506. 0, &dwType, (LPBYTE)&state, &dwSize);
  507. if (ERROR_SUCCESS != result || dwType != REG_BINARY || dwSize != sizeof(state))
  508. {
  509. state.cbSize = 0; //flag as error
  510. }
  511. if (state.cbSize != sizeof(state)) //error or incorrect registry format/version
  512. { //state not saved in registry; use defaults
  513. int i;
  514. state.bDetails = FALSE;
  515. state.bAdjustWindowPos = FALSE;
  516. state.colOrder[0] = 1;
  517. state.colOrder[1] = 0;
  518. for (i=2; i<MAX_DLG_COL; i++)
  519. state.colOrder[i] = i;
  520. for (i=0; i<MAX_DLG_COL; i++)
  521. state.colWidth[i] = colDlg[i].cchCol * iCharWidth;
  522. }
  523. RegCloseKey (key);
  524. return TRUE;
  525. }
  526. STDMETHODIMP CUpdateDialog::Show(BOOL bShow)
  527. {
  528. if (!m_bInitialized) {
  529. ASSERT(0);
  530. return E_FAIL;
  531. }
  532. ASSERT(m_hDlg);
  533. ShowWindow(m_hDlg, (bShow)?SW_SHOW:SW_HIDE);
  534. ShowWindow(m_hLV, (bShow)?SW_SHOW:SW_HIDE);
  535. return NOERROR;
  536. }
  537. STDMETHODIMP CUpdateDialog::ResetDialog(void)
  538. {
  539. if (!m_bInitialized) {
  540. return S_OK;
  541. }
  542. ASSERT(m_hLV);
  543. ListView_DeleteAllItems(m_hLV);
  544. cookieMap.ResetMap();
  545. m_bInitialized = FALSE;
  546. return S_OK;
  547. }
  548. STDMETHODIMP CUpdateDialog::IItem2Cookie(const int iItem, CLSID * pCookie)
  549. {
  550. LV_ITEM item = {0};
  551. HRESULT hr;
  552. ASSERT(pCookie);
  553. item.iItem = iItem;
  554. item.iSubItem = 0;
  555. item.mask = LVIF_PARAM;
  556. if (!ListView_GetItem(m_hLV, &item)) {
  557. return E_FAIL;
  558. }
  559. hr = cookieMap.FindCookie(item.lParam, pCookie);
  560. ASSERT(SUCCEEDED(hr));
  561. return hr;
  562. }
  563. STDMETHODIMP CUpdateDialog::GetSelectedCookies(CLSID * pCookies, UINT * pCount)
  564. {
  565. if (!m_bInitialized)
  566. return E_INVALIDARG;
  567. ASSERT(pCookies && pCount);
  568. int index = -1;
  569. *pCount = 0;
  570. index = ListView_GetNextItem(m_hLV, index, LVNI_ALL | LVNI_SELECTED);
  571. while (-1 != index) {
  572. if (FAILED(IItem2Cookie(index, pCookies + *pCount))) {
  573. ASSERT(0);
  574. return S_FALSE;
  575. }
  576. index = ListView_GetNextItem(m_hLV, index, LVNI_ALL | LVNI_SELECTED);
  577. *pCount = *pCount + 1;
  578. }
  579. return S_OK;
  580. }
  581. STDMETHODIMP CUpdateDialog::GetSelectionCount(UINT * pCount)
  582. {
  583. if (!m_bInitialized)
  584. return E_INVALIDARG;
  585. ASSERT(pCount);
  586. * pCount = ListView_GetSelectedCount(m_hLV);
  587. return S_OK;
  588. }
  589. STDMETHODIMP CUpdateDialog::AddItem(CLSID * pCookie, LPTSTR name, STATUS stat)
  590. {
  591. HRESULT hr;
  592. TCHAR szBuf[MAX_URL];
  593. LV_ITEM lvi = {0};
  594. BOOL bNew;
  595. lvi.iSubItem = 0;
  596. hr = cookieMap.AddCookie(pCookie, &(lvi.lParam));
  597. if (S_OK == hr) {
  598. bNew = TRUE;
  599. } else if (S_FALSE == hr) {
  600. bNew = FALSE;
  601. } else {
  602. return hr;
  603. }
  604. lvi.pszText = name;
  605. if (bNew) {
  606. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  607. switch (m_pController->GetSubscriptionType(pCookie))
  608. {
  609. case SUBSTYPE_CHANNEL:
  610. lvi.iImage = ILI_CHANNEL;
  611. break;
  612. case SUBSTYPE_DESKTOPURL:
  613. case SUBSTYPE_DESKTOPCHANNEL:
  614. lvi.iImage = ILI_DESKTOP;
  615. break;
  616. case SUBSTYPE_URL:
  617. default:
  618. lvi.iImage = ILI_SITE;
  619. break;
  620. }
  621. lvi.iItem = ListView_InsertItem(m_hLV, &lvi);
  622. if (lvi.iItem == -1)
  623. return E_FAIL;
  624. if (lvi.iItem == 0) {
  625. ListView_SetItemState(m_hLV, 0, LVIS_SELECTED, LVIS_SELECTED);
  626. }
  627. } else {
  628. LV_FINDINFO lvfi = {0};
  629. lvfi.flags = LVFI_PARAM;
  630. lvfi.lParam = lvi.lParam;
  631. lvi.iItem = ListView_FindItem(m_hLV, -1, &lvfi);
  632. if (lvi.iItem == -1)
  633. return E_FAIL;
  634. lvi.mask = LVIF_TEXT;
  635. ListView_SetItem(m_hLV, &lvi);
  636. }
  637. //add subitem for status icon
  638. lvi.mask = LVIF_IMAGE;
  639. lvi.iSubItem ++; // Icon field.
  640. switch (stat) {
  641. case ITEM_STAT_QUEUED:
  642. case ITEM_STAT_PENDING:
  643. lvi.iImage = ILI_PENDING;
  644. break;
  645. case ITEM_STAT_UPDATING:
  646. lvi.iImage = ILI_UPDATING;
  647. break;
  648. case ITEM_STAT_SUCCEEDED:
  649. lvi.iImage = ILI_SUCCEEDED;
  650. if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
  651. Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
  652. break;
  653. case ITEM_STAT_SKIPPED:
  654. lvi.iImage = ILI_SKIPPED;
  655. if (ListView_GetItemState(m_hLV, lvi.iItem, LVIS_SELECTED))
  656. Button_Enable(GetDlgItem(m_hDlg, IDCMD_SKIP), FALSE);
  657. default:
  658. lvi.iImage = ILI_FAILED;
  659. break;
  660. }
  661. ListView_SetItem(m_hLV, &lvi);
  662. //add subitem for status text
  663. lvi.mask = LVIF_TEXT;
  664. ASSERT ((UINT)stat <= ITEM_STAT_SUCCEEDED);
  665. MLLoadString(IDS_ITEM_STAT_IDLE + stat, szBuf, ARRAYSIZE(szBuf));
  666. lvi.pszText = szBuf;
  667. lvi.iSubItem ++;
  668. ListView_SetItem(m_hLV, &lvi);
  669. //add subitem for URL
  670. PReportMap prm = m_pController->FindReportEntry (pCookie);
  671. lvi.pszText = prm->url;
  672. lvi.iSubItem++;
  673. ListView_SetItem(m_hLV, &lvi);
  674. //add subitem for size
  675. lvi.pszText = TEXT("");
  676. lvi.iSubItem++;
  677. ListView_SetItem(m_hLV, &lvi);
  678. return S_OK;
  679. }