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.

644 lines
15 KiB

  1. //*******************************************************************************************
  2. //
  3. // Filename : Sfview.cpp
  4. //
  5. // Implementation file for CSFView
  6. //
  7. // Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
  8. //
  9. //*******************************************************************************************
  10. #include "Pch.H"
  11. #include "SFView.H"
  12. #include "SFVWnd.H"
  13. #include "Resource.H"
  14. #include "ThisGuid.H"
  15. #include "SFView.H"
  16. struct SFSTATE_HDR
  17. {
  18. CLSID clsThis;
  19. SFSTATE sfState;
  20. UINT nCols;
  21. } ;
  22. CSFView::CSFView(IShellFolder *psf, IShellFolderViewCallback *psfvcb) :
  23. m_psf(psf), m_erFolder(psf), m_erCB(psfvcb), m_pCDB(NULL), m_cView(this),
  24. m_uState(SVUIA_DEACTIVATE), m_pcmSel(NULL), m_cAccel(IDA_MAIN)
  25. {
  26. m_psfvcb = psfvcb;
  27. if (psfvcb)
  28. {
  29. psfvcb->AddRef();
  30. }
  31. psf->AddRef();
  32. m_aParamSort = DPA_Create(4);
  33. m_sfState.lParamSort = 0;
  34. }
  35. CSFView::~CSFView()
  36. {
  37. ReleaseSelContextMenu();
  38. }
  39. STDMETHODIMP CSFView::QueryInterface(REFIID riid, void ** ppvObj)
  40. {
  41. static const IID *apiid[] = { &IID_IShellView, NULL };
  42. LPUNKNOWN aobj[] = { (IShellView *)this };
  43. return(QIHelper(riid, ppvObj, apiid, aobj));
  44. }
  45. STDMETHODIMP_(ULONG) CSFView::AddRef()
  46. {
  47. return(AddRefHelper());
  48. }
  49. STDMETHODIMP_(ULONG) CSFView::Release()
  50. {
  51. return(ReleaseHelper());
  52. }
  53. STDMETHODIMP CSFView::GetWindow(HWND * lphwnd)
  54. {
  55. return(E_NOTIMPL);
  56. }
  57. STDMETHODIMP CSFView::ContextSensitiveHelp(BOOL fEnterMode)
  58. {
  59. return(E_NOTIMPL);
  60. }
  61. //*****************************************************************************
  62. //
  63. // CSFView::TranslateAccelerator
  64. //
  65. // Purpose:
  66. // Handle the accelerator keystrokes
  67. //
  68. //
  69. // Parameters:
  70. // LPMSG lpmsg - message structure
  71. //
  72. //
  73. // Comments:
  74. //
  75. //*****************************************************************************
  76. STDMETHODIMP CSFView::TranslateAccelerator(LPMSG lpmsg)
  77. {
  78. return(m_cAccel.TranslateAccelerator(m_cView, lpmsg) ? S_OK : S_FALSE);
  79. }
  80. STDMETHODIMP CSFView::EnableModeless(BOOL fEnable)
  81. {
  82. return(E_NOTIMPL);
  83. }
  84. //*****************************************************************************
  85. //
  86. // CSFView:UIActivate
  87. //
  88. // Purpose:
  89. // The explorer calls this member function whenever the activation
  90. // state of the view window is changed by a certain event that is
  91. // NOT caused by the shell view itself.
  92. //
  93. //
  94. // Parameters:
  95. //
  96. // UINT uState - UI activate flag
  97. //
  98. // Comments:
  99. //
  100. //*****************************************************************************
  101. STDMETHODIMP CSFView::UIActivate(UINT uState)
  102. {
  103. if (uState)
  104. {
  105. OnActivate(uState);
  106. }
  107. else
  108. {
  109. OnDeactivate();
  110. }
  111. return S_OK;
  112. }
  113. STDMETHODIMP CSFView::Refresh()
  114. {
  115. FillList(FALSE);
  116. return S_OK;// yes, this is potentially bad, but we risk app compat problems if we change it. 2000/02/10 -ccooney
  117. }
  118. //*****************************************************************************
  119. //
  120. // CSFView::CreateViewWindow
  121. //
  122. // Purpose:
  123. //
  124. // called by IShellBrowser to create a contents pane window
  125. //
  126. // Parameters:
  127. //
  128. // IShellView *lpPrevView - previous view
  129. // LPCFOLDERSETTINGS lpfs - folder settings for the view
  130. // IShellBrowser *psb - pointer to the shell browser
  131. // RECT * prcView - view Rectangle
  132. // HWND * phWnd - pointer to Window handle
  133. //
  134. //
  135. // Comments:
  136. //
  137. //*****************************************************************************
  138. STDMETHODIMP CSFView::CreateViewWindow(IShellView *lpPrevView,
  139. LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,
  140. RECT * prcView, HWND *phWnd)
  141. {
  142. *phWnd = NULL;
  143. if ((HWND)m_cView)
  144. {
  145. return(E_UNEXPECTED);
  146. }
  147. m_fs = *lpfs;
  148. m_psb = psb;
  149. // get the main window handle from shell browser
  150. psb->GetWindow(&m_hwndMain);
  151. // bring up the contents pane
  152. if (!m_cView.DoModeless(IDD_VIEW, m_hwndMain))
  153. {
  154. return(E_OUTOFMEMORY);
  155. }
  156. *phWnd = m_cView;
  157. // map the current view mode into menu id and set the contents pane
  158. // view mode accordingly
  159. OnCommand(NULL, GET_WM_COMMAND_MPS(GetMenuIDFromViewMode(), 0, 0));
  160. AddColumns();
  161. RestoreViewState();
  162. // size the contents pane
  163. SetWindowPos(m_cView, NULL, prcView->left, prcView->top,
  164. prcView->right-prcView->left, prcView->bottom-prcView->top,
  165. SWP_NOZORDER|SWP_SHOWWINDOW);
  166. FillList(TRUE);
  167. return(NOERROR);
  168. }
  169. STDMETHODIMP CSFView::DestroyViewWindow()
  170. {
  171. if (!(HWND)m_cView)
  172. {
  173. return(E_UNEXPECTED);
  174. }
  175. m_cView.DestroyWindow();
  176. return(NOERROR);
  177. }
  178. STDMETHODIMP CSFView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
  179. {
  180. *lpfs = m_fs;
  181. return(NOERROR);
  182. }
  183. STDMETHODIMP CSFView::AddPropertySheetPages(DWORD dwReserved,
  184. LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
  185. {
  186. return(E_NOTIMPL);
  187. }
  188. STDMETHODIMP CSFView::SaveViewState()
  189. {
  190. SFSTATE_HDR hdr;
  191. LPSTREAM pstm;
  192. HRESULT hres = m_psb->GetViewStateStream(STGM_WRITE, &pstm);
  193. if (FAILED(hres))
  194. {
  195. return(hres);
  196. }
  197. CEnsureRelease erStr(pstm);
  198. pstm->Write(&hdr, sizeof(hdr), NULL);
  199. hdr.clsThis = CLSID_ThisDll;
  200. hdr.sfState = m_sfState;
  201. hdr.nCols = SaveColumns(pstm);
  202. ULARGE_INTEGER libCurPosition;
  203. LARGE_INTEGER dlibMove;
  204. dlibMove.HighPart = 0;
  205. dlibMove.LowPart = 0;
  206. pstm->Seek(dlibMove, STREAM_SEEK_SET, &libCurPosition);
  207. hres = pstm->Write(&hdr, sizeof(hdr), NULL);
  208. return(hres);
  209. }
  210. STDMETHODIMP CSFView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags)
  211. {
  212. return(E_NOTIMPL);
  213. }
  214. STDMETHODIMP CSFView::GetItemObject(UINT uItem, REFIID riid,
  215. void **ppv)
  216. {
  217. return(E_NOTIMPL);
  218. }
  219. int CSFView::AddObject(LPCITEMIDLIST pidl)
  220. {
  221. // Check the commdlg hook to see if we should include this
  222. // object.
  223. if (IncludeObject(pidl) != S_OK)
  224. {
  225. return(-1);
  226. }
  227. return(m_cView.AddObject(pidl));
  228. }
  229. int CALLBACK CSFView::CompareIDs(LPVOID p1, LPVOID p2, LPARAM lParam)
  230. {
  231. PFNDPACOMPARE pfnCheckAPI = CompareIDs;
  232. CSFView *pThis = (CSFView *)lParam;
  233. HRESULT hres = pThis->m_psf->CompareIDs(pThis->m_sfState.lParamSort,
  234. (LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
  235. return (hres);
  236. }
  237. //*****************************************************************************
  238. //
  239. // CSFView::FillList
  240. //
  241. // Purpose:
  242. //
  243. // Enumerates the objects in the namespace and fills up the
  244. // data structures
  245. //
  246. //
  247. // Comments:
  248. //
  249. //*****************************************************************************
  250. HRESULT CSFView::FillList(BOOL bInteractive)
  251. {
  252. m_cView.DeleteAllItems();
  253. // Setup the enum flags.
  254. DWORD dwEnumFlags = SHCONTF_NONFOLDERS;
  255. if (ShowAllObjects())
  256. {
  257. dwEnumFlags |= SHCONTF_INCLUDEHIDDEN ;
  258. }
  259. if (!(m_fs.fFlags & FWF_NOSUBFOLDERS))
  260. {
  261. dwEnumFlags |= SHCONTF_FOLDERS;
  262. }
  263. // Create an enum object and get the IEnumIDList ptr
  264. LPENUMIDLIST peIDL;
  265. HRESULT hres = m_psf->EnumObjects(bInteractive ? m_hwndMain : NULL,
  266. dwEnumFlags, &peIDL);
  267. // Note the return may be S_FALSE which indicates no enumerator.
  268. // That's why we shouldn't use if (FAILED(hres))
  269. if (hres != S_OK)
  270. {
  271. if (hres == S_FALSE)
  272. {
  273. return(NOERROR);
  274. }
  275. return(hres);
  276. }
  277. CEnsureRelease erEnum(peIDL);
  278. HDPA hdpaNew = DPA_Create(16);
  279. if (!hdpaNew)
  280. {
  281. return(E_OUTOFMEMORY);
  282. }
  283. LPITEMIDLIST pidl;
  284. ULONG celt;
  285. // Enumerate the idlist and insert into the DPA
  286. while (peIDL->Next(1, &pidl, &celt) == S_OK)
  287. {
  288. if (DPA_InsertPtr(hdpaNew, 0x7fff, pidl) == -1)
  289. {
  290. m_cMalloc.Free(pidl);
  291. }
  292. }
  293. DPA_Sort(hdpaNew, CompareIDs, (LPARAM)this);
  294. int cNew = DPA_GetPtrCount(hdpaNew);
  295. for (int i=0; i<cNew; ++i)
  296. {
  297. LPITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaNew, i);
  298. if (AddObject(pidl) < 0)
  299. {
  300. m_cMalloc.Free(pidl);
  301. }
  302. }
  303. return(NOERROR);
  304. }
  305. //*****************************************************************************
  306. //
  307. // CSFView::AddColumns
  308. //
  309. // Purpose:
  310. //
  311. // Adds columns to the contents pane listview
  312. //
  313. // Comments:
  314. //
  315. //*****************************************************************************
  316. void CSFView::AddColumns()
  317. {
  318. UINT cxChar = m_cView.CharWidth();
  319. // add columns to the listview in the contents pane
  320. for (int i=0; ; ++i)
  321. {
  322. SFVCB_GETDETAILSOF_DATA gdo;
  323. gdo.pidl = NULL;
  324. // get the first column
  325. HRESULT hres = CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo);
  326. if (hres != S_OK)
  327. {
  328. if (i != 0)
  329. {
  330. break;
  331. }
  332. // If there is no first column, fake one up
  333. gdo.fmt = LVCFMT_LEFT;
  334. gdo.cChar = 40;
  335. gdo.lParamSort = 0;
  336. gdo.str.uType = STRRET_CSTR;
  337. LoadString(g_ThisDll.GetInstance(), IDS_NAME, gdo.str.cStr, sizeof(gdo.str.cStr));
  338. }
  339. char szText[MAX_PATH];
  340. // init the column info for the details view ...
  341. LV_COLUMN col;
  342. col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  343. col.fmt = gdo.fmt;
  344. col.cx = gdo.cChar * cxChar;
  345. col.pszText = szText;
  346. col.cchTextMax = sizeof(szText);
  347. col.iSubItem = i;
  348. StrRetToStr(szText, sizeof(szText), &gdo.str, NULL);
  349. // insert the column into the list view
  350. if (m_cView.InsertColumn(i, &col)>=0 && m_aParamSort)
  351. {
  352. DPA_InsertPtr(m_aParamSort, 0x7fff, (LPVOID)gdo.lParamSort);
  353. }
  354. if (hres != S_OK)
  355. {
  356. break;
  357. }
  358. }
  359. }
  360. //
  361. // Save (and check) column header information
  362. // Returns TRUE if the columns are the default width, FALSE otherwise
  363. // Side effect: the stream pointer is left right after the last column
  364. //
  365. BOOL CSFView::SaveColumns(LPSTREAM pstm)
  366. {
  367. UINT cxChar = m_cView.CharWidth();
  368. BOOL bDefaultCols = TRUE;
  369. for (int i=0; ; ++i)
  370. {
  371. SFVCB_GETDETAILSOF_DATA gdo;
  372. gdo.pidl = NULL;
  373. if (CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo) != S_OK)
  374. {
  375. break;
  376. }
  377. LV_COLUMN col;
  378. col.mask = LVCF_WIDTH;
  379. if (!m_cView.GetColumn(i, &col))
  380. {
  381. // There is some problem, so just assume
  382. // default column widths
  383. bDefaultCols = TRUE;
  384. break;
  385. }
  386. if (col.cx != (int)(gdo.cChar * cxChar))
  387. {
  388. bDefaultCols = FALSE;
  389. }
  390. // HACK: I don't really care about column widths larger
  391. // than 64K
  392. if (FAILED(pstm->Write(&col.cx, sizeof(USHORT), NULL)))
  393. {
  394. // There is some problem, so just assume
  395. // default column widths
  396. bDefaultCols = TRUE;
  397. break;
  398. }
  399. }
  400. return(bDefaultCols ? 0 : i);
  401. }
  402. void CSFView::RestoreColumns(LPSTREAM pstm, int nCols)
  403. {
  404. for (int i=0; i<nCols; ++i)
  405. {
  406. LV_COLUMN col;
  407. col.mask = LVCF_WIDTH;
  408. if (FAILED(pstm->Read(&col.cx, sizeof(USHORT), NULL)))
  409. {
  410. break;
  411. }
  412. m_cView.SetColumn(i, &col);
  413. }
  414. }
  415. void CSFView::RestoreViewState()
  416. {
  417. SFSTATE_HDR hdr;
  418. LPSTREAM pstm;
  419. MergeToolBar();
  420. // get the stream for storing view specific info
  421. if (FAILED(m_psb->GetViewStateStream(STGM_READ, &pstm)))
  422. {
  423. return;
  424. }
  425. CEnsureRelease erStr(pstm);
  426. if (FAILED(pstm->Read(&hdr, sizeof(hdr), NULL)))
  427. {
  428. return;
  429. }
  430. // Validate the header
  431. if (hdr.clsThis != CLSID_ThisDll)
  432. {
  433. return;
  434. }
  435. m_sfState = hdr.sfState;
  436. RestoreColumns(pstm, hdr.nCols);
  437. }
  438. void CSFView::CheckToolbar()
  439. {
  440. UINT idCmdCurView = GetMenuIDFromViewMode();
  441. for (UINT idCmd=IDC_VIEW_ICON; idCmd<=IDC_VIEW_DETAILS; ++idCmd)
  442. {
  443. m_psb->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, idCmd,
  444. (LPARAM)(idCmd == idCmdCurView), NULL);
  445. }
  446. }
  447. void CSFView::MergeToolBar()
  448. {
  449. enum
  450. {
  451. IN_STD_BMP = 0x4000,
  452. IN_VIEW_BMP = 0x8000,
  453. } ;
  454. static const TBBUTTON c_tbDefault[] =
  455. {
  456. { STD_COPY | IN_STD_BMP, IDC_EDIT_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
  457. { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
  458. // the bitmap indexes here are relative to the view bitmap
  459. { VIEW_LARGEICONS | IN_VIEW_BMP, IDC_VIEW_ICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
  460. { VIEW_SMALLICONS | IN_VIEW_BMP, IDC_VIEW_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
  461. { VIEW_LIST | IN_VIEW_BMP, IDC_VIEW_LIST, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
  462. { VIEW_DETAILS | IN_VIEW_BMP, IDC_VIEW_DETAILS, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
  463. } ;
  464. LRESULT iStdBMOffset;
  465. LRESULT iViewBMOffset;
  466. TBADDBITMAP ab;
  467. ab.hInst = HINST_COMMCTRL; // hinstCommctrl
  468. ab.nID = IDB_STD_SMALL_COLOR; // std bitmaps
  469. m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iStdBMOffset);
  470. ab.nID = IDB_VIEW_SMALL_COLOR; // std view bitmaps
  471. m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iViewBMOffset);
  472. TBBUTTON tbActual[ARRAYSIZE(c_tbDefault)];
  473. for (int i=0; i<ARRAYSIZE(c_tbDefault); ++i)
  474. {
  475. tbActual[i] = c_tbDefault[i];
  476. if (!(tbActual[i].fsStyle & TBSTYLE_SEP))
  477. {
  478. if (tbActual[i].iBitmap & IN_VIEW_BMP)
  479. {
  480. tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_VIEW_BMP) + iViewBMOffset;
  481. }
  482. else if (tbActual[i].iBitmap & IN_STD_BMP)
  483. {
  484. tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_STD_BMP) + iStdBMOffset;
  485. }
  486. }
  487. }
  488. m_psb->SetToolbarItems(tbActual, ARRAYSIZE(c_tbDefault), FCT_MERGE);
  489. CheckToolbar();
  490. }
  491. HRESULT CreateShellFolderView(IShellFolder *psf, IShellFolderViewCallback *psfvcb,
  492. LPSHELLVIEW * ppsv)
  493. {
  494. CSFView *pSFView = new CSFView(psf, psfvcb);
  495. if (!pSFView)
  496. {
  497. return(E_OUTOFMEMORY);
  498. }
  499. pSFView->AddRef();
  500. HRESULT hRes = pSFView->QueryInterface(IID_IShellView, (void **)ppsv);
  501. pSFView->Release();
  502. return(hRes);
  503. }