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.

391 lines
11 KiB

  1. #include "stdafx.h"
  2. #ifdef FEATURE_STARTPAGE
  3. #include "pidlbutton.h"
  4. #include <shellp.h>
  5. namespace DirectUI
  6. {
  7. int PIDLButton::s_nImageSize = 0;
  8. // Construction / Destruction
  9. //
  10. PIDLButton::~PIDLButton()
  11. {
  12. ILFree(_pidl);
  13. }
  14. HRESULT PIDLButton::Create(LPITEMIDLIST pidl, UINT nActive, OUT Element** ppElement)
  15. {
  16. *ppElement = NULL;
  17. PIDLButton* pb = HNew <PIDLButton>();
  18. if (!pb)
  19. return E_OUTOFMEMORY;
  20. HRESULT hr = pb->Initialize(pidl, nActive);
  21. if (FAILED(hr))
  22. {
  23. pb->Destroy();
  24. return hr;
  25. }
  26. *ppElement = pb;
  27. return S_OK;
  28. }
  29. HIMAGELIST GetSysImageList(UINT flags)
  30. {
  31. static HIMAGELIST s_imgList;
  32. static HIMAGELIST s_imgListSmall;
  33. if (!s_imgList)
  34. {
  35. Shell_GetImageLists(&s_imgList, &s_imgListSmall);
  36. }
  37. return (flags & SHGFI_SMALLICON) ? s_imgListSmall : s_imgList;
  38. }
  39. HRESULT PIDLButton::Initialize(LPITEMIDLIST pidl, UINT nActive)
  40. {
  41. _pidl = pidl;
  42. Layout* pbl = NULL;
  43. Element* peLabel = NULL;
  44. Element* peImage = NULL;
  45. Value* pvChildren;
  46. ElementList* pel;
  47. HRESULT hr = Button::Initialize(nActive);
  48. if (FAILED(hr))
  49. goto CleanUp;
  50. // Create children
  51. hr = Element::Create(0, &peLabel);
  52. if (FAILED(hr))
  53. goto CleanUp;
  54. hr = Element::Create(0, &peImage);
  55. if (FAILED(hr))
  56. goto CleanUp;
  57. // Create layout
  58. hr = BorderLayout::Create(&pbl);
  59. if (FAILED(hr))
  60. goto CleanUp;
  61. // Initialize
  62. SetLayout(pbl);
  63. // Setup children
  64. peImage->SetLayoutPos(BLP_Left);
  65. peImage->SetID(L"Image");
  66. peLabel->SetLayoutPos(BLP_Client);
  67. peLabel->SetID(L"Label");
  68. Add(peImage);
  69. Add(peLabel);
  70. pel = GetChildren(&pvChildren);
  71. // Initialize Shell's ImageList
  72. GetSysImageList(0);
  73. if (_pidl && pel && (pel->GetSize() >= 2))
  74. {
  75. IShellFolder *psf;
  76. LPCITEMIDLIST pidlItem;
  77. if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlItem)))
  78. {
  79. int iSysIndex = SHMapPIDLToSystemImageListIndex(psf, pidlItem, NULL);
  80. if (iSysIndex != -1)
  81. {
  82. HICON hi = ImageList_GetIcon(GetSysImageList(s_nImageSize), iSysIndex, 0);
  83. Value *pvalIcon = Value::CreateGraphic(hi);
  84. if (pvalIcon)
  85. {
  86. pel->GetItem(0)->SetValue(ContentProp, PI_Local, pvalIcon);
  87. pvalIcon->Release();
  88. }
  89. else
  90. {
  91. DestroyIcon(hi);
  92. }
  93. }
  94. TCHAR szOut[MAX_PATH];
  95. if (SUCCEEDED(DisplayNameOf(psf, pidlItem, SHGDN_NORMAL, szOut, ARRAYSIZE(szOut))))
  96. {
  97. pel->GetItem(1)->SetContentString(szOut);
  98. }
  99. psf->Release();
  100. }
  101. }
  102. pvChildren->Release();
  103. return hr;
  104. CleanUp:
  105. if (pbl)
  106. pbl->Destroy();
  107. if (peImage)
  108. peImage->Destroy();
  109. if (peLabel)
  110. peLabel->Destroy();
  111. return hr;
  112. }
  113. HRESULT PIDLButton::InvokePidl()
  114. {
  115. HRESULT hr = E_FAIL;
  116. IShellFolder *psf;
  117. LPCITEMIDLIST pidlShort;
  118. // Multi-level child pidl
  119. if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort)))
  120. {
  121. hr = SHInvokeDefaultCommand(GetHWND(), psf, pidlShort);
  122. psf->Release();
  123. }
  124. return hr;
  125. }
  126. HRESULT PIDLButton::OnContextMenu(POINT *ppt)
  127. {
  128. HRESULT hr = E_FAIL;
  129. IShellFolder *psf;
  130. LPCITEMIDLIST pidlShort;
  131. if (!GetHWND())
  132. return hr;
  133. if (ppt->x == -1) // Keyboard context menu
  134. {
  135. Value *pv;
  136. const SIZE *psize = GetExtent(&pv);
  137. ppt->x = psize->cx/2;
  138. ppt->y = psize->cy/2;
  139. pv->Release();
  140. }
  141. POINT pt;
  142. GetRoot()->MapElementPoint(this, ppt, &pt);
  143. ClientToScreen(GetHWND(), &pt);
  144. // Multi-level child pidl
  145. if (SUCCEEDED(SHBindToFolderIDListParent(NULL, _pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlShort)))
  146. {
  147. IContextMenu *pcm;
  148. if (SUCCEEDED(hr = psf->GetUIObjectOf(GetHWND(), 1, &pidlShort, IID_IContextMenu, NULL, (void **)&pcm)))
  149. {
  150. HMENU hmenu = ::CreatePopupMenu();
  151. if (hmenu)
  152. {
  153. UINT uFlags = CMF_NORMAL;
  154. if (GetKeyState(VK_SHIFT) < 0)
  155. {
  156. uFlags |= CMF_EXTENDEDVERBS;
  157. }
  158. #if 0 // REVIEW fabriced
  159. if (_dwFlags & HOSTF_CANRENAME)
  160. {
  161. uFlags |= CMF_CANRENAME;
  162. }
  163. #endif
  164. pcm->QueryContextMenu(hmenu, 0, IDM_QCM_MIN, IDM_QCM_MAX, uFlags);
  165. // Remove "Create shortcut" from context menu because it creates
  166. // the shortcut on the desktop, which the user can't see...
  167. ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("link"));
  168. // Remove "Cut" from context menu because we don't want objects
  169. // to be deleted.
  170. ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("cut"));
  171. // Change "Delete" to "Remove from this list".
  172. // If client doesn't support "delete" then nuke it outright.
  173. ContextMenu_DeleteCommandByName(pcm, hmenu, IDM_QCM_MIN, TEXT("delete"));
  174. #if 0 // REVIEW fabriced
  175. if (_dwFlags & HOSTF_CANDELETE)
  176. {
  177. if (LoadString(_Module.GetResourceInstance(), IDS_SFTHOST_REMOVEFROMLIST, szBuf, ARRAYSIZE(szBuf)))
  178. {
  179. ModifyMenu(hmenu, iposDelete, MF_BYPOSITION | MF_STRING, GetMenuItemID(hmenu, iposDelete), szBuf);
  180. }
  181. }
  182. else
  183. #endif
  184. _SHPrettyMenu(hmenu);
  185. ASSERT(_pcm2Pop == NULL); // Shouldn't be recursing
  186. pcm->QueryInterface(IID_PPV_ARG(IContextMenu2, &_pcm2Pop));
  187. ASSERT(_pcm3Pop == NULL); // Shouldn't be recursing
  188. pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3Pop));
  189. GetHWNDHost()->WndProc(GetHWND(), PBM_SETMENUFORWARD, 0, (LPARAM)this);
  190. int idCmd = TrackPopupMenuEx(hmenu,
  191. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  192. pt.x, pt.y, GetHWND(), NULL);
  193. if (idCmd >= IDM_QCM_MIN && idCmd < IDM_QCM_MAX)
  194. {
  195. idCmd -= IDM_QCM_MIN;
  196. CMINVOKECOMMANDINFOEX ici = {
  197. sizeof(ici), // cbSize
  198. CMIC_MASK_ASYNCOK, // fMask
  199. GetHWND(), // hwnd
  200. (LPCSTR)IntToPtr(idCmd),// lpVerb
  201. NULL, // lpParameters
  202. NULL, // lpDirectory
  203. SW_SHOWDEFAULT, // nShow
  204. 0, // dwHotKey
  205. 0, // hIcon
  206. NULL, // lpTitle
  207. (LPCWSTR)IntToPtr(idCmd),// lpVerbW
  208. NULL, // lpParametersW
  209. NULL, // lpDirectoryW
  210. NULL, // lpTitleW
  211. { pt.x, pt.y }, // ptInvoke
  212. };
  213. #if 0 // REVIEW fabriced
  214. if (_dwFlags & (HOSTF_CANDELETE | HOSTF_CANRENAME))
  215. {
  216. ContextMenu_GetCommandStringVerb(pcm, idCmd, szBuf, ARRAYSIZE(szBuf));
  217. }
  218. if ((_dwFlags & HOSTF_CANDELETE) &&
  219. StrCmpI(szBuf, TEXT("delete")) == 0)
  220. {
  221. ContextMenuDeleteItem(pitem, pcm, &ici);
  222. SMNMCOMMANDINVOKED ci;
  223. ListView_GetItemRect(_hwndList, iItem, &ci.rcItem, LVIR_BOUNDS);
  224. MapWindowRect(_hwndList, NULL, &ci.rcItem);
  225. _SendNotify(_hwnd, SMN_COMMANDINVOKED, &ci);
  226. }
  227. else if ((_dwFlags & HOSTF_CANRENAME) &&
  228. StrCmpI(szBuf, TEXT("rename")) == 0)
  229. {
  230. ListView_EditLabel(_hwndList, iItem);
  231. }
  232. else
  233. #endif
  234. {
  235. pcm->InvokeCommand(reinterpret_cast<LPCMINVOKECOMMANDINFO>(&ici));
  236. }
  237. }
  238. DestroyMenu(hmenu);
  239. GetHWNDHost()->WndProc(GetHWND(), PBM_SETMENUFORWARD, 0, (LPARAM)NULL);
  240. ATOMICRELEASE(_pcm2Pop);
  241. ATOMICRELEASE(_pcm3Pop);
  242. }
  243. pcm->Release();
  244. }
  245. psf->Release();
  246. }
  247. return hr;
  248. }
  249. LRESULT PIDLButton::OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  250. {
  251. LRESULT lres;
  252. if (_pcm3Pop && SUCCEEDED(_pcm3Pop->HandleMenuMsg2(uMsg, wParam, lParam, &lres)))
  253. {
  254. return lres;
  255. }
  256. if (_pcm2Pop && SUCCEEDED(_pcm2Pop->HandleMenuMsg(uMsg, wParam, lParam)))
  257. {
  258. return 0;
  259. }
  260. return 0;
  261. }
  262. ////////////////////////////////////////////////////////
  263. // System events
  264. void PIDLButton::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  265. {
  266. // Do default processing
  267. Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  268. }
  269. // Pointer is only guaranteed good for the lifetime of the call
  270. void PIDLButton::OnEvent(Event *pEvent)
  271. {
  272. if ((pEvent->peTarget == this) && (pEvent->uidType == Button::Click))
  273. {
  274. // execute pidl
  275. InvokePidl();
  276. pEvent->fHandled = true;
  277. return;
  278. }
  279. else if ((pEvent->peTarget == this) && (pEvent->uidType == Button::Context))
  280. {
  281. ButtonContextEvent *peButton = reinterpret_cast<ButtonContextEvent *>(pEvent);
  282. OnContextMenu(&peButton->pt);
  283. return;
  284. }
  285. Button::OnEvent(pEvent);
  286. }
  287. void PIDLButton::OnInput(InputEvent* pie)
  288. {
  289. // Fabrice, I will be putting right button click support for context menu here -- I'll have it for you Monday
  290. Button::OnInput(pie);
  291. }
  292. ////////////////////////////////////////////////////////
  293. // Property definitions
  294. /** Property template (replace !!!), also update private PropertyInfo* parray and class header (element.h)
  295. // !!! property
  296. static int vv!!![] = { DUIV_INT, -1 }; StaticValue(svDefault!!!, DUIV_INT, 0);
  297. static PropertyInfo imp!!!Prop = { L"!!!", PF_Normal, 0, vv!!!, (Value*)&svDefault!!! };
  298. PropertyInfo* Element::!!!Prop = &imp!!!Prop;
  299. **/
  300. ////////////////////////////////////////////////////////
  301. // ClassInfo (must appear after property definitions)
  302. // Class properties
  303. // Define class info with type and base type, set static class pointer
  304. IClassInfo* PIDLButton::Class = NULL;
  305. HRESULT PIDLButton::Register()
  306. {
  307. return ClassInfo<PIDLButton,Button>::Register(L"PIDLButton", NULL, 0);
  308. }
  309. } // namespace DirectUI
  310. #endif // FEATURE_STARTPAGE