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