[SHELL32_NEW]
[reactos.git] / dll / win32 / shell32 / shlview.cpp
1 /*
2 * ShellView
3 *
4 * Copyright 1998,1999 <juergen.schmied@debitel.net>
5 *
6 * This is the view visualizing the data provided by the shellfolder.
7 * No direct access to data from pidls should be done from here.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 *
23 * FIXME: The order by part of the background context menu should be
24 * built according to the columns shown.
25 *
26 * FIXME: CheckToolbar: handle the "new folder" and "folder up" button
27 *
28 * FIXME: ShellView_FillList: consider sort orders
29 */
30
31 /*
32 TODO:
33 1. Load/Save the view state from/into the stream provided by the ShellBrowser.
34 2. Let the shell folder sort items.
35 3. Code to merge menus in the shellbrowser is incorrect.
36 4. Move the background context menu creation into shell view. It should store the
37 shell view HWND to send commands.
38 5. Send init, measure, and draw messages to context menu during tracking.
39 6. Shell view should do SetCommandTarget on internet toolbar.
40 7. When editing starts on item, set edit text to for editing value.
41 8. When shell view is called back for item info, let listview save the value.
42 9. Shell view should update status bar.
43 10. Fix shell view to handle view mode popup exec.
44 11. The background context menu should have a pidl just like foreground menus. This
45 causes crashes when dynamic handlers try to use the NULL pidl.
46 12. The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
47 annoying flashing of blue even on XP, and is not correct.
48 13. Reorder of columns doesn't work - might be bug in comctl32
49 */
50
51 #include <precomp.h>
52 #include <tchar.h>
53 #include <atlbase.h>
54 #include <atlcom.h>
55 #include <atlwin.h>
56 #include "shlwapi_undoc.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(shell);
59
60 #undef SV_CLASS_NAME
61
62 static const WCHAR SV_CLASS_NAME[] = {'S','H','E','L','L','D','L','L','_','D','e','f','V','i','e','w',0};
63
64 typedef struct
65 { BOOL bIsAscending;
66 INT nHeaderID;
67 INT nLastHeaderID;
68 }LISTVIEW_SORT_INFO, *LPLISTVIEW_SORT_INFO;
69
70 #define SHV_CHANGE_NOTIFY WM_USER + 0x1111
71
72 class CDefView :
73 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
74 public CComObjectRootEx<CComMultiThreadModelNoCS>,
75 public IShellView,
76 public IFolderView,
77 public IOleCommandTarget,
78 public IDropTarget,
79 public IDropSource,
80 public IViewObject,
81 public IServiceProvider
82 {
83 private:
84 CComPtr<IShellFolder> pSFParent;
85 CComPtr<IShellFolder2> pSF2Parent;
86 CComPtr<IShellBrowser> pShellBrowser;
87 CComPtr<ICommDlgBrowser> pCommDlgBrowser;
88 HWND hWndList; /* ListView control */
89 HWND hWndParent;
90 FOLDERSETTINGS FolderSettings;
91 HMENU hMenu;
92 UINT uState;
93 UINT cidl;
94 LPITEMIDLIST *apidl;
95 LISTVIEW_SORT_INFO ListViewSortInfo;
96 ULONG hNotify; /* change notification handle */
97 HANDLE hAccel;
98 DWORD dwAspects;
99 DWORD dwAdvf;
100 CComPtr<IAdviseSink> pAdvSink;
101 // for drag and drop
102 CComPtr<IDropTarget> pCurDropTarget; /* The sub-item, which is currently dragged over */
103 CComPtr<IDataObject> pCurDataObject; /* The dragged data-object */
104 LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */
105 UINT cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
106 POINT ptLastMousePos; /* Mouse position at last DragOver call */
107 //
108 CComPtr<IContextMenu2> pCM;
109 public:
110 CDefView();
111 ~CDefView();
112 HRESULT WINAPI Initialize(IShellFolder *shellFolder);
113 HRESULT IncludeObject(LPCITEMIDLIST pidl);
114 HRESULT OnDefaultCommand();
115 HRESULT OnStateChange(UINT uFlags);
116 void CheckToolbar();
117 void SetStyle(DWORD dwAdd, DWORD dwRemove);
118 BOOL CreateList();
119 BOOL InitList();
120 static INT CALLBACK CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
121 static INT CALLBACK ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
122 int LV_FindItemByPidl(LPCITEMIDLIST pidl);
123 BOOLEAN LV_AddItem(LPCITEMIDLIST pidl);
124 BOOLEAN LV_DeleteItem(LPCITEMIDLIST pidl);
125 BOOLEAN LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew);
126 static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg);
127 HRESULT FillList();
128 HMENU BuildFileMenu();
129 void MergeFileMenu(HMENU hSubMenu);
130 void MergeViewMenu(HMENU hSubMenu);
131 UINT GetSelections();
132 HRESULT OpenSelectedItems();
133 void OnDeactivate();
134 void DoActivate(UINT uState);
135 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
136
137 // *** IOleWindow methods ***
138 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
139 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
140
141 // *** IShellView methods ***
142 virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG *pmsg);
143 virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable);
144 virtual HRESULT STDMETHODCALLTYPE UIActivate(UINT uState);
145 virtual HRESULT STDMETHODCALLTYPE Refresh();
146 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
147 virtual HRESULT STDMETHODCALLTYPE DestroyViewWindow();
148 virtual HRESULT STDMETHODCALLTYPE GetCurrentInfo(LPFOLDERSETTINGS pfs);
149 virtual HRESULT STDMETHODCALLTYPE AddPropertySheetPages(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam);
150 virtual HRESULT STDMETHODCALLTYPE SaveViewState();
151 virtual HRESULT STDMETHODCALLTYPE SelectItem(LPCITEMIDLIST pidlItem, SVSIF uFlags);
152 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
153
154 // *** IFolderView methods ***
155 virtual HRESULT STDMETHODCALLTYPE GetCurrentViewMode(UINT *pViewMode);
156 virtual HRESULT STDMETHODCALLTYPE SetCurrentViewMode(UINT ViewMode);
157 virtual HRESULT STDMETHODCALLTYPE GetFolder(REFIID riid, void **ppv);
158 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, LPITEMIDLIST *ppidl);
159 virtual HRESULT STDMETHODCALLTYPE ItemCount(UINT uFlags, int *pcItems);
160 virtual HRESULT STDMETHODCALLTYPE Items(UINT uFlags, REFIID riid, void **ppv);
161 virtual HRESULT STDMETHODCALLTYPE GetSelectionMarkedItem(int *piItem);
162 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
163 virtual HRESULT STDMETHODCALLTYPE GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt);
164 virtual HRESULT STDMETHODCALLTYPE GetSpacing(POINT *ppt);
165 virtual HRESULT STDMETHODCALLTYPE GetDefaultSpacing(POINT *ppt);
166 virtual HRESULT STDMETHODCALLTYPE GetAutoArrange();
167 virtual HRESULT STDMETHODCALLTYPE SelectItem(int iItem, DWORD dwFlags);
168 virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags);
169
170 // *** IOleCommandTarget methods ***
171 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
172 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
173
174 // *** IDropTarget methods ***
175 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
176 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
177 virtual HRESULT STDMETHODCALLTYPE DragLeave();
178 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
179
180 // *** IDropSource methods ***
181 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
182 virtual HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
183
184 // *** IViewObject methods ***
185 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
186 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
187 BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
188 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
189 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
190 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
191 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
192 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
193 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
194
195 // *** IServiceProvider methods ***
196 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
197
198 // message handlers
199 LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
200 LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
201 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
202 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
203 LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
204 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
205 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
206 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
207 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
208 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
209 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
210 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
211 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
212 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
213 LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
214
215 static ATL::CWndClassInfo& GetWndClassInfo()
216 {
217 static ATL::CWndClassInfo wc =
218 {
219 { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, StartWindowProc,
220 0, 0, NULL, NULL,
221 LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_BACKGROUND + 1), NULL, SV_CLASS_NAME, NULL },
222 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
223 };
224 return wc;
225 }
226
227 virtual WNDPROC GetWindowProc()
228 {
229 return WindowProc;
230 }
231
232 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
233 {
234 CDefView *pThis;
235 LRESULT result;
236
237 // must hold a reference during message handling
238 pThis = reinterpret_cast<CDefView *>(hWnd);
239 pThis->AddRef();
240 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
241 pThis->Release();
242 return result;
243 }
244
245 BEGIN_MSG_MAP(CDefView)
246 MESSAGE_HANDLER(WM_SIZE, OnSize)
247 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
248 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
249 MESSAGE_HANDLER(WM_CREATE, OnCreate)
250 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
251 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
252 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
253 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
254 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
255 MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem)
256 MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem)
257 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
258 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
259 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
260 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
261 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser)
262 END_MSG_MAP()
263
264 BEGIN_COM_MAP(CDefView)
265 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
266 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
267 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
268 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
269 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
270 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
271 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject)
272 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
273 END_COM_MAP()
274 };
275
276 /* ListView Header ID's */
277 #define LISTVIEW_COLUMN_NAME 0
278 #define LISTVIEW_COLUMN_SIZE 1
279 #define LISTVIEW_COLUMN_TYPE 2
280 #define LISTVIEW_COLUMN_TIME 3
281 #define LISTVIEW_COLUMN_ATTRIB 4
282
283 /*menu items */
284 #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
285 #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
286 #define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
287
288 #define ID_LISTVIEW 1
289
290 /*windowsx.h */
291 #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
292 #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
293 #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
294
295 /*
296 Items merged into the toolbar and the filemenu
297 */
298 typedef struct
299 { int idCommand;
300 int iImage;
301 int idButtonString;
302 int idMenuString;
303 BYTE bState;
304 BYTE bStyle;
305 } MYTOOLINFO, *LPMYTOOLINFO;
306
307 static const MYTOOLINFO Tools[] =
308 {
309 { FCIDM_SHVIEW_BIGICON, 0, 0, IDS_VIEW_LARGE, TBSTATE_ENABLED, BTNS_BUTTON },
310 { FCIDM_SHVIEW_SMALLICON, 0, 0, IDS_VIEW_SMALL, TBSTATE_ENABLED, BTNS_BUTTON },
311 { FCIDM_SHVIEW_LISTVIEW, 0, 0, IDS_VIEW_LIST, TBSTATE_ENABLED, BTNS_BUTTON },
312 { FCIDM_SHVIEW_REPORTVIEW, 0, 0, IDS_VIEW_DETAILS, TBSTATE_ENABLED, BTNS_BUTTON },
313 { -1, 0, 0, 0, 0, 0}
314 };
315
316 typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
317
318 CDefView::CDefView()
319 {
320 hWndList = NULL;
321 hWndParent = NULL;
322 FolderSettings.fFlags = 0;
323 FolderSettings.ViewMode = 0;
324 hMenu = NULL;
325 uState = 0;
326 cidl = 0;
327 apidl = NULL;
328 ListViewSortInfo.bIsAscending = FALSE;
329 ListViewSortInfo.nHeaderID = 0;
330 ListViewSortInfo.nLastHeaderID = 0;
331 hNotify = 0;
332 hAccel = NULL;
333 dwAspects = 0;
334 dwAdvf = 0;
335 iDragOverItem = 0;
336 cScrollDelay = 0;
337 ptLastMousePos.x = 0;
338 ptLastMousePos.y = 0;
339 }
340
341 CDefView::~CDefView()
342 {
343 TRACE(" destroying IShellView(%p)\n", this);
344
345 SHFree(apidl);
346 }
347
348 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
349 {
350 pSFParent = shellFolder;
351 shellFolder->QueryInterface(IID_IShellFolder2, (LPVOID *)&pSF2Parent);
352 return S_OK;
353 }
354
355 /**********************************************************
356 *
357 * ##### helperfunctions for communication with ICommDlgBrowser #####
358 */
359 HRESULT CDefView::IncludeObject(LPCITEMIDLIST pidl)
360 {
361 HRESULT ret = S_OK;
362
363 if (pCommDlgBrowser.p != NULL)
364 {
365 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
366 ret = pCommDlgBrowser->IncludeObject((IShellView *)this, pidl);
367 TRACE("--0x%08x\n", ret);
368 }
369 return ret;
370 }
371
372 HRESULT CDefView::OnDefaultCommand()
373 {
374 HRESULT ret = S_FALSE;
375
376 if (pCommDlgBrowser.p != NULL)
377 {
378 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
379 ret = pCommDlgBrowser->OnDefaultCommand((IShellView *)this);
380 TRACE("-- returns %08x\n", ret);
381 }
382 return ret;
383 }
384
385 HRESULT CDefView::OnStateChange(UINT uFlags)
386 {
387 HRESULT ret = S_FALSE;
388
389 if (pCommDlgBrowser.p != NULL)
390 {
391 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
392 ret = pCommDlgBrowser->OnStateChange((IShellView *)this, uFlags);
393 TRACE("--\n");
394 }
395 return ret;
396 }
397 /**********************************************************
398 * set the toolbar of the filedialog buttons
399 *
400 * - activates the buttons from the shellbrowser according to
401 * the view state
402 */
403 void CDefView::CheckToolbar()
404 {
405 LRESULT result;
406
407 TRACE("\n");
408
409 if (pCommDlgBrowser != NULL)
410 {
411 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
412 FCIDM_TB_SMALLICON, (FolderSettings.ViewMode==FVM_LIST)? TRUE : FALSE, &result);
413 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
414 FCIDM_TB_REPORTVIEW, (FolderSettings.ViewMode==FVM_DETAILS)? TRUE : FALSE, &result);
415 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
416 FCIDM_TB_SMALLICON, TRUE, &result);
417 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
418 FCIDM_TB_REPORTVIEW, TRUE, &result);
419 }
420 }
421
422 /**********************************************************
423 *
424 * ##### helperfunctions for initializing the view #####
425 */
426 /**********************************************************
427 * change the style of the listview control
428 */
429 void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
430 {
431 DWORD tmpstyle;
432
433 TRACE("(%p)\n", this);
434
435 tmpstyle = ::GetWindowLongPtrW(hWndList, GWL_STYLE);
436 ::SetWindowLongPtrW(hWndList, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
437 }
438
439 /**********************************************************
440 * ShellView_CreateList()
441 *
442 * - creates the list view window
443 */
444 BOOL CDefView::CreateList()
445 { DWORD dwStyle, dwExStyle;
446
447 TRACE("%p\n",this);
448
449 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
450 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
451 dwExStyle = WS_EX_CLIENTEDGE;
452
453 if (FolderSettings.fFlags & FWF_DESKTOP)
454 dwStyle |= LVS_ALIGNLEFT;
455 else
456 dwStyle |= LVS_ALIGNTOP;
457
458 switch (FolderSettings.ViewMode)
459 {
460 case FVM_ICON: dwStyle |= LVS_ICON; break;
461 case FVM_DETAILS: dwStyle |= LVS_REPORT; break;
462 case FVM_SMALLICON: dwStyle |= LVS_SMALLICON; break;
463 case FVM_LIST: dwStyle |= LVS_LIST; break;
464 default: dwStyle |= LVS_LIST; break;
465 }
466
467 if (FolderSettings.fFlags & FWF_AUTOARRANGE) dwStyle |= LVS_AUTOARRANGE;
468 if (FolderSettings.fFlags & FWF_DESKTOP)
469 FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
470 if (FolderSettings.fFlags & FWF_SINGLESEL) dwStyle |= LVS_SINGLESEL;
471 if (FolderSettings.fFlags & FWF_NOCLIENTEDGE)
472 dwExStyle &= ~WS_EX_CLIENTEDGE;
473
474 hWndList=CreateWindowExW( dwExStyle,
475 WC_LISTVIEWW,
476 NULL,
477 dwStyle,
478 0,0,0,0,
479 m_hWnd,
480 (HMENU)ID_LISTVIEW,
481 shell32_hInstance,
482 NULL);
483
484 if(!hWndList)
485 return FALSE;
486
487 ListViewSortInfo.bIsAscending = TRUE;
488 ListViewSortInfo.nHeaderID = -1;
489 ListViewSortInfo.nLastHeaderID = -1;
490
491 if (FolderSettings.fFlags & FWF_DESKTOP) {
492 /*
493 * FIXME: look at the registry value
494 * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ListviewShadow
495 * and activate drop shadows if necessary
496 */
497 if (1)
498 {
499 SendMessageW(hWndList, LVM_SETTEXTBKCOLOR, 0, CLR_NONE);
500 SendMessageW(hWndList, LVM_SETBKCOLOR, 0, CLR_NONE);
501 }
502 else
503 {
504 SendMessageW(hWndList, LVM_SETTEXTBKCOLOR, 0, GetSysColor(COLOR_DESKTOP));
505 SendMessageW(hWndList, LVM_SETBKCOLOR, 0, GetSysColor(COLOR_DESKTOP));
506 }
507
508 SendMessageW(hWndList, LVM_SETTEXTCOLOR, 0, RGB(255,255,255));
509 }
510
511 /* UpdateShellSettings(); */
512 return TRUE;
513 }
514
515 /**********************************************************
516 * ShellView_InitList()
517 *
518 * - adds all needed columns to the shellview
519 */
520 BOOL CDefView::InitList()
521 {
522 LVCOLUMNW lvColumn;
523 SHELLDETAILS sd;
524 int i;
525 WCHAR szTemp[50];
526
527 TRACE("%p\n",this);
528
529 SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
530
531 lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
532 lvColumn.pszText = szTemp;
533
534 if (pSF2Parent)
535 {
536 for (i=0; 1; i++)
537 {
538 if (FAILED(pSF2Parent->GetDetailsOf(NULL, i, &sd)))
539 break;
540 lvColumn.fmt = sd.fmt;
541 lvColumn.cx = sd.cxChar*8; /* chars->pixel */
542 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
543 SendMessageW(hWndList, LVM_INSERTCOLUMNW, i, (LPARAM) &lvColumn);
544 }
545 }
546 else
547 {
548 FIXME("no SF2\n");
549 }
550
551 SendMessageW(hWndList, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)ShellSmallIconList);
552 SendMessageW(hWndList, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)ShellBigIconList);
553
554 return TRUE;
555 }
556
557 /**********************************************************
558 * ShellView_CompareItems()
559 *
560 * NOTES
561 * internal, CALLBACK for DSA_Sort
562 */
563 INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
564 {
565 int ret;
566 TRACE("pidl1=%p pidl2=%p lpsf=%p\n", lParam1, lParam2, (LPVOID) lpData);
567
568 if(!lpData) return 0;
569
570 ret = (SHORT)SCODE_CODE(((IShellFolder *)lpData)->CompareIDs(0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2));
571 TRACE("ret=%i\n",ret);
572 return ret;
573 }
574
575 /*************************************************************************
576 * ShellView_ListViewCompareItems
577 *
578 * Compare Function for the Listview (FileOpen Dialog)
579 *
580 * PARAMS
581 * lParam1 [I] the first ItemIdList to compare with
582 * lParam2 [I] the second ItemIdList to compare with
583 * lpData [I] The column ID for the header Ctrl to process
584 *
585 * RETURNS
586 * A negative value if the first item should precede the second,
587 * a positive value if the first item should follow the second,
588 * or zero if the two items are equivalent
589 *
590 * NOTES
591 * FIXME: function does what ShellView_CompareItems is supposed to do.
592 * unify it and figure out how to use the undocumented first parameter
593 * of IShellFolder_CompareIDs to do the job this function does and
594 * move this code to IShellFolder.
595 * make LISTVIEW_SORT_INFO obsolete
596 * the way this function works is only usable if we had only
597 * filesystemfolders (25/10/99 jsch)
598 */
599 INT CALLBACK CDefView::ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
600 {
601 INT nDiff=0;
602 FILETIME fd1, fd2;
603 char strName1[MAX_PATH], strName2[MAX_PATH];
604 BOOL bIsFolder1, bIsFolder2,bIsBothFolder;
605 LPITEMIDLIST pItemIdList1 = (LPITEMIDLIST) lParam1;
606 LPITEMIDLIST pItemIdList2 = (LPITEMIDLIST) lParam2;
607 LISTVIEW_SORT_INFO *pSortInfo = (LPLISTVIEW_SORT_INFO) lpData;
608
609
610 bIsFolder1 = _ILIsFolder(pItemIdList1);
611 bIsFolder2 = _ILIsFolder(pItemIdList2);
612 bIsBothFolder = bIsFolder1 && bIsFolder2;
613
614 /* When sorting between a File and a Folder, the Folder gets sorted first */
615 if( (bIsFolder1 || bIsFolder2) && !bIsBothFolder)
616 {
617 nDiff = bIsFolder1 ? -1 : 1;
618 }
619 else
620 {
621 /* Sort by Time: Folders or Files can be sorted */
622
623 if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TIME)
624 {
625 _ILGetFileDateTime(pItemIdList1, &fd1);
626 _ILGetFileDateTime(pItemIdList2, &fd2);
627 nDiff = CompareFileTime(&fd2, &fd1);
628 }
629 /* Sort by Attribute: Folder or Files can be sorted */
630 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_ATTRIB)
631 {
632 _ILGetFileAttributes(pItemIdList1, strName1, MAX_PATH);
633 _ILGetFileAttributes(pItemIdList2, strName2, MAX_PATH);
634 nDiff = lstrcmpiA(strName1, strName2);
635 }
636 /* Sort by FileName: Folder or Files can be sorted */
637 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_NAME || bIsBothFolder)
638 {
639 /* Sort by Text */
640 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
641 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
642 nDiff = lstrcmpiA(strName1, strName2);
643 }
644 /* Sort by File Size, Only valid for Files */
645 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_SIZE)
646 {
647 nDiff = (INT)(_ILGetFileSize(pItemIdList1, NULL, 0) - _ILGetFileSize(pItemIdList2, NULL, 0));
648 }
649 /* Sort by File Type, Only valid for Files */
650 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TYPE)
651 {
652 /* Sort by Type */
653 _ILGetFileType(pItemIdList1, strName1, MAX_PATH);
654 _ILGetFileType(pItemIdList2, strName2, MAX_PATH);
655 nDiff = lstrcmpiA(strName1, strName2);
656 }
657 }
658 /* If the Date, FileSize, FileType, Attrib was the same, sort by FileName */
659
660 if(nDiff == 0)
661 {
662 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
663 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
664 nDiff = lstrcmpiA(strName1, strName2);
665 }
666
667 if(!pSortInfo->bIsAscending)
668 {
669 nDiff = -nDiff;
670 }
671
672 return nDiff;
673
674 }
675
676 /**********************************************************
677 * LV_FindItemByPidl()
678 */
679 int CDefView::LV_FindItemByPidl(LPCITEMIDLIST pidl)
680 {
681 LVITEMW lvItem;
682 lvItem.iSubItem = 0;
683 lvItem.mask = LVIF_PARAM;
684 for(lvItem.iItem = 0;
685 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
686 lvItem.iItem++)
687 {
688 LPITEMIDLIST currentpidl = (LPITEMIDLIST) lvItem.lParam;
689 HRESULT hr = pSFParent->CompareIDs(0, pidl, currentpidl);
690 if(SUCCEEDED(hr) && !HRESULT_CODE(hr))
691 {
692 return lvItem.iItem;
693 }
694 }
695 return -1;
696 }
697
698 /**********************************************************
699 * LV_AddItem()
700 */
701 BOOLEAN CDefView::LV_AddItem(LPCITEMIDLIST pidl)
702 {
703 LVITEMW lvItem;
704
705 TRACE("(%p)(pidl=%p)\n", this, pidl);
706
707 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
708 lvItem.iItem = ListView_GetItemCount(hWndList); /*add the item to the end of the list*/
709 lvItem.iSubItem = 0;
710 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidl)); /*set the item's data*/
711 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
712 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
713 if (SendMessageW(hWndList, LVM_INSERTITEMW, 0, (LPARAM)&lvItem) == -1)
714 return FALSE;
715 else
716 return TRUE;
717 }
718
719 /**********************************************************
720 * LV_DeleteItem()
721 */
722 BOOLEAN CDefView::LV_DeleteItem(LPCITEMIDLIST pidl)
723 {
724 int nIndex;
725
726 TRACE("(%p)(pidl=%p)\n", this, pidl);
727
728 nIndex = LV_FindItemByPidl(ILFindLastID(pidl));
729 return (-1 == ListView_DeleteItem(hWndList, nIndex)) ? FALSE : TRUE;
730 }
731
732 /**********************************************************
733 * LV_RenameItem()
734 */
735 BOOLEAN CDefView::LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew)
736 {
737 int nItem;
738 LVITEMW lvItem;
739
740 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
741
742 nItem = LV_FindItemByPidl(ILFindLastID(pidlOld));
743 if ( -1 != nItem )
744 {
745 lvItem.mask = LVIF_PARAM; /* only the pidl */
746 lvItem.iItem = nItem;
747 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
748
749 SHFree((LPITEMIDLIST)lvItem.lParam);
750 lvItem.mask = LVIF_PARAM;
751 lvItem.iItem = nItem;
752 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidlNew)); /* set the item's data */
753 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
754 SendMessageW(hWndList, LVM_UPDATE, nItem, 0);
755 return TRUE; /* FIXME: better handling */
756 }
757 return FALSE;
758 }
759
760 /**********************************************************
761 * ShellView_FillList()
762 *
763 * - gets the objectlist from the shellfolder
764 * - sorts the list
765 * - fills the list into the view
766 */
767 INT CALLBACK CDefView::fill_list( LPVOID ptr, LPVOID arg )
768 {
769 LPITEMIDLIST pidl = (LPITEMIDLIST)ptr;
770 CDefView *pThis = (CDefView *)arg;
771 /* in a commdlg This works as a filemask*/
772 if ( pThis->IncludeObject(pidl)==S_OK ) pThis->LV_AddItem(pidl);
773 SHFree(pidl);
774 return TRUE;
775 }
776
777 HRESULT CDefView::FillList()
778 {
779 LPENUMIDLIST pEnumIDList;
780 LPITEMIDLIST pidl;
781 DWORD dwFetched;
782 HRESULT hRes;
783 HDPA hdpa;
784
785 TRACE("%p\n",this);
786
787 /* get the itemlist from the shfolder*/
788 hRes = pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
789 if (hRes != S_OK)
790 {
791 if (hRes==S_FALSE)
792 return(NOERROR);
793 return(hRes);
794 }
795
796 /* create a pointer array */
797 hdpa = DPA_Create(16);
798 if (!hdpa)
799 {
800 return(E_OUTOFMEMORY);
801 }
802
803 /* copy the items into the array*/
804 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
805 {
806 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
807 {
808 SHFree(pidl);
809 }
810 }
811
812 /* sort the array */
813 DPA_Sort(hdpa, CompareItems, (LPARAM)pSFParent.p);
814
815 /*turn the listview's redrawing off*/
816 SendMessageA(hWndList, WM_SETREDRAW, FALSE, 0);
817
818 DPA_DestroyCallback( hdpa, fill_list, (void *)this);
819
820 /*turn the listview's redrawing back on and force it to draw*/
821 SendMessageA(hWndList, WM_SETREDRAW, TRUE, 0);
822
823 pEnumIDList->Release(); /* destroy the list*/
824
825 return S_OK;
826 }
827
828 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
829 {
830 ::UpdateWindow(hWndList);
831 bHandled = FALSE;
832 return 0;
833 }
834
835 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
836 {
837 return SendMessageW(hWndList, uMsg, 0, 0);
838 }
839
840 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
841 {
842 RevokeDragDrop(m_hWnd);
843 SHChangeNotifyDeregister(hNotify);
844 bHandled = FALSE;
845 return 0;
846 }
847
848 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
849 {
850 if (FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
851 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
852
853 bHandled = FALSE;
854 return 0;
855 }
856
857 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
858 {
859 return (LRESULT)pShellBrowser.p;
860 }
861
862 /**********************************************************
863 * ShellView_OnCreate()
864 */
865 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
866 {
867 CComPtr<IDropTarget> pdt;
868 SHChangeNotifyEntry ntreg;
869 CComPtr<IPersistFolder2> ppf2;
870
871 TRACE("%p\n",this);
872
873 if(CreateList())
874 {
875 if(InitList())
876 {
877 FillList();
878 }
879 }
880
881 if (SUCCEEDED(this->QueryInterface(IID_IDropTarget, (LPVOID*)&pdt)))
882 RegisterDragDrop(m_hWnd, pdt);
883
884 /* register for receiving notifications */
885 pSFParent->QueryInterface(IID_IPersistFolder2, (LPVOID*)&ppf2);
886 if (ppf2)
887 {
888 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
889 ntreg.fRecursive = TRUE;
890 hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
891 SHFree((LPITEMIDLIST)ntreg.pidl);
892 }
893
894 hAccel = LoadAcceleratorsA(shell32_hInstance, "shv_accel");
895
896 return S_OK;
897 }
898
899 /**********************************************************
900 * #### Handling of the menus ####
901 */
902
903 /**********************************************************
904 * ShellView_BuildFileMenu()
905 */
906 HMENU CDefView::BuildFileMenu()
907 { WCHAR szText[MAX_PATH];
908 MENUITEMINFOW mii;
909 int nTools,i;
910 HMENU hSubMenu;
911
912 TRACE("(%p)\n",this);
913
914 hSubMenu = CreatePopupMenu();
915 if(hSubMenu)
916 { /*get the number of items in our global array*/
917 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++){}
918
919 /*add the menu items*/
920 for(i = 0; i < nTools; i++)
921 {
922 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
923
924 ZeroMemory(&mii, sizeof(mii));
925 mii.cbSize = sizeof(mii);
926 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
927
928 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
929 {
930 mii.fType = MFT_STRING;
931 mii.fState = MFS_ENABLED;
932 mii.dwTypeData = szText;
933 mii.wID = Tools[i].idCommand;
934 }
935 else
936 {
937 mii.fType = MFT_SEPARATOR;
938 }
939 /* tack This item onto the end of the menu */
940 InsertMenuItemW(hSubMenu, (UINT)-1, TRUE, &mii);
941 }
942 }
943 TRACE("-- return (menu=%p)\n",hSubMenu);
944 return hSubMenu;
945 }
946
947 /**********************************************************
948 * ShellView_MergeFileMenu()
949 */
950 void CDefView::MergeFileMenu(HMENU hSubMenu)
951 { TRACE("(%p)->(submenu=%p) stub\n",this,hSubMenu);
952
953 if(hSubMenu)
954 { /*insert This item at the beginning of the menu */
955 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
956 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
957
958 }
959 TRACE("--\n");
960 }
961
962 /**********************************************************
963 * ShellView_MergeViewMenu()
964 */
965 void CDefView::MergeViewMenu(HMENU hSubMenu)
966 {
967 TRACE("(%p)->(submenu=%p)\n",this,hSubMenu);
968
969 if(hSubMenu)
970 { /*add a separator at the correct position in the menu*/
971 MENUITEMINFOW mii;
972 static WCHAR view[] = L"View";
973
974 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
975
976 ZeroMemory(&mii, sizeof(mii));
977 mii.cbSize = sizeof(mii);
978 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
979 mii.fType = MFT_STRING;
980 mii.dwTypeData = view;
981 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
982 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
983 }
984 }
985
986 /**********************************************************
987 * ShellView_GetSelections()
988 *
989 * - fills the this->apidl list with the selected objects
990 *
991 * RETURNS
992 * number of selected items
993 */
994 UINT CDefView::GetSelections()
995 {
996 LVITEMW lvItem;
997 UINT i = 0;
998
999 SHFree(apidl);
1000
1001 cidl = ListView_GetSelectedCount(hWndList);
1002 apidl = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1003
1004 TRACE("selected=%i\n", cidl);
1005
1006 if(apidl)
1007 {
1008 TRACE("-- Items selected =%u\n", cidl);
1009
1010 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1011 lvItem.stateMask = LVIS_SELECTED;
1012 lvItem.iItem = 0;
1013 lvItem.iSubItem = 0;
1014
1015 while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < cidl))
1016 {
1017 if(lvItem.state & LVIS_SELECTED)
1018 {
1019 apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1020 i++;
1021 if (i == cidl)
1022 break;
1023 TRACE("-- selected Item found\n");
1024 }
1025 lvItem.iItem++;
1026 }
1027 }
1028 return cidl;
1029
1030 }
1031
1032 /**********************************************************
1033 * ShellView_OpenSelectedItems()
1034 */
1035 HRESULT CDefView::OpenSelectedItems()
1036 {
1037 static UINT CF_IDLIST = 0;
1038 HRESULT hr;
1039 CComPtr<IDataObject> selection;
1040 CComPtr<IContextMenu> cm;
1041 HMENU hmenu;
1042 FORMATETC fetc;
1043 STGMEDIUM stgm;
1044 LPIDA pIDList;
1045 LPCITEMIDLIST parent_pidl;
1046 WCHAR parent_path[MAX_PATH];
1047 LPCWSTR parent_dir = NULL;
1048 SFGAOF attribs;
1049 int i;
1050 CMINVOKECOMMANDINFOEX ici;
1051 MENUITEMINFOW info;
1052
1053 if (0 == GetSelections())
1054 {
1055 return S_OK;
1056 }
1057
1058 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1059 (LPCITEMIDLIST*)apidl, IID_IContextMenu,
1060 0, (LPVOID *)&cm);
1061
1062 if (SUCCEEDED(hr))
1063 {
1064 hmenu = CreatePopupMenu();
1065 if (hmenu)
1066 {
1067 hr = IUnknown_SetSite(cm, (IShellView *)this);
1068 if (SUCCEEDED(cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY)))
1069 {
1070 INT def = -1, n = GetMenuItemCount(hmenu);
1071
1072 for ( i = 0; i < n; i++ )
1073 {
1074 memset( &info, 0, sizeof info );
1075 info.cbSize = sizeof info;
1076 info.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID;
1077 if (GetMenuItemInfoW( hmenu, i, TRUE, &info))
1078 {
1079 if (info.fState & MFS_DEFAULT)
1080 {
1081 def = info.wID;
1082 break;
1083 }
1084 }
1085 }
1086 if (def != -1)
1087 {
1088 memset( &ici, 0, sizeof ici );
1089 ici.cbSize = sizeof ici;
1090 ici.lpVerb = MAKEINTRESOURCEA( def );
1091 ici.hwnd = m_hWnd;
1092
1093 if (cm->InvokeCommand((LPCMINVOKECOMMANDINFO) &ici ) == S_OK)
1094 {
1095 DestroyMenu( hmenu );
1096 hr = IUnknown_SetSite(cm, NULL);
1097 return S_OK;
1098 }
1099 }
1100
1101 }
1102 DestroyMenu( hmenu );
1103 hr = IUnknown_SetSite(cm, NULL);
1104 }
1105 cm->Release();
1106 }
1107
1108
1109
1110 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1111 (LPCITEMIDLIST*)apidl, IID_IDataObject,
1112 0, (LPVOID *)&selection);
1113
1114
1115
1116 if (FAILED(hr))
1117 return hr;
1118
1119 if (0 == CF_IDLIST)
1120 {
1121 CF_IDLIST = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
1122 }
1123 fetc.cfFormat = CF_IDLIST;
1124 fetc.ptd = NULL;
1125 fetc.dwAspect = DVASPECT_CONTENT;
1126 fetc.lindex = -1;
1127 fetc.tymed = TYMED_HGLOBAL;
1128
1129 hr = selection->QueryGetData(&fetc);
1130 if (FAILED(hr))
1131 return hr;
1132
1133 hr = selection->GetData(&fetc, &stgm);
1134 if (FAILED(hr))
1135 return hr;
1136
1137 pIDList = (LPIDA)GlobalLock(stgm.hGlobal);
1138
1139 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pIDList+pIDList->aoffset[0]);
1140 hr = pSFParent->GetAttributesOf(1, &parent_pidl, &attribs);
1141 if (SUCCEEDED(hr) && (attribs & SFGAO_FILESYSTEM) &&
1142 SHGetPathFromIDListW(parent_pidl, parent_path))
1143 {
1144 parent_dir = parent_path;
1145 }
1146
1147 for (i = pIDList->cidl; i > 0; --i)
1148 {
1149 LPCITEMIDLIST pidl;
1150
1151 pidl = (LPCITEMIDLIST)((LPBYTE)pIDList+pIDList->aoffset[i]);
1152
1153 attribs = SFGAO_FOLDER;
1154 hr = pSFParent->GetAttributesOf(1, &pidl, &attribs);
1155
1156 if (SUCCEEDED(hr) && ! (attribs & SFGAO_FOLDER))
1157 {
1158 SHELLEXECUTEINFOW shexinfo;
1159
1160 shexinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
1161 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; /* SEE_MASK_IDLIST is also possible. */
1162 shexinfo.hwnd = NULL;
1163 shexinfo.lpVerb = NULL;
1164 shexinfo.lpFile = NULL;
1165 shexinfo.lpParameters = NULL;
1166 shexinfo.lpDirectory = parent_dir;
1167 shexinfo.nShow = SW_NORMAL;
1168 shexinfo.lpIDList = ILCombine(parent_pidl, pidl);
1169
1170 ShellExecuteExW(&shexinfo); /* Discard error/success info */
1171
1172 ILFree((LPITEMIDLIST)shexinfo.lpIDList);
1173 }
1174 }
1175
1176 GlobalUnlock(stgm.hGlobal);
1177 ReleaseStgMedium(&stgm);
1178
1179 return S_OK;
1180 }
1181
1182 /**********************************************************
1183 * ShellView_DoContextMenu()
1184 */
1185 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1186 {
1187 WORD x;
1188 WORD y;
1189 BOOL bDefault;
1190 UINT uCommand;
1191 DWORD wFlags;
1192 HMENU hMenu;
1193 BOOL fExplore;
1194 HWND hwndTree;
1195 CMINVOKECOMMANDINFO cmi;
1196 HRESULT hResult;
1197
1198 // for some reason I haven't figured out, we sometimes recurse into this method
1199 if (pCM != NULL)
1200 return 0;
1201
1202 x = LOWORD(lParam);
1203 y = HIWORD(lParam);
1204 bDefault = FALSE;
1205
1206 TRACE("(%p)->(0x%08x 0x%08x 0x%08x) stub\n",this, x, y, bDefault);
1207
1208 fExplore = FALSE;
1209 hwndTree = NULL;
1210
1211 /* look, what's selected and create a context menu object of it*/
1212 if (GetSelections())
1213 {
1214 pSFParent->GetUIObjectOf(hWndParent, cidl, (LPCITEMIDLIST*)apidl, IID_IContextMenu, NULL, (LPVOID *)&pCM);
1215
1216 if(pCM)
1217 {
1218 TRACE("-- pContextMenu\n");
1219 hMenu = CreatePopupMenu();
1220
1221 if( hMenu )
1222 {
1223 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1224 /* See if we are in Explore or Open mode. If the browser's tree is present, we are in Explore mode.*/
1225 if(SUCCEEDED(pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
1226 {
1227 TRACE("-- explore mode\n");
1228 fExplore = TRUE;
1229 }
1230
1231 /* build the flags depending on what we can do with the selected item */
1232 wFlags = CMF_NORMAL | (cidl != 1 ? 0 : CMF_CANRENAME) | (fExplore ? CMF_EXPLORE : 0);
1233
1234 /* let the ContextMenu merge its items in */
1235 if (SUCCEEDED(pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags )))
1236 {
1237 if (FolderSettings.fFlags & FWF_DESKTOP)
1238 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1239
1240 if( bDefault )
1241 {
1242 TRACE("-- get menu default command\n");
1243 uCommand = GetMenuDefaultItem(hMenu, FALSE, GMDI_GOINTOPOPUPS);
1244 }
1245 else
1246 {
1247 TRACE("-- track popup\n");
1248 uCommand = TrackPopupMenu( hMenu,TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
1249 }
1250
1251 if(uCommand > 0)
1252 {
1253 TRACE("-- uCommand=%u\n", uCommand);
1254 if (uCommand==FCIDM_SHVIEW_OPEN && pCommDlgBrowser.p != NULL)
1255 {
1256 TRACE("-- dlg: OnDefaultCommand\n");
1257 if (OnDefaultCommand() != S_OK)
1258 {
1259 OpenSelectedItems();
1260 }
1261 }
1262 else
1263 {
1264 TRACE("-- explore -- invoke command\n");
1265 ZeroMemory(&cmi, sizeof(cmi));
1266 cmi.cbSize = sizeof(cmi);
1267 cmi.hwnd = hWndParent; /* this window has to answer CWM_GETISHELLBROWSER */
1268 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1269 pCM->InvokeCommand(&cmi);
1270 }
1271 }
1272 hResult = IUnknown_SetSite(pCM, NULL);
1273 DestroyMenu(hMenu);
1274 }
1275 }
1276 pCM.Release();
1277 }
1278 }
1279 else /* background context menu */
1280 {
1281 hMenu = CreatePopupMenu();
1282
1283 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)&pCM);
1284 pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1285
1286 uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
1287 DestroyMenu(hMenu);
1288
1289 TRACE("-- (%p)->(uCommand=0x%08x )\n",this, uCommand);
1290
1291 ZeroMemory(&cmi, sizeof(cmi));
1292 cmi.cbSize = sizeof(cmi);
1293 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1294 cmi.hwnd = hWndParent;
1295 pCM->InvokeCommand(&cmi);
1296
1297 pCM.Release();
1298 }
1299 return 0;
1300 }
1301
1302 /**********************************************************
1303 * ##### message handling #####
1304 */
1305
1306 /**********************************************************
1307 * ShellView_OnSize()
1308 */
1309 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1310 {
1311 WORD wWidth;
1312 WORD wHeight;
1313
1314 wWidth = LOWORD(lParam);
1315 wHeight = HIWORD(lParam);
1316
1317 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1318
1319 /*resize the ListView to fit our window*/
1320 if (hWndList)
1321 {
1322 ::MoveWindow(hWndList, 0, 0, wWidth, wHeight, TRUE);
1323 }
1324
1325 return 0;
1326 }
1327
1328 /**********************************************************
1329 * ShellView_OnDeactivate()
1330 *
1331 * NOTES
1332 * internal
1333 */
1334 void CDefView::OnDeactivate()
1335 {
1336 TRACE("%p\n",this);
1337
1338 if(uState != SVUIA_DEACTIVATE)
1339 {
1340 if(hMenu)
1341 {
1342 pShellBrowser->SetMenuSB(0, 0, 0);
1343 pShellBrowser->RemoveMenusSB(hMenu);
1344 DestroyMenu(hMenu);
1345 hMenu = 0;
1346 }
1347
1348 uState = SVUIA_DEACTIVATE;
1349 }
1350 }
1351
1352 void CDefView::DoActivate(UINT uState)
1353 {
1354 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1355 MENUITEMINFOA mii;
1356 CHAR szText[MAX_PATH];
1357
1358 TRACE("%p uState=%x\n", this, uState);
1359
1360 /*don't do anything if the state isn't really changing */
1361 if(uState == uState)
1362 {
1363 return;
1364 }
1365
1366 OnDeactivate();
1367
1368 /*only do This if we are active */
1369 if(uState != SVUIA_DEACTIVATE)
1370 {
1371 /*merge the menus */
1372 hMenu = CreateMenu();
1373
1374 if(hMenu)
1375 {
1376 pShellBrowser->InsertMenusSB(hMenu, &omw);
1377 TRACE("-- after fnInsertMenusSB\n");
1378
1379 /*build the top level menu get the menu item's text*/
1380 strcpy(szText,"dummy 31");
1381
1382 ZeroMemory(&mii, sizeof(mii));
1383 mii.cbSize = sizeof(mii);
1384 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1385 mii.fType = MFT_STRING;
1386 mii.fState = MFS_ENABLED;
1387 mii.dwTypeData = szText;
1388 mii.hSubMenu = BuildFileMenu();
1389
1390 /*insert our menu into the menu bar*/
1391 if(mii.hSubMenu)
1392 {
1393 InsertMenuItemA(hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1394 }
1395
1396 /*get the view menu so we can merge with it*/
1397 ZeroMemory(&mii, sizeof(mii));
1398 mii.cbSize = sizeof(mii);
1399 mii.fMask = MIIM_SUBMENU;
1400
1401 if(GetMenuItemInfoA(hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1402 {
1403 MergeViewMenu(mii.hSubMenu);
1404 }
1405
1406 /*add the items that should only be added if we have the focus*/
1407 if(SVUIA_ACTIVATE_FOCUS == uState)
1408 {
1409 /*get the file menu so we can merge with it */
1410 ZeroMemory(&mii, sizeof(mii));
1411 mii.cbSize = sizeof(mii);
1412 mii.fMask = MIIM_SUBMENU;
1413
1414 if(GetMenuItemInfoA(hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1415 {
1416 MergeFileMenu(mii.hSubMenu);
1417 }
1418 }
1419 TRACE("-- before fnSetMenuSB\n");
1420 pShellBrowser->SetMenuSB(hMenu, 0, m_hWnd);
1421 }
1422 }
1423 uState = uState;
1424 TRACE("--\n");
1425 }
1426
1427 /**********************************************************
1428 * ShellView_OnActivate()
1429 */
1430 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1431 {
1432 DoActivate(SVUIA_ACTIVATE_FOCUS);
1433 return 0;
1434 }
1435
1436 /**********************************************************
1437 * ShellView_OnSetFocus()
1438 *
1439 */
1440 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1441 {
1442 TRACE("%p\n", this);
1443
1444 /* Tell the browser one of our windows has received the focus. This
1445 should always be done before merging menus (OnActivate merges the
1446 menus) if one of our windows has the focus.*/
1447
1448 pShellBrowser->OnViewWindowActive((IShellView *)this);
1449 DoActivate(SVUIA_ACTIVATE_FOCUS);
1450
1451 /* Set the focus to the listview */
1452 ::SetFocus(hWndList);
1453
1454 /* Notify the ICommDlgBrowser interface */
1455 OnStateChange(CDBOSC_SETFOCUS);
1456
1457 return 0;
1458 }
1459
1460 /**********************************************************
1461 * ShellView_OnKillFocus()
1462 */
1463 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1464 {
1465 TRACE("(%p) stub\n", this);
1466
1467 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1468 /* Notify the ICommDlgBrowser */
1469 OnStateChange(CDBOSC_KILLFOCUS);
1470
1471 return 0;
1472 }
1473
1474 /**********************************************************
1475 * ShellView_OnCommand()
1476 *
1477 * NOTES
1478 * the CmdID's are the ones from the context menu
1479 */
1480 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1481 {
1482 DWORD dwCmdID;
1483 DWORD dwCmd;
1484 HWND hwndCmd;
1485
1486 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1487 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1488 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1489
1490 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n",this, dwCmdID, dwCmd, hwndCmd);
1491
1492 switch(dwCmdID)
1493 {
1494 case FCIDM_SHVIEW_SMALLICON:
1495 FolderSettings.ViewMode = FVM_SMALLICON;
1496 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1497 CheckToolbar();
1498 break;
1499
1500 case FCIDM_SHVIEW_BIGICON:
1501 FolderSettings.ViewMode = FVM_ICON;
1502 SetStyle (LVS_ICON, LVS_TYPEMASK);
1503 CheckToolbar();
1504 break;
1505
1506 case FCIDM_SHVIEW_LISTVIEW:
1507 FolderSettings.ViewMode = FVM_LIST;
1508 SetStyle (LVS_LIST, LVS_TYPEMASK);
1509 CheckToolbar();
1510 break;
1511
1512 case FCIDM_SHVIEW_REPORTVIEW:
1513 FolderSettings.ViewMode = FVM_DETAILS;
1514 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1515 CheckToolbar();
1516 break;
1517
1518 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1519 case 0x30:
1520 case 0x31:
1521 case 0x32:
1522 case 0x33:
1523 ListViewSortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1524 ListViewSortInfo.bIsAscending = TRUE;
1525 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1526 SendMessageA(hWndList, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1527 break;
1528
1529 default:
1530 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1531 }
1532 return 0;
1533 }
1534
1535 /**********************************************************
1536 * ShellView_OnNotify()
1537 */
1538
1539 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1540 {
1541 UINT CtlID;
1542 LPNMHDR lpnmh;
1543 LPNMLISTVIEW lpnmlv;
1544 NMLVDISPINFOW *lpdi;
1545 LPITEMIDLIST pidl;
1546 BOOL unused;
1547
1548 CtlID = wParam;
1549 lpnmh = (LPNMHDR)lParam;
1550 lpnmlv = (LPNMLISTVIEW)lpnmh;
1551 lpdi = (NMLVDISPINFOW *)lpnmh;
1552
1553 TRACE("%p CtlID=%u lpnmh->code=%x\n",this,CtlID,lpnmh->code);
1554
1555 switch(lpnmh->code)
1556 {
1557 case NM_SETFOCUS:
1558 TRACE("-- NM_SETFOCUS %p\n", this);
1559 OnSetFocus(0, 0, 0, unused);
1560 break;
1561
1562 case NM_KILLFOCUS:
1563 TRACE("-- NM_KILLFOCUS %p\n", this);
1564 OnDeactivate();
1565 /* Notify the ICommDlgBrowser interface */
1566 OnStateChange(CDBOSC_KILLFOCUS);
1567 break;
1568
1569 case NM_CUSTOMDRAW:
1570 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1571 return CDRF_DODEFAULT;
1572
1573 case NM_RELEASEDCAPTURE:
1574 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1575 break;
1576
1577 case NM_CLICK:
1578 TRACE("-- NM_CLICK %p\n", this);
1579 break;
1580
1581 case NM_RCLICK:
1582 TRACE("-- NM_RCLICK %p\n", this);
1583 break;
1584
1585 case NM_DBLCLK:
1586 TRACE("-- NM_DBLCLK %p\n", this);
1587 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1588 break;
1589
1590 case NM_RETURN:
1591 TRACE("-- NM_RETURN %p\n", this);
1592 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1593 break;
1594
1595 case HDN_ENDTRACKW:
1596 TRACE("-- HDN_ENDTRACKW %p\n", this);
1597 /*nColumn1 = ListView_GetColumnWidth(hWndList, 0);
1598 nColumn2 = ListView_GetColumnWidth(hWndList, 1);*/
1599 break;
1600
1601 case LVN_DELETEITEM:
1602 TRACE("-- LVN_DELETEITEM %p\n", this);
1603 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1604 break;
1605
1606 case LVN_DELETEALLITEMS:
1607 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1608 return FALSE;
1609
1610 case LVN_INSERTITEM:
1611 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1612 break;
1613
1614 case LVN_ITEMACTIVATE:
1615 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1616 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1617 break;
1618
1619 case LVN_COLUMNCLICK:
1620 ListViewSortInfo.nHeaderID = lpnmlv->iSubItem;
1621 if(ListViewSortInfo.nLastHeaderID == ListViewSortInfo.nHeaderID)
1622 {
1623 ListViewSortInfo.bIsAscending = !ListViewSortInfo.bIsAscending;
1624 }
1625 else
1626 {
1627 ListViewSortInfo.bIsAscending = TRUE;
1628 }
1629 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1630
1631 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1632 break;
1633
1634 case LVN_GETDISPINFOA:
1635 case LVN_GETDISPINFOW:
1636 TRACE("-- LVN_GETDISPINFO %p\n", this);
1637 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1638
1639 if(lpdi->item.mask & LVIF_TEXT) /* text requested */
1640 {
1641 if (pSF2Parent)
1642 {
1643 SHELLDETAILS sd;
1644 pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd);
1645 if (lpnmh->code == LVN_GETDISPINFOA)
1646 {
1647 /* shouldn't happen */
1648 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1649 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1650 TRACE("-- text=%s\n",lpdiA->item.pszText);
1651 }
1652 else /* LVN_GETDISPINFOW */
1653 {
1654 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1655 TRACE("-- text=%s\n",debugstr_w(lpdi->item.pszText));
1656 }
1657 }
1658 else
1659 {
1660 FIXME("no SF2\n");
1661 }
1662 }
1663 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1664 {
1665 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidl, 0);
1666 }
1667 lpdi->item.mask |= LVIF_DI_SETITEM;
1668 break;
1669
1670 case LVN_ITEMCHANGED:
1671 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1672 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1673 break;
1674
1675 case LVN_BEGINDRAG:
1676 case LVN_BEGINRDRAG:
1677 TRACE("-- LVN_BEGINDRAG\n");
1678
1679 if (GetSelections())
1680 {
1681 IDataObject * pda;
1682 DWORD dwAttributes = SFGAO_CANLINK;
1683 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1684
1685 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject,0,(LPVOID *)&pda)))
1686 {
1687 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1688
1689 if (SUCCEEDED(pSFParent->GetAttributesOf(cidl, (LPCITEMIDLIST*)apidl, &dwAttributes)))
1690 {
1691 if (dwAttributes & SFGAO_CANLINK)
1692 {
1693 dwEffect |= DROPEFFECT_LINK;
1694 }
1695 }
1696
1697 if (pds)
1698 {
1699 DWORD dwEffect2;
1700 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1701 }
1702 pda->Release();
1703 }
1704 }
1705 break;
1706
1707 case LVN_BEGINLABELEDITW:
1708 {
1709 DWORD dwAttr = SFGAO_CANRENAME;
1710 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1711
1712 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1713
1714 pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1715 if (SFGAO_CANRENAME & dwAttr)
1716 {
1717 return FALSE;
1718 }
1719 return TRUE;
1720 }
1721
1722 case LVN_ENDLABELEDITW:
1723 {
1724 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1725 if (lpdi->item.pszText)
1726 {
1727 HRESULT hr;
1728 LVITEMW lvItem;
1729
1730 lvItem.iItem = lpdi->item.iItem;
1731 lvItem.iSubItem = 0;
1732 lvItem.mask = LVIF_PARAM;
1733 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1734
1735 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1736 hr = pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1737
1738 if(SUCCEEDED(hr) && pidl)
1739 {
1740 lvItem.mask = LVIF_PARAM;
1741 lvItem.lParam = (LPARAM)pidl;
1742 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1743 return TRUE;
1744 }
1745 }
1746 return FALSE;
1747 }
1748
1749 case LVN_KEYDOWN:
1750 {
1751 /* MSG msg;
1752 msg.hwnd = m_hWnd;
1753 msg.message = WM_KEYDOWN;
1754 msg.wParam = plvKeyDown->wVKey;
1755 msg.lParam = 0;
1756 msg.time = 0;
1757 msg.pt = 0;*/
1758
1759 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1760 SHORT ctrl = GetKeyState(VK_CONTROL) & 0x8000;
1761
1762 /* initiate a rename of the selected file or directory */
1763 if(plvKeyDown->wVKey == VK_F2)
1764 {
1765 /* see how many files are selected */
1766 int i = ListView_GetSelectedCount(hWndList);
1767
1768 /* get selected item */
1769 if(i == 1)
1770 {
1771 /* get selected item */
1772 i = ListView_GetNextItem(hWndList, -1,
1773 LVNI_SELECTED);
1774
1775 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
1776 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
1777 }
1778 }
1779 #if 0
1780 TranslateAccelerator(m_hWnd, hAccel, &msg)
1781 #endif
1782 else if(plvKeyDown->wVKey == VK_DELETE)
1783 {
1784 UINT i;
1785 int item_index;
1786 LVITEMA item;
1787 LPITEMIDLIST* pItems;
1788 ISFHelper *psfhlp;
1789
1790 pSFParent->QueryInterface(IID_ISFHelper,
1791 (LPVOID*)&psfhlp);
1792
1793 if (psfhlp == NULL)
1794 break;
1795
1796 if(!(i = ListView_GetSelectedCount(hWndList)))
1797 break;
1798
1799 /* allocate memory for the pidl array */
1800 pItems = (LPITEMIDLIST *)HeapAlloc(GetProcessHeap(), 0,
1801 sizeof(LPITEMIDLIST) * i);
1802
1803 /* retrieve all selected items */
1804 i = 0;
1805 item_index = -1;
1806 while(ListView_GetSelectedCount(hWndList) > i)
1807 {
1808 /* get selected item */
1809 item_index = ListView_GetNextItem(hWndList,
1810 item_index, LVNI_SELECTED);
1811 item.iItem = item_index;
1812 item.mask = LVIF_PARAM;
1813 SendMessageA(hWndList, LVM_GETITEMA, 0, (LPARAM) &item);
1814
1815 /* get item pidl */
1816 pItems[i] = (LPITEMIDLIST)item.lParam;
1817
1818 i++;
1819 }
1820
1821 /* perform the item deletion */
1822 psfhlp->DeleteItems(i, (LPCITEMIDLIST*)pItems);
1823
1824 /* free pidl array memory */
1825 HeapFree(GetProcessHeap(), 0, pItems);
1826 }
1827
1828 /* Initiate a refresh */
1829 else if(plvKeyDown->wVKey == VK_F5)
1830 {
1831 Refresh();
1832 }
1833 else if(plvKeyDown->wVKey == VK_BACK)
1834 {
1835 LPSHELLBROWSER lpSb;
1836 if((lpSb = (LPSHELLBROWSER)SendMessageW(hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1837 {
1838 lpSb->BrowseObject(NULL, SBSP_PARENT);
1839 }
1840 }
1841 else if(plvKeyDown->wVKey == 'C' && ctrl)
1842 {
1843 if (GetSelections())
1844 {
1845 CComPtr<IDataObject> pda;
1846
1847 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1848 {
1849 HRESULT hr = OleSetClipboard(pda);
1850 if (FAILED(hr))
1851 {
1852 WARN("OleSetClipboard failed");
1853 }
1854 }
1855 }
1856 break;
1857 }
1858 else if(plvKeyDown->wVKey == 'V' && ctrl)
1859 {
1860 CComPtr<IDataObject> pda;
1861 STGMEDIUM medium;
1862 FORMATETC formatetc;
1863 LPITEMIDLIST * apidl;
1864 LPITEMIDLIST pidl;
1865 CComPtr<IShellFolder> psfFrom;
1866 CComPtr<IShellFolder> psfDesktop;
1867 CComPtr<IShellFolder> psfTarget;
1868 LPIDA lpcida;
1869 CComPtr<ISFHelper> psfhlpdst;
1870 CComPtr<ISFHelper> psfhlpsrc;
1871 HRESULT hr;
1872
1873 hr = OleGetClipboard(&pda);
1874 if (hr != S_OK)
1875 {
1876 ERR("Failed to get clipboard with %lx\n", hr);
1877 return E_FAIL;
1878 }
1879
1880 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
1881 hr = pda->GetData(&formatetc, &medium);
1882
1883 if (FAILED(hr))
1884 {
1885 ERR("Failed to get clipboard data with %lx\n", hr);
1886 return E_FAIL;
1887 }
1888
1889 /* lock the handle */
1890 lpcida = (LPIDA)GlobalLock(medium.hGlobal);
1891 if (!lpcida)
1892 {
1893 ERR("failed to lock pidl\n");
1894 ReleaseStgMedium(&medium);
1895 return E_FAIL;
1896 }
1897
1898 /* convert the data into pidl */
1899 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1900
1901 if (!apidl)
1902 {
1903 ERR("failed to copy pidl\n");
1904 return E_FAIL;
1905 }
1906
1907 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
1908 {
1909 ERR("failed to get desktop folder\n");
1910 SHFree(pidl);
1911 _ILFreeaPidl(apidl, lpcida->cidl);
1912 ReleaseStgMedium(&medium);
1913 return E_FAIL;
1914 }
1915
1916 if (_ILIsDesktop(pidl))
1917 {
1918 /* use desktop shellfolder */
1919 psfFrom = psfDesktop;
1920 }
1921 else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
1922 {
1923 ERR("no IShellFolder\n");
1924
1925 SHFree(pidl);
1926 _ILFreeaPidl(apidl, lpcida->cidl);
1927 ReleaseStgMedium(&medium);
1928
1929 return E_FAIL;
1930 }
1931
1932 psfTarget = pSFParent;
1933
1934
1935 /* get source and destination shellfolder */
1936 if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
1937 {
1938 ERR("no IID_ISFHelper for destination\n");
1939
1940 SHFree(pidl);
1941 _ILFreeaPidl(apidl, lpcida->cidl);
1942 ReleaseStgMedium(&medium);
1943
1944 return E_FAIL;
1945 }
1946
1947 if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
1948 {
1949 ERR("no IID_ISFHelper for source\n");
1950
1951 SHFree(pidl);
1952 _ILFreeaPidl(apidl, lpcida->cidl);
1953 ReleaseStgMedium(&medium);
1954 return E_FAIL;
1955 }
1956
1957 /* FIXXME
1958 * do we want to perform a copy or move ???
1959 */
1960 hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
1961
1962 SHFree(pidl);
1963 _ILFreeaPidl(apidl, lpcida->cidl);
1964 ReleaseStgMedium(&medium);
1965
1966 TRACE("paste end hr %x\n", hr);
1967 break;
1968 }
1969 else
1970 FIXME("LVN_KEYDOWN key=0x%08x\n",plvKeyDown->wVKey);
1971 }
1972 break;
1973
1974 default:
1975 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1976 break;
1977 }
1978 return 0;
1979 }
1980
1981 /**********************************************************
1982 * ShellView_OnChange()
1983 */
1984 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1985 {
1986 LPITEMIDLIST *Pidls;
1987
1988 Pidls = (LPITEMIDLIST *)wParam;
1989
1990 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1991
1992 switch (lParam)
1993 {
1994 case SHCNE_MKDIR:
1995 case SHCNE_CREATE:
1996 LV_AddItem(Pidls[0]);
1997 break;
1998 case SHCNE_RMDIR:
1999 case SHCNE_DELETE:
2000 LV_DeleteItem(Pidls[0]);
2001 break;
2002 case SHCNE_RENAMEFOLDER:
2003 case SHCNE_RENAMEITEM:
2004 LV_RenameItem(Pidls[0], Pidls[1]);
2005 break;
2006 case SHCNE_UPDATEITEM:
2007 break;
2008 }
2009 return TRUE;
2010 }
2011
2012 /**********************************************************
2013 * ShellView_DoMeasureItem
2014 */
2015 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2016 {
2017 if (!pCM.p)
2018 {
2019 /* no menu */
2020 ERR("no menu!!!\n");
2021 return FALSE;
2022 }
2023
2024 if (pCM.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
2025 return TRUE;
2026 else
2027 return FALSE;
2028 }
2029
2030 /**********************************************************
2031 *
2032 *
2033 * The INTERFACE of the IShellView object
2034 *
2035 *
2036 **********************************************************
2037 */
2038
2039 /**********************************************************
2040 * ShellView_GetWindow
2041 */
2042 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2043 {
2044 TRACE("(%p)\n",this);
2045
2046 *phWnd = m_hWnd;
2047
2048 return S_OK;
2049 }
2050
2051 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2052 {
2053 FIXME("(%p) stub\n",this);
2054
2055 return E_NOTIMPL;
2056 }
2057
2058 /**********************************************************
2059 * IShellView_TranslateAccelerator
2060 *
2061 * FIXME:
2062 * use the accel functions
2063 */
2064 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2065 {
2066 #if 0
2067 FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n",this,lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
2068 #endif
2069
2070 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message >= WM_KEYLAST)
2071 {
2072 TRACE("-- key=0x04%lx\n",lpmsg->wParam) ;
2073 }
2074 return S_FALSE; /* not handled */
2075 }
2076
2077 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2078 {
2079 FIXME("(%p) stub\n",this);
2080
2081 return E_NOTIMPL;
2082 }
2083
2084 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2085 {
2086 /*
2087 CHAR szName[MAX_PATH];
2088 */
2089 LRESULT lResult;
2090 int nPartArray[1] = {-1};
2091
2092 TRACE("(%p)->(state=%x) stub\n",this, uState);
2093
2094 /*don't do anything if the state isn't really changing*/
2095 if(uState == uState)
2096 {
2097 return S_OK;
2098 }
2099
2100 /*OnActivate handles the menu merging and internal state*/
2101 DoActivate(uState);
2102
2103 /*only do This if we are active*/
2104 if(uState != SVUIA_DEACTIVATE)
2105 {
2106
2107 /*
2108 GetFolderPath is not a method of IShellFolder
2109 IShellFolder_GetFolderPath( pSFParent, szName, sizeof(szName) );
2110 */
2111 /* set the number of parts */
2112 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2113
2114 /* set the text for the parts */
2115 /*
2116 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2117 */
2118 }
2119
2120 return S_OK;
2121 }
2122
2123 HRESULT WINAPI CDefView::Refresh()
2124 {
2125 TRACE("(%p)\n",this);
2126
2127 SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
2128 FillList();
2129
2130 return S_OK;
2131 }
2132
2133 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2134 {
2135 *phWnd = 0;
2136
2137 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n",this, lpPrevView,lpfs, psb, prcView, phWnd);
2138
2139 if (lpfs != NULL)
2140 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
2141 if (prcView != NULL)
2142 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2143
2144 /* Validate the Shell Browser */
2145 if (psb == NULL)
2146 return E_UNEXPECTED;
2147
2148 /*set up the member variables*/
2149 pShellBrowser = psb;
2150 FolderSettings = *lpfs;
2151
2152 /*get our parent window*/
2153 pShellBrowser->GetWindow(&hWndParent);
2154
2155 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2156 pCommDlgBrowser = NULL;
2157 if (SUCCEEDED(pShellBrowser->QueryInterface(IID_ICommDlgBrowser, (LPVOID *)&pCommDlgBrowser)))
2158 {
2159 TRACE("-- CommDlgBrowser\n");
2160 }
2161
2162 Create(hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
2163 if (m_hWnd == NULL)
2164 return E_FAIL;
2165
2166 *phWnd = m_hWnd;
2167
2168 CheckToolbar();
2169
2170 if (!*phWnd)
2171 return E_FAIL;
2172
2173 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2174 UpdateWindow();
2175
2176 return S_OK;
2177 }
2178
2179 HRESULT WINAPI CDefView::DestroyViewWindow()
2180 {
2181 TRACE("(%p)\n",this);
2182
2183 /*Make absolutely sure all our UI is cleaned up.*/
2184 UIActivate(SVUIA_DEACTIVATE);
2185
2186 if(hMenu)
2187 {
2188 DestroyMenu(hMenu);
2189 }
2190
2191 DestroyWindow();
2192 pShellBrowser.Release();
2193 pCommDlgBrowser.Release();
2194
2195 return S_OK;
2196 }
2197
2198 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2199 {
2200 TRACE("(%p)->(%p) vmode=%x flags=%x\n",this, lpfs,
2201 FolderSettings.ViewMode, FolderSettings.fFlags);
2202
2203 if (!lpfs) return E_INVALIDARG;
2204
2205 *lpfs = FolderSettings;
2206 return NOERROR;
2207 }
2208
2209 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2210 {
2211 FIXME("(%p) stub\n",this);
2212
2213 return E_NOTIMPL;
2214 }
2215
2216 HRESULT WINAPI CDefView::SaveViewState()
2217 {
2218 FIXME("(%p) stub\n",this);
2219
2220 return S_OK;
2221 }
2222
2223 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2224 {
2225 int i;
2226
2227 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n",this, pidl, uFlags);
2228
2229 i = LV_FindItemByPidl(pidl);
2230
2231 if (i != -1)
2232 {
2233 LVITEMW lvItem;
2234
2235 if(uFlags & SVSI_ENSUREVISIBLE)
2236 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
2237
2238 lvItem.mask = LVIF_STATE;
2239 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2240 lvItem.iItem = 0;
2241 lvItem.iSubItem = 0;
2242
2243 while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2244 {
2245 if (lvItem.iItem == i)
2246 {
2247 if (uFlags & SVSI_SELECT)
2248 lvItem.state |= LVIS_SELECTED;
2249 else
2250 lvItem.state &= ~LVIS_SELECTED;
2251
2252 if(uFlags & SVSI_FOCUSED)
2253 lvItem.state &= ~LVIS_FOCUSED;
2254 }
2255 else
2256 {
2257 if (uFlags & SVSI_DESELECTOTHERS)
2258 lvItem.state &= ~LVIS_SELECTED;
2259 }
2260 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2261 lvItem.iItem++;
2262 }
2263
2264
2265 if(uFlags & SVSI_EDIT)
2266 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
2267
2268 }
2269 return S_OK;
2270 }
2271
2272 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2273 {
2274 HRESULT hr = E_FAIL;
2275
2276 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",this, uItem, debugstr_guid(&riid), ppvOut);
2277
2278 *ppvOut = NULL;
2279
2280 switch(uItem)
2281 {
2282 case SVGIO_BACKGROUND:
2283 if (IsEqualIID(riid, IID_IContextMenu))
2284 {
2285 //*ppvOut = ISvBgCm_Constructor(pSFParent, FALSE);
2286 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2287 if (!ppvOut)
2288 hr = E_OUTOFMEMORY;
2289 }
2290 break;
2291
2292 case SVGIO_SELECTION:
2293 GetSelections();
2294 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, riid, 0, ppvOut);
2295 break;
2296 }
2297 TRACE("-- (%p)->(interface=%p)\n",this, *ppvOut);
2298
2299 return hr;
2300 }
2301
2302 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2303 {
2304 return E_NOTIMPL;
2305 }
2306
2307 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2308 {
2309 return E_NOTIMPL;
2310 }
2311
2312 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2313 {
2314 if (pSFParent == NULL)
2315 return E_FAIL;
2316 return pSFParent->QueryInterface(riid, ppv);
2317 }
2318
2319 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2320 {
2321 return E_NOTIMPL;
2322 }
2323
2324 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2325 {
2326 return E_NOTIMPL;
2327 }
2328
2329 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2330 {
2331 return E_NOTIMPL;
2332 }
2333
2334 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2335 {
2336 return E_NOTIMPL;
2337 }
2338
2339 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2340 {
2341 return E_NOTIMPL;
2342 }
2343
2344 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2345 {
2346 return E_NOTIMPL;
2347 }
2348
2349 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2350 {
2351 return E_NOTIMPL;
2352 }
2353
2354 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2355 {
2356 return E_NOTIMPL;
2357 }
2358
2359 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2360 {
2361 return E_NOTIMPL;
2362 }
2363
2364 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2365 {
2366 return E_NOTIMPL;
2367 }
2368
2369 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2370 {
2371 return E_NOTIMPL;
2372 }
2373
2374 /**********************************************************
2375 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2376 */
2377 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2378 {
2379 UINT i;
2380
2381 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2382 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2383
2384 if (!prgCmds)
2385 return E_POINTER;
2386 for (i = 0; i < cCmds; i++)
2387 {
2388 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2389 prgCmds[i].cmdf = 0;
2390 }
2391 return OLECMDERR_E_UNKNOWNGROUP;
2392 }
2393
2394 /**********************************************************
2395 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2396 *
2397 * nCmdID is the OLECMDID_* enumeration
2398 */
2399 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2400 {
2401 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2402 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2403
2404 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2405 (nCmdID == 0x29) &&
2406 (nCmdexecopt == 4) && pvaOut)
2407 return S_OK;
2408 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2409 (nCmdID == 9) &&
2410 (nCmdexecopt == 0))
2411 return 1;
2412
2413 return OLECMDERR_E_UNKNOWNGROUP;
2414 }
2415
2416 /**********************************************************
2417 * ISVDropTarget implementation
2418 */
2419
2420 /******************************************************************************
2421 * drag_notify_subitem [Internal]
2422 *
2423 * Figure out the shellfolder object, which is currently under the mouse cursor
2424 * and notify it via the IDropTarget interface.
2425 */
2426
2427 #define SCROLLAREAWIDTH 20
2428
2429 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2430 {
2431 LVHITTESTINFO htinfo;
2432 LVITEMW lvItem;
2433 LONG lResult;
2434 HRESULT hr;
2435 RECT clientRect;
2436
2437 /* Map from global to client coordinates and query the index of the listview-item, which is
2438 * currently under the mouse cursor. */
2439 htinfo.pt.x = pt.x;
2440 htinfo.pt.y = pt.y;
2441 htinfo.flags = LVHT_ONITEM;
2442 ::ScreenToClient(hWndList, &htinfo.pt);
2443 lResult = SendMessageW(hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2444
2445 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2446 ::GetClientRect(hWndList, &clientRect);
2447 if (htinfo.pt.x == ptLastMousePos.x && htinfo.pt.y == ptLastMousePos.y &&
2448 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2449 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2450 {
2451 cScrollDelay = (cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2452 if (cScrollDelay == 0) { /* Mouse did hover another 250 ms over the scroll-area */
2453 if (htinfo.pt.x < SCROLLAREAWIDTH)
2454 SendMessageW(hWndList, WM_HSCROLL, SB_LINEUP, 0);
2455 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2456 SendMessageW(hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2457 if (htinfo.pt.y < SCROLLAREAWIDTH)
2458 SendMessageW(hWndList, WM_VSCROLL, SB_LINEUP, 0);
2459 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2460 SendMessageW(hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2461 }
2462 } else {
2463 cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2464 }
2465 ptLastMousePos = htinfo.pt;
2466
2467 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2468 if (pCurDropTarget && lResult == iDragOverItem)
2469 return pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2470
2471 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2472 if (pCurDropTarget) {
2473 pCurDropTarget->DragLeave();
2474 pCurDropTarget.Release();
2475 }
2476
2477 iDragOverItem = lResult;
2478 if (lResult == -1) {
2479 /* We are not above one of the listview's subitems. Bind to the parent folder's
2480 * DropTarget interface. */
2481 hr = pSFParent->QueryInterface(IID_IDropTarget,
2482 (LPVOID*)&pCurDropTarget);
2483 } else {
2484 /* Query the relative PIDL of the shellfolder object represented by the currently
2485 * dragged over listview-item ... */
2486 lvItem.mask = LVIF_PARAM;
2487 lvItem.iItem = lResult;
2488 lvItem.iSubItem = 0;
2489 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2490
2491 /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2492 hr = pSFParent->GetUIObjectOf(hWndList, 1,
2493 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&pCurDropTarget);
2494 }
2495
2496 /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2497 if (FAILED(hr))
2498 return hr;
2499
2500 /* Notify the item just entered via DragEnter. */
2501 return pCurDropTarget->DragEnter(pCurDataObject, grfKeyState, pt, pdwEffect);
2502 }
2503
2504 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2505 {
2506 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2507 pCurDataObject = pDataObject;
2508 pDataObject->AddRef();
2509
2510 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2511 }
2512
2513 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2514 {
2515 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2516 }
2517
2518 HRESULT WINAPI CDefView::DragLeave()
2519 {
2520 if (pCurDropTarget)
2521 {
2522 pCurDropTarget->DragLeave();
2523 pCurDropTarget.Release();
2524 }
2525
2526 if (pCurDataObject != NULL)
2527 {
2528 pCurDataObject.Release();
2529 }
2530
2531 iDragOverItem = 0;
2532
2533 return S_OK;
2534 }
2535
2536 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2537 {
2538 if (pCurDropTarget)
2539 {
2540 pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2541 pCurDropTarget.Release();
2542 }
2543
2544 pCurDataObject.Release();
2545 iDragOverItem = 0;
2546
2547 return S_OK;
2548 }
2549
2550 /**********************************************************
2551 * ISVDropSource implementation
2552 */
2553
2554 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2555 {
2556 TRACE("(%p)\n",this);
2557
2558 if (fEscapePressed)
2559 return DRAGDROP_S_CANCEL;
2560 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2561 return DRAGDROP_S_DROP;
2562 else
2563 return NOERROR;
2564 }
2565
2566 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2567 {
2568 TRACE("(%p)\n",this);
2569
2570 return DRAGDROP_S_USEDEFAULTCURSORS;
2571 }
2572
2573 /**********************************************************
2574 * ISVViewObject implementation
2575 */
2576
2577 HRESULT WINAPI CDefView::Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue)
2578 {
2579 FIXME("Stub: this=%p\n",this);
2580
2581 return E_NOTIMPL;
2582 }
2583
2584 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2585 {
2586 FIXME("Stub: this=%p\n",this);
2587
2588 return E_NOTIMPL;
2589 }
2590
2591 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2592 {
2593 FIXME("Stub: this=%p\n",this);
2594
2595 return E_NOTIMPL;
2596 }
2597
2598 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2599 {
2600 FIXME("Stub: this=%p\n",this);
2601
2602 return E_NOTIMPL;
2603 }
2604
2605 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2606 {
2607 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2608
2609 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2610 pAdvSink = pAdvSink;
2611 dwAspects = aspects;
2612 dwAdvf = advf;
2613
2614 return S_OK;
2615 }
2616
2617 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2618 {
2619 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2620
2621 if( ppAdvSink )
2622 {
2623 *ppAdvSink = pAdvSink;
2624 pAdvSink.p->AddRef();
2625 }
2626 if( pAspects )
2627 *pAspects = dwAspects;
2628 if( pAdvf )
2629 *pAdvf = dwAdvf;
2630
2631 return S_OK;
2632 }
2633
2634 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2635 {
2636 if (IsEqualIID(guidService, SID_IShellBrowser))
2637 return pShellBrowser->QueryInterface(riid, ppvObject);
2638 return E_NOINTERFACE;
2639 }
2640
2641 /**********************************************************
2642 * IShellView_Constructor
2643 */
2644 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2645 {
2646 CComObject<CDefView> *theView;
2647 CComPtr<IShellView> result;
2648 HRESULT hResult;
2649
2650 if (newView == NULL)
2651 return E_POINTER;
2652 *newView = NULL;
2653 ATLTRY (theView = new CComObject<CDefView>);
2654 if (theView == NULL)
2655 return E_OUTOFMEMORY;
2656 hResult = theView->QueryInterface (IID_IShellView, (void **)&result);
2657 if (FAILED (hResult))
2658 {
2659 delete theView;
2660 return hResult;
2661 }
2662 hResult = theView->Initialize (pFolder);
2663 if (FAILED (hResult))
2664 return hResult;
2665 *newView = result.Detach ();
2666 return S_OK;
2667 }