[shell32.dll]
[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 DbgPrint("[shell32, CDefView::FillList] Called\n");
785
786 /* get the itemlist from the shfolder*/
787 hRes = pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
788 if (hRes != S_OK)
789 {
790 if (hRes==S_FALSE)
791 return(NOERROR);
792 return(hRes);
793 }
794
795 /* create a pointer array */
796 hdpa = DPA_Create(16);
797 if (!hdpa)
798 {
799 return(E_OUTOFMEMORY);
800 }
801
802 /* copy the items into the array*/
803 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
804 {
805 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
806 {
807 SHFree(pidl);
808 }
809 }
810
811 /* sort the array */
812 DPA_Sort(hdpa, CompareItems, (LPARAM)pSFParent.p);
813
814 /*turn the listview's redrawing off*/
815 SendMessageA(hWndList, WM_SETREDRAW, FALSE, 0);
816
817 DPA_DestroyCallback( hdpa, fill_list, (void *)this);
818
819 /*turn the listview's redrawing back on and force it to draw*/
820 SendMessageA(hWndList, WM_SETREDRAW, TRUE, 0);
821
822 pEnumIDList->Release(); /* destroy the list*/
823
824 return S_OK;
825 }
826
827 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
828 {
829 ::UpdateWindow(hWndList);
830 bHandled = FALSE;
831 return 0;
832 }
833
834 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
835 {
836 return SendMessageW(hWndList, uMsg, 0, 0);
837 }
838
839 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
840 {
841 RevokeDragDrop(m_hWnd);
842 SHChangeNotifyDeregister(hNotify);
843 bHandled = FALSE;
844 return 0;
845 }
846
847 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
848 {
849 if (FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
850 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
851
852 bHandled = FALSE;
853 return 0;
854 }
855
856 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
857 {
858 /* Forward WM_SYSCOLORCHANGE to common controls */
859 return SendMessageW(hWndList, uMsg, 0, 0);
860 }
861
862 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
863 {
864 return (LRESULT)pShellBrowser.p;
865 }
866
867 /**********************************************************
868 * ShellView_OnCreate()
869 */
870 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
871 {
872 CComPtr<IDropTarget> pdt;
873 SHChangeNotifyEntry ntreg;
874 CComPtr<IPersistFolder2> ppf2;
875
876 TRACE("%p\n",this);
877
878 DbgPrint("[shell32, CDefView::OnCreate] Called\n");
879
880 if(CreateList())
881 {
882 if(InitList())
883 {
884 FillList();
885 }
886 }
887
888 if (SUCCEEDED(this->QueryInterface(IID_IDropTarget, (LPVOID*)&pdt)))
889 RegisterDragDrop(m_hWnd, pdt);
890
891 /* register for receiving notifications */
892 pSFParent->QueryInterface(IID_IPersistFolder2, (LPVOID*)&ppf2);
893 if (ppf2)
894 {
895 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
896 ntreg.fRecursive = TRUE;
897 hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
898 SHFree((LPITEMIDLIST)ntreg.pidl);
899 }
900
901 hAccel = LoadAcceleratorsA(shell32_hInstance, "shv_accel");
902
903 return S_OK;
904 }
905
906 /**********************************************************
907 * #### Handling of the menus ####
908 */
909
910 /**********************************************************
911 * ShellView_BuildFileMenu()
912 */
913 HMENU CDefView::BuildFileMenu()
914 { WCHAR szText[MAX_PATH];
915 MENUITEMINFOW mii;
916 int nTools,i;
917 HMENU hSubMenu;
918
919 TRACE("(%p)\n",this);
920
921 hSubMenu = CreatePopupMenu();
922 if(hSubMenu)
923 { /*get the number of items in our global array*/
924 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++){}
925
926 /*add the menu items*/
927 for(i = 0; i < nTools; i++)
928 {
929 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
930
931 ZeroMemory(&mii, sizeof(mii));
932 mii.cbSize = sizeof(mii);
933 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
934
935 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
936 {
937 mii.fType = MFT_STRING;
938 mii.fState = MFS_ENABLED;
939 mii.dwTypeData = szText;
940 mii.wID = Tools[i].idCommand;
941 }
942 else
943 {
944 mii.fType = MFT_SEPARATOR;
945 }
946 /* tack This item onto the end of the menu */
947 InsertMenuItemW(hSubMenu, (UINT)-1, TRUE, &mii);
948 }
949 }
950 TRACE("-- return (menu=%p)\n",hSubMenu);
951 return hSubMenu;
952 }
953
954 /**********************************************************
955 * ShellView_MergeFileMenu()
956 */
957 void CDefView::MergeFileMenu(HMENU hSubMenu)
958 { TRACE("(%p)->(submenu=%p) stub\n",this,hSubMenu);
959
960 if(hSubMenu)
961 { /*insert This item at the beginning of the menu */
962 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
963 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
964
965 }
966 TRACE("--\n");
967 }
968
969 /**********************************************************
970 * ShellView_MergeViewMenu()
971 */
972 void CDefView::MergeViewMenu(HMENU hSubMenu)
973 {
974 TRACE("(%p)->(submenu=%p)\n",this,hSubMenu);
975
976 if(hSubMenu)
977 { /*add a separator at the correct position in the menu*/
978 MENUITEMINFOW mii;
979 static WCHAR view[] = L"View";
980
981 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
982
983 ZeroMemory(&mii, sizeof(mii));
984 mii.cbSize = sizeof(mii);
985 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
986 mii.fType = MFT_STRING;
987 mii.dwTypeData = view;
988 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
989 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
990 }
991 }
992
993 /**********************************************************
994 * ShellView_GetSelections()
995 *
996 * - fills the this->apidl list with the selected objects
997 *
998 * RETURNS
999 * number of selected items
1000 */
1001 UINT CDefView::GetSelections()
1002 {
1003 LVITEMW lvItem;
1004 UINT i = 0;
1005
1006 SHFree(apidl);
1007
1008 cidl = ListView_GetSelectedCount(hWndList);
1009 apidl = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1010
1011 TRACE("selected=%i\n", cidl);
1012
1013 if(apidl)
1014 {
1015 TRACE("-- Items selected =%u\n", cidl);
1016
1017 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1018 lvItem.stateMask = LVIS_SELECTED;
1019 lvItem.iItem = 0;
1020 lvItem.iSubItem = 0;
1021 lvItem.state = 0;
1022
1023 while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < cidl))
1024 {
1025 if(lvItem.state & LVIS_SELECTED)
1026 {
1027 apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1028 i++;
1029 if (i == cidl)
1030 break;
1031 TRACE("-- selected Item found\n");
1032 }
1033 lvItem.iItem++;
1034 }
1035 }
1036 return cidl;
1037
1038 }
1039
1040 /**********************************************************
1041 * ShellView_OpenSelectedItems()
1042 */
1043 HRESULT CDefView::OpenSelectedItems()
1044 {
1045 static UINT CF_IDLIST = 0;
1046 HRESULT hr;
1047 CComPtr<IDataObject> selection;
1048 CComPtr<IContextMenu> cm;
1049 HMENU hmenu;
1050 FORMATETC fetc;
1051 STGMEDIUM stgm;
1052 LPIDA pIDList;
1053 LPCITEMIDLIST parent_pidl;
1054 WCHAR parent_path[MAX_PATH];
1055 LPCWSTR parent_dir = NULL;
1056 SFGAOF attribs;
1057 int i;
1058 CMINVOKECOMMANDINFOEX ici;
1059 MENUITEMINFOW info;
1060
1061 if (0 == GetSelections())
1062 {
1063 return S_OK;
1064 }
1065
1066 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1067 (LPCITEMIDLIST*)apidl, IID_IContextMenu,
1068 0, (LPVOID *)&cm);
1069
1070 if (SUCCEEDED(hr))
1071 {
1072 hmenu = CreatePopupMenu();
1073 if (hmenu)
1074 {
1075 hr = IUnknown_SetSite(cm, (IShellView *)this);
1076 if (SUCCEEDED(cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY)))
1077 {
1078 INT def = -1, n = GetMenuItemCount(hmenu);
1079
1080 for ( i = 0; i < n; i++ )
1081 {
1082 memset( &info, 0, sizeof info );
1083 info.cbSize = sizeof info;
1084 info.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID;
1085 if (GetMenuItemInfoW( hmenu, i, TRUE, &info))
1086 {
1087 if (info.fState & MFS_DEFAULT)
1088 {
1089 def = info.wID;
1090 break;
1091 }
1092 }
1093 }
1094 if (def != -1)
1095 {
1096 memset( &ici, 0, sizeof ici );
1097 ici.cbSize = sizeof ici;
1098 ici.lpVerb = MAKEINTRESOURCEA( def );
1099 ici.hwnd = m_hWnd;
1100
1101 if (cm->InvokeCommand((LPCMINVOKECOMMANDINFO) &ici ) == S_OK)
1102 {
1103 DestroyMenu( hmenu );
1104 hr = IUnknown_SetSite(cm, NULL);
1105 return S_OK;
1106 }
1107 }
1108
1109 }
1110 DestroyMenu( hmenu );
1111 hr = IUnknown_SetSite(cm, NULL);
1112 }
1113 cm->Release();
1114 }
1115
1116
1117
1118 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1119 (LPCITEMIDLIST*)apidl, IID_IDataObject,
1120 0, (LPVOID *)&selection);
1121
1122
1123
1124 if (FAILED(hr))
1125 return hr;
1126
1127 if (0 == CF_IDLIST)
1128 {
1129 CF_IDLIST = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
1130 }
1131 fetc.cfFormat = CF_IDLIST;
1132 fetc.ptd = NULL;
1133 fetc.dwAspect = DVASPECT_CONTENT;
1134 fetc.lindex = -1;
1135 fetc.tymed = TYMED_HGLOBAL;
1136
1137 hr = selection->QueryGetData(&fetc);
1138 if (FAILED(hr))
1139 return hr;
1140
1141 hr = selection->GetData(&fetc, &stgm);
1142 if (FAILED(hr))
1143 return hr;
1144
1145 pIDList = (LPIDA)GlobalLock(stgm.hGlobal);
1146
1147 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pIDList+pIDList->aoffset[0]);
1148 hr = pSFParent->GetAttributesOf(1, &parent_pidl, &attribs);
1149 if (SUCCEEDED(hr) && (attribs & SFGAO_FILESYSTEM) &&
1150 SHGetPathFromIDListW(parent_pidl, parent_path))
1151 {
1152 parent_dir = parent_path;
1153 }
1154
1155 for (i = pIDList->cidl; i > 0; --i)
1156 {
1157 LPCITEMIDLIST pidl;
1158
1159 pidl = (LPCITEMIDLIST)((LPBYTE)pIDList+pIDList->aoffset[i]);
1160
1161 attribs = SFGAO_FOLDER;
1162 hr = pSFParent->GetAttributesOf(1, &pidl, &attribs);
1163
1164 if (SUCCEEDED(hr) && ! (attribs & SFGAO_FOLDER))
1165 {
1166 SHELLEXECUTEINFOW shexinfo;
1167
1168 shexinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
1169 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; /* SEE_MASK_IDLIST is also possible. */
1170 shexinfo.hwnd = NULL;
1171 shexinfo.lpVerb = NULL;
1172 shexinfo.lpFile = NULL;
1173 shexinfo.lpParameters = NULL;
1174 shexinfo.lpDirectory = parent_dir;
1175 shexinfo.nShow = SW_NORMAL;
1176 shexinfo.lpIDList = ILCombine(parent_pidl, pidl);
1177
1178 ShellExecuteExW(&shexinfo); /* Discard error/success info */
1179
1180 ILFree((LPITEMIDLIST)shexinfo.lpIDList);
1181 }
1182 }
1183
1184 GlobalUnlock(stgm.hGlobal);
1185 ReleaseStgMedium(&stgm);
1186
1187 return S_OK;
1188 }
1189
1190 /**********************************************************
1191 * ShellView_DoContextMenu()
1192 */
1193 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1194 {
1195 WORD x;
1196 WORD y;
1197 BOOL bDefault;
1198 UINT uCommand;
1199 DWORD wFlags;
1200 HMENU hMenu;
1201 BOOL fExplore;
1202 HWND hwndTree;
1203 CMINVOKECOMMANDINFO cmi;
1204 HRESULT hResult;
1205
1206 // for some reason I haven't figured out, we sometimes recurse into this method
1207 if (pCM != NULL)
1208 return 0;
1209
1210 x = LOWORD(lParam);
1211 y = HIWORD(lParam);
1212 bDefault = FALSE;
1213
1214 TRACE("(%p)->(0x%08x 0x%08x 0x%08x) stub\n",this, x, y, bDefault);
1215
1216 fExplore = FALSE;
1217 hwndTree = NULL;
1218
1219 /* look, what's selected and create a context menu object of it*/
1220 if (GetSelections())
1221 {
1222 pSFParent->GetUIObjectOf(hWndParent, cidl, (LPCITEMIDLIST*)apidl, IID_IContextMenu, NULL, (LPVOID *)&pCM);
1223
1224 if(pCM)
1225 {
1226 TRACE("-- pContextMenu\n");
1227 hMenu = CreatePopupMenu();
1228
1229 if( hMenu )
1230 {
1231 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1232 /* See if we are in Explore or Open mode. If the browser's tree is present, we are in Explore mode.*/
1233 if(SUCCEEDED(pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
1234 {
1235 TRACE("-- explore mode\n");
1236 fExplore = TRUE;
1237 }
1238
1239 /* build the flags depending on what we can do with the selected item */
1240 wFlags = CMF_NORMAL | (cidl != 1 ? 0 : CMF_CANRENAME) | (fExplore ? CMF_EXPLORE : 0);
1241
1242 /* let the ContextMenu merge its items in */
1243 if (SUCCEEDED(pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags )))
1244 {
1245 if (FolderSettings.fFlags & FWF_DESKTOP)
1246 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1247
1248 if( bDefault )
1249 {
1250 TRACE("-- get menu default command\n");
1251 uCommand = GetMenuDefaultItem(hMenu, FALSE, GMDI_GOINTOPOPUPS);
1252 }
1253 else
1254 {
1255 TRACE("-- track popup\n");
1256 uCommand = TrackPopupMenu( hMenu,TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
1257 }
1258
1259 if(uCommand > 0)
1260 {
1261 TRACE("-- uCommand=%u\n", uCommand);
1262 if (uCommand==FCIDM_SHVIEW_OPEN && pCommDlgBrowser.p != NULL)
1263 {
1264 TRACE("-- dlg: OnDefaultCommand\n");
1265 if (OnDefaultCommand() != S_OK)
1266 {
1267 OpenSelectedItems();
1268 }
1269 }
1270 else
1271 {
1272 TRACE("-- explore -- invoke command\n");
1273 ZeroMemory(&cmi, sizeof(cmi));
1274 cmi.cbSize = sizeof(cmi);
1275 cmi.hwnd = hWndParent; /* this window has to answer CWM_GETISHELLBROWSER */
1276 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1277 pCM->InvokeCommand(&cmi);
1278 }
1279 }
1280 hResult = IUnknown_SetSite(pCM, NULL);
1281 DestroyMenu(hMenu);
1282 }
1283 }
1284 pCM.Release();
1285 }
1286 }
1287 else /* background context menu */
1288 {
1289 hMenu = CreatePopupMenu();
1290
1291 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)&pCM);
1292 pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1293
1294 uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
1295 DestroyMenu(hMenu);
1296
1297 TRACE("-- (%p)->(uCommand=0x%08x )\n",this, uCommand);
1298
1299 ZeroMemory(&cmi, sizeof(cmi));
1300 cmi.cbSize = sizeof(cmi);
1301 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1302 cmi.hwnd = hWndParent;
1303 pCM->InvokeCommand(&cmi);
1304
1305 pCM.Release();
1306 }
1307 return 0;
1308 }
1309
1310 /**********************************************************
1311 * ##### message handling #####
1312 */
1313
1314 /**********************************************************
1315 * ShellView_OnSize()
1316 */
1317 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1318 {
1319 WORD wWidth;
1320 WORD wHeight;
1321
1322 wWidth = LOWORD(lParam);
1323 wHeight = HIWORD(lParam);
1324
1325 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1326
1327 /*resize the ListView to fit our window*/
1328 if (hWndList)
1329 {
1330 ::MoveWindow(hWndList, 0, 0, wWidth, wHeight, TRUE);
1331 }
1332
1333 return 0;
1334 }
1335
1336 /**********************************************************
1337 * ShellView_OnDeactivate()
1338 *
1339 * NOTES
1340 * internal
1341 */
1342 void CDefView::OnDeactivate()
1343 {
1344 TRACE("%p\n",this);
1345
1346 if(uState != SVUIA_DEACTIVATE)
1347 {
1348 if(hMenu)
1349 {
1350 pShellBrowser->SetMenuSB(0, 0, 0);
1351 pShellBrowser->RemoveMenusSB(hMenu);
1352 DestroyMenu(hMenu);
1353 hMenu = 0;
1354 }
1355
1356 uState = SVUIA_DEACTIVATE;
1357 }
1358 }
1359
1360 void CDefView::DoActivate(UINT uState)
1361 {
1362 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1363 MENUITEMINFOA mii;
1364 CHAR szText[MAX_PATH];
1365
1366 TRACE("%p uState=%x\n", this, uState);
1367
1368 /*don't do anything if the state isn't really changing */
1369 if(uState == uState)
1370 {
1371 return;
1372 }
1373
1374 OnDeactivate();
1375
1376 /*only do This if we are active */
1377 if(uState != SVUIA_DEACTIVATE)
1378 {
1379 /*merge the menus */
1380 hMenu = CreateMenu();
1381
1382 if(hMenu)
1383 {
1384 pShellBrowser->InsertMenusSB(hMenu, &omw);
1385 TRACE("-- after fnInsertMenusSB\n");
1386
1387 /*build the top level menu get the menu item's text*/
1388 strcpy(szText,"dummy 31");
1389
1390 ZeroMemory(&mii, sizeof(mii));
1391 mii.cbSize = sizeof(mii);
1392 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1393 mii.fType = MFT_STRING;
1394 mii.fState = MFS_ENABLED;
1395 mii.dwTypeData = szText;
1396 mii.hSubMenu = BuildFileMenu();
1397
1398 /*insert our menu into the menu bar*/
1399 if(mii.hSubMenu)
1400 {
1401 InsertMenuItemA(hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1402 }
1403
1404 /*get the view menu so we can merge with it*/
1405 ZeroMemory(&mii, sizeof(mii));
1406 mii.cbSize = sizeof(mii);
1407 mii.fMask = MIIM_SUBMENU;
1408
1409 if(GetMenuItemInfoA(hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1410 {
1411 MergeViewMenu(mii.hSubMenu);
1412 }
1413
1414 /*add the items that should only be added if we have the focus*/
1415 if(SVUIA_ACTIVATE_FOCUS == uState)
1416 {
1417 /*get the file menu so we can merge with it */
1418 ZeroMemory(&mii, sizeof(mii));
1419 mii.cbSize = sizeof(mii);
1420 mii.fMask = MIIM_SUBMENU;
1421
1422 if(GetMenuItemInfoA(hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1423 {
1424 MergeFileMenu(mii.hSubMenu);
1425 }
1426 }
1427 TRACE("-- before fnSetMenuSB\n");
1428 pShellBrowser->SetMenuSB(hMenu, 0, m_hWnd);
1429 }
1430 }
1431 uState = uState;
1432 TRACE("--\n");
1433 }
1434
1435 /**********************************************************
1436 * ShellView_OnActivate()
1437 */
1438 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1439 {
1440 DoActivate(SVUIA_ACTIVATE_FOCUS);
1441 return 0;
1442 }
1443
1444 /**********************************************************
1445 * ShellView_OnSetFocus()
1446 *
1447 */
1448 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1449 {
1450 TRACE("%p\n", this);
1451
1452 /* Tell the browser one of our windows has received the focus. This
1453 should always be done before merging menus (OnActivate merges the
1454 menus) if one of our windows has the focus.*/
1455
1456 pShellBrowser->OnViewWindowActive((IShellView *)this);
1457 DoActivate(SVUIA_ACTIVATE_FOCUS);
1458
1459 /* Set the focus to the listview */
1460 ::SetFocus(hWndList);
1461
1462 /* Notify the ICommDlgBrowser interface */
1463 OnStateChange(CDBOSC_SETFOCUS);
1464
1465 return 0;
1466 }
1467
1468 /**********************************************************
1469 * ShellView_OnKillFocus()
1470 */
1471 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1472 {
1473 TRACE("(%p) stub\n", this);
1474
1475 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1476 /* Notify the ICommDlgBrowser */
1477 OnStateChange(CDBOSC_KILLFOCUS);
1478
1479 return 0;
1480 }
1481
1482 /**********************************************************
1483 * ShellView_OnCommand()
1484 *
1485 * NOTES
1486 * the CmdID's are the ones from the context menu
1487 */
1488 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1489 {
1490 DWORD dwCmdID;
1491 DWORD dwCmd;
1492 HWND hwndCmd;
1493
1494 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1495 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1496 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1497
1498 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n",this, dwCmdID, dwCmd, hwndCmd);
1499
1500 switch(dwCmdID)
1501 {
1502 case FCIDM_SHVIEW_SMALLICON:
1503 FolderSettings.ViewMode = FVM_SMALLICON;
1504 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1505 CheckToolbar();
1506 break;
1507
1508 case FCIDM_SHVIEW_BIGICON:
1509 FolderSettings.ViewMode = FVM_ICON;
1510 SetStyle (LVS_ICON, LVS_TYPEMASK);
1511 CheckToolbar();
1512 break;
1513
1514 case FCIDM_SHVIEW_LISTVIEW:
1515 FolderSettings.ViewMode = FVM_LIST;
1516 SetStyle (LVS_LIST, LVS_TYPEMASK);
1517 CheckToolbar();
1518 break;
1519
1520 case FCIDM_SHVIEW_REPORTVIEW:
1521 FolderSettings.ViewMode = FVM_DETAILS;
1522 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1523 CheckToolbar();
1524 break;
1525
1526 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1527 case 0x30:
1528 case 0x31:
1529 case 0x32:
1530 case 0x33:
1531 ListViewSortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1532 ListViewSortInfo.bIsAscending = TRUE;
1533 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1534 SendMessageA(hWndList, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1535 break;
1536
1537 default:
1538 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1539 }
1540 return 0;
1541 }
1542
1543 /**********************************************************
1544 * ShellView_OnNotify()
1545 */
1546
1547 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1548 {
1549 UINT CtlID;
1550 LPNMHDR lpnmh;
1551 LPNMLISTVIEW lpnmlv;
1552 NMLVDISPINFOW *lpdi;
1553 LPITEMIDLIST pidl;
1554 BOOL unused;
1555
1556 CtlID = wParam;
1557 lpnmh = (LPNMHDR)lParam;
1558 lpnmlv = (LPNMLISTVIEW)lpnmh;
1559 lpdi = (NMLVDISPINFOW *)lpnmh;
1560
1561 TRACE("%p CtlID=%u lpnmh->code=%x\n",this,CtlID,lpnmh->code);
1562
1563 switch(lpnmh->code)
1564 {
1565 case NM_SETFOCUS:
1566 TRACE("-- NM_SETFOCUS %p\n", this);
1567 OnSetFocus(0, 0, 0, unused);
1568 break;
1569
1570 case NM_KILLFOCUS:
1571 TRACE("-- NM_KILLFOCUS %p\n", this);
1572 OnDeactivate();
1573 /* Notify the ICommDlgBrowser interface */
1574 OnStateChange(CDBOSC_KILLFOCUS);
1575 break;
1576
1577 case NM_CUSTOMDRAW:
1578 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1579 return CDRF_DODEFAULT;
1580
1581 case NM_RELEASEDCAPTURE:
1582 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1583 break;
1584
1585 case NM_CLICK:
1586 TRACE("-- NM_CLICK %p\n", this);
1587 break;
1588
1589 case NM_RCLICK:
1590 TRACE("-- NM_RCLICK %p\n", this);
1591 break;
1592
1593 case NM_DBLCLK:
1594 TRACE("-- NM_DBLCLK %p\n", this);
1595 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1596 break;
1597
1598 case NM_RETURN:
1599 TRACE("-- NM_RETURN %p\n", this);
1600 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1601 break;
1602
1603 case HDN_ENDTRACKW:
1604 TRACE("-- HDN_ENDTRACKW %p\n", this);
1605 /*nColumn1 = ListView_GetColumnWidth(hWndList, 0);
1606 nColumn2 = ListView_GetColumnWidth(hWndList, 1);*/
1607 break;
1608
1609 case LVN_DELETEITEM:
1610 TRACE("-- LVN_DELETEITEM %p\n", this);
1611 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1612 break;
1613
1614 case LVN_DELETEALLITEMS:
1615 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1616 return FALSE;
1617
1618 case LVN_INSERTITEM:
1619 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1620 break;
1621
1622 case LVN_ITEMACTIVATE:
1623 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1624 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1625 break;
1626
1627 case LVN_COLUMNCLICK:
1628 ListViewSortInfo.nHeaderID = lpnmlv->iSubItem;
1629 if(ListViewSortInfo.nLastHeaderID == ListViewSortInfo.nHeaderID)
1630 {
1631 ListViewSortInfo.bIsAscending = !ListViewSortInfo.bIsAscending;
1632 }
1633 else
1634 {
1635 ListViewSortInfo.bIsAscending = TRUE;
1636 }
1637 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1638
1639 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1640 break;
1641
1642 case LVN_GETDISPINFOA:
1643 case LVN_GETDISPINFOW:
1644 TRACE("-- LVN_GETDISPINFO %p\n", this);
1645 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1646
1647 if(lpdi->item.mask & LVIF_TEXT) /* text requested */
1648 {
1649 if (pSF2Parent)
1650 {
1651 SHELLDETAILS sd;
1652 pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd);
1653 if (lpnmh->code == LVN_GETDISPINFOA)
1654 {
1655 /* shouldn't happen */
1656 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1657 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1658 TRACE("-- text=%s\n",lpdiA->item.pszText);
1659 }
1660 else /* LVN_GETDISPINFOW */
1661 {
1662 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1663 TRACE("-- text=%s\n",debugstr_w(lpdi->item.pszText));
1664 }
1665 }
1666 else
1667 {
1668 FIXME("no SF2\n");
1669 }
1670 }
1671 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1672 {
1673 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidl, 0);
1674 }
1675 lpdi->item.mask |= LVIF_DI_SETITEM;
1676 break;
1677
1678 case LVN_ITEMCHANGED:
1679 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1680 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1681 break;
1682
1683 case LVN_BEGINDRAG:
1684 case LVN_BEGINRDRAG:
1685 TRACE("-- LVN_BEGINDRAG\n");
1686
1687 if (GetSelections())
1688 {
1689 IDataObject * pda;
1690 DWORD dwAttributes = SFGAO_CANLINK;
1691 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1692
1693 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject,0,(LPVOID *)&pda)))
1694 {
1695 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1696
1697 if (SUCCEEDED(pSFParent->GetAttributesOf(cidl, (LPCITEMIDLIST*)apidl, &dwAttributes)))
1698 {
1699 if (dwAttributes & SFGAO_CANLINK)
1700 {
1701 dwEffect |= DROPEFFECT_LINK;
1702 }
1703 }
1704
1705 if (pds)
1706 {
1707 DWORD dwEffect2;
1708 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1709 }
1710 pda->Release();
1711 }
1712 }
1713 break;
1714
1715 case LVN_BEGINLABELEDITW:
1716 {
1717 DWORD dwAttr = SFGAO_CANRENAME;
1718 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1719
1720 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1721
1722 pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1723 if (SFGAO_CANRENAME & dwAttr)
1724 {
1725 return FALSE;
1726 }
1727 return TRUE;
1728 }
1729
1730 case LVN_ENDLABELEDITW:
1731 {
1732 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1733 if (lpdi->item.pszText)
1734 {
1735 HRESULT hr;
1736 LVITEMW lvItem;
1737
1738 lvItem.iItem = lpdi->item.iItem;
1739 lvItem.iSubItem = 0;
1740 lvItem.mask = LVIF_PARAM;
1741 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1742
1743 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1744 hr = pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1745
1746 if(SUCCEEDED(hr) && pidl)
1747 {
1748 lvItem.mask = LVIF_PARAM;
1749 lvItem.lParam = (LPARAM)pidl;
1750 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1751 return TRUE;
1752 }
1753 }
1754 return FALSE;
1755 }
1756
1757 case LVN_KEYDOWN:
1758 {
1759 /* MSG msg;
1760 msg.hwnd = m_hWnd;
1761 msg.message = WM_KEYDOWN;
1762 msg.wParam = plvKeyDown->wVKey;
1763 msg.lParam = 0;
1764 msg.time = 0;
1765 msg.pt = 0;*/
1766
1767 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1768 SHORT ctrl = GetKeyState(VK_CONTROL) & 0x8000;
1769
1770 /* initiate a rename of the selected file or directory */
1771 if(plvKeyDown->wVKey == VK_F2)
1772 {
1773 /* see how many files are selected */
1774 int i = ListView_GetSelectedCount(hWndList);
1775
1776 /* get selected item */
1777 if(i == 1)
1778 {
1779 /* get selected item */
1780 i = ListView_GetNextItem(hWndList, -1,
1781 LVNI_SELECTED);
1782
1783 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
1784 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
1785 }
1786 }
1787 #if 0
1788 TranslateAccelerator(m_hWnd, hAccel, &msg)
1789 #endif
1790 else if(plvKeyDown->wVKey == VK_DELETE)
1791 {
1792 UINT i;
1793 int item_index;
1794 LVITEMA item;
1795 LPITEMIDLIST* pItems;
1796 ISFHelper *psfhlp;
1797
1798 pSFParent->QueryInterface(IID_ISFHelper,
1799 (LPVOID*)&psfhlp);
1800
1801 if (psfhlp == NULL)
1802 break;
1803
1804 if(!(i = ListView_GetSelectedCount(hWndList)))
1805 break;
1806
1807 /* allocate memory for the pidl array */
1808 pItems = (LPITEMIDLIST *)HeapAlloc(GetProcessHeap(), 0,
1809 sizeof(LPITEMIDLIST) * i);
1810
1811 /* retrieve all selected items */
1812 i = 0;
1813 item_index = -1;
1814 while(ListView_GetSelectedCount(hWndList) > i)
1815 {
1816 /* get selected item */
1817 item_index = ListView_GetNextItem(hWndList,
1818 item_index, LVNI_SELECTED);
1819 item.iItem = item_index;
1820 item.mask = LVIF_PARAM;
1821 SendMessageA(hWndList, LVM_GETITEMA, 0, (LPARAM) &item);
1822
1823 /* get item pidl */
1824 pItems[i] = (LPITEMIDLIST)item.lParam;
1825
1826 i++;
1827 }
1828
1829 /* perform the item deletion */
1830 psfhlp->DeleteItems(i, (LPCITEMIDLIST*)pItems);
1831
1832 /* free pidl array memory */
1833 HeapFree(GetProcessHeap(), 0, pItems);
1834 }
1835
1836 /* Initiate a refresh */
1837 else if(plvKeyDown->wVKey == VK_F5)
1838 {
1839 Refresh();
1840 }
1841 else if(plvKeyDown->wVKey == VK_BACK)
1842 {
1843 LPSHELLBROWSER lpSb;
1844 if((lpSb = (LPSHELLBROWSER)SendMessageW(hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1845 {
1846 lpSb->BrowseObject(NULL, SBSP_PARENT);
1847 }
1848 }
1849 else if(plvKeyDown->wVKey == 'C' && ctrl)
1850 {
1851 if (GetSelections())
1852 {
1853 CComPtr<IDataObject> pda;
1854
1855 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1856 {
1857 HRESULT hr = OleSetClipboard(pda);
1858 if (FAILED(hr))
1859 {
1860 WARN("OleSetClipboard failed");
1861 }
1862 }
1863 }
1864 break;
1865 }
1866 else if(plvKeyDown->wVKey == 'V' && ctrl)
1867 {
1868 CComPtr<IDataObject> pda;
1869 STGMEDIUM medium;
1870 FORMATETC formatetc;
1871 LPITEMIDLIST * apidl;
1872 LPITEMIDLIST pidl;
1873 CComPtr<IShellFolder> psfFrom;
1874 CComPtr<IShellFolder> psfDesktop;
1875 CComPtr<IShellFolder> psfTarget;
1876 LPIDA lpcida;
1877 CComPtr<ISFHelper> psfhlpdst;
1878 CComPtr<ISFHelper> psfhlpsrc;
1879 HRESULT hr;
1880
1881 hr = OleGetClipboard(&pda);
1882 if (hr != S_OK)
1883 {
1884 ERR("Failed to get clipboard with %lx\n", hr);
1885 return E_FAIL;
1886 }
1887
1888 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
1889 hr = pda->GetData(&formatetc, &medium);
1890
1891 if (FAILED(hr))
1892 {
1893 ERR("Failed to get clipboard data with %lx\n", hr);
1894 return E_FAIL;
1895 }
1896
1897 /* lock the handle */
1898 lpcida = (LPIDA)GlobalLock(medium.hGlobal);
1899 if (!lpcida)
1900 {
1901 ERR("failed to lock pidl\n");
1902 ReleaseStgMedium(&medium);
1903 return E_FAIL;
1904 }
1905
1906 /* convert the data into pidl */
1907 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1908
1909 if (!apidl)
1910 {
1911 ERR("failed to copy pidl\n");
1912 return E_FAIL;
1913 }
1914
1915 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
1916 {
1917 ERR("failed to get desktop folder\n");
1918 SHFree(pidl);
1919 _ILFreeaPidl(apidl, lpcida->cidl);
1920 ReleaseStgMedium(&medium);
1921 return E_FAIL;
1922 }
1923
1924 if (_ILIsDesktop(pidl))
1925 {
1926 /* use desktop shellfolder */
1927 psfFrom = psfDesktop;
1928 }
1929 else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
1930 {
1931 ERR("no IShellFolder\n");
1932
1933 SHFree(pidl);
1934 _ILFreeaPidl(apidl, lpcida->cidl);
1935 ReleaseStgMedium(&medium);
1936
1937 return E_FAIL;
1938 }
1939
1940 psfTarget = pSFParent;
1941
1942
1943 /* get source and destination shellfolder */
1944 if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
1945 {
1946 ERR("no IID_ISFHelper for destination\n");
1947
1948 SHFree(pidl);
1949 _ILFreeaPidl(apidl, lpcida->cidl);
1950 ReleaseStgMedium(&medium);
1951
1952 return E_FAIL;
1953 }
1954
1955 if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
1956 {
1957 ERR("no IID_ISFHelper for source\n");
1958
1959 SHFree(pidl);
1960 _ILFreeaPidl(apidl, lpcida->cidl);
1961 ReleaseStgMedium(&medium);
1962 return E_FAIL;
1963 }
1964
1965 /* FIXXME
1966 * do we want to perform a copy or move ???
1967 */
1968 hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
1969
1970 SHFree(pidl);
1971 _ILFreeaPidl(apidl, lpcida->cidl);
1972 ReleaseStgMedium(&medium);
1973
1974 TRACE("paste end hr %x\n", hr);
1975 break;
1976 }
1977 else
1978 FIXME("LVN_KEYDOWN key=0x%08x\n",plvKeyDown->wVKey);
1979 }
1980 break;
1981
1982 default:
1983 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1984 break;
1985 }
1986 return 0;
1987 }
1988
1989 /**********************************************************
1990 * ShellView_OnChange()
1991 */
1992 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1993 {
1994 LPITEMIDLIST *Pidls;
1995
1996 Pidls = (LPITEMIDLIST *)wParam;
1997
1998 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1999
2000 switch (lParam)
2001 {
2002 case SHCNE_MKDIR:
2003 case SHCNE_CREATE:
2004 LV_AddItem(Pidls[0]);
2005 break;
2006 case SHCNE_RMDIR:
2007 case SHCNE_DELETE:
2008 LV_DeleteItem(Pidls[0]);
2009 break;
2010 case SHCNE_RENAMEFOLDER:
2011 case SHCNE_RENAMEITEM:
2012 LV_RenameItem(Pidls[0], Pidls[1]);
2013 break;
2014 case SHCNE_UPDATEITEM:
2015 break;
2016 }
2017 return TRUE;
2018 }
2019
2020 /**********************************************************
2021 * ShellView_DoMeasureItem
2022 */
2023 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2024 {
2025 if (!pCM.p)
2026 {
2027 /* no menu */
2028 ERR("no menu!!!\n");
2029 return FALSE;
2030 }
2031
2032 if (pCM.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
2033 return TRUE;
2034 else
2035 return FALSE;
2036 }
2037
2038 /**********************************************************
2039 *
2040 *
2041 * The INTERFACE of the IShellView object
2042 *
2043 *
2044 **********************************************************
2045 */
2046
2047 /**********************************************************
2048 * ShellView_GetWindow
2049 */
2050 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2051 {
2052 TRACE("(%p)\n",this);
2053
2054 *phWnd = m_hWnd;
2055
2056 return S_OK;
2057 }
2058
2059 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2060 {
2061 FIXME("(%p) stub\n",this);
2062
2063 return E_NOTIMPL;
2064 }
2065
2066 /**********************************************************
2067 * IShellView_TranslateAccelerator
2068 *
2069 * FIXME:
2070 * use the accel functions
2071 */
2072 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2073 {
2074 #if 0
2075 FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n",this,lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
2076 #endif
2077
2078 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message >= WM_KEYLAST)
2079 {
2080 TRACE("-- key=0x04%lx\n",lpmsg->wParam) ;
2081 }
2082 return S_FALSE; /* not handled */
2083 }
2084
2085 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2086 {
2087 FIXME("(%p) stub\n",this);
2088
2089 return E_NOTIMPL;
2090 }
2091
2092 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2093 {
2094 /*
2095 CHAR szName[MAX_PATH];
2096 */
2097 LRESULT lResult;
2098 int nPartArray[1] = {-1};
2099
2100 TRACE("(%p)->(state=%x) stub\n",this, uState);
2101
2102 /*don't do anything if the state isn't really changing*/
2103 if(uState == uState)
2104 {
2105 return S_OK;
2106 }
2107
2108 /*OnActivate handles the menu merging and internal state*/
2109 DoActivate(uState);
2110
2111 /*only do This if we are active*/
2112 if(uState != SVUIA_DEACTIVATE)
2113 {
2114
2115 /*
2116 GetFolderPath is not a method of IShellFolder
2117 IShellFolder_GetFolderPath( pSFParent, szName, sizeof(szName) );
2118 */
2119 /* set the number of parts */
2120 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2121
2122 /* set the text for the parts */
2123 /*
2124 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2125 */
2126 }
2127
2128 return S_OK;
2129 }
2130
2131 HRESULT WINAPI CDefView::Refresh()
2132 {
2133 TRACE("(%p)\n",this);
2134
2135 SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
2136 FillList();
2137
2138 return S_OK;
2139 }
2140
2141 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2142 {
2143 *phWnd = 0;
2144
2145 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n",this, lpPrevView,lpfs, psb, prcView, phWnd);
2146
2147 DbgPrint("[shell32, CDefView::CreateViewWindow] Called lpfs = 0x%x, psb = 0x%x\n", lpfs, psb);
2148
2149 if (lpfs != NULL)
2150 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
2151 if (prcView != NULL)
2152 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2153
2154 /* Validate the Shell Browser */
2155 if (psb == NULL)
2156 return E_UNEXPECTED;
2157
2158 /*set up the member variables*/
2159 pShellBrowser = psb;
2160 FolderSettings = *lpfs;
2161
2162 /*get our parent window*/
2163 pShellBrowser->GetWindow(&hWndParent);
2164
2165 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2166 pCommDlgBrowser = NULL;
2167 if (SUCCEEDED(pShellBrowser->QueryInterface(IID_ICommDlgBrowser, (LPVOID *)&pCommDlgBrowser)))
2168 {
2169 TRACE("-- CommDlgBrowser\n");
2170 }
2171
2172 DbgPrint("[shell32, CDefView::CreateViewWindow] About to call the create function\n");
2173
2174 Create(hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
2175 if (m_hWnd == NULL)
2176 return E_FAIL;
2177
2178 *phWnd = m_hWnd;
2179
2180 CheckToolbar();
2181
2182 if (!*phWnd)
2183 return E_FAIL;
2184
2185 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2186 UpdateWindow();
2187
2188 return S_OK;
2189 }
2190
2191 HRESULT WINAPI CDefView::DestroyViewWindow()
2192 {
2193 TRACE("(%p)\n",this);
2194
2195 /*Make absolutely sure all our UI is cleaned up.*/
2196 UIActivate(SVUIA_DEACTIVATE);
2197
2198 if(hMenu)
2199 {
2200 DestroyMenu(hMenu);
2201 }
2202
2203 DestroyWindow();
2204 pShellBrowser.Release();
2205 pCommDlgBrowser.Release();
2206
2207 return S_OK;
2208 }
2209
2210 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2211 {
2212 TRACE("(%p)->(%p) vmode=%x flags=%x\n",this, lpfs,
2213 FolderSettings.ViewMode, FolderSettings.fFlags);
2214
2215 if (!lpfs) return E_INVALIDARG;
2216
2217 *lpfs = FolderSettings;
2218 return NOERROR;
2219 }
2220
2221 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2222 {
2223 FIXME("(%p) stub\n",this);
2224
2225 return E_NOTIMPL;
2226 }
2227
2228 HRESULT WINAPI CDefView::SaveViewState()
2229 {
2230 FIXME("(%p) stub\n",this);
2231
2232 return S_OK;
2233 }
2234
2235 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2236 {
2237 int i;
2238
2239 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n",this, pidl, uFlags);
2240
2241 i = LV_FindItemByPidl(pidl);
2242
2243 if (i != -1)
2244 {
2245 LVITEMW lvItem;
2246
2247 if(uFlags & SVSI_ENSUREVISIBLE)
2248 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
2249
2250 lvItem.mask = LVIF_STATE;
2251 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2252 lvItem.iItem = 0;
2253 lvItem.iSubItem = 0;
2254
2255 while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2256 {
2257 if (lvItem.iItem == i)
2258 {
2259 if (uFlags & SVSI_SELECT)
2260 lvItem.state |= LVIS_SELECTED;
2261 else
2262 lvItem.state &= ~LVIS_SELECTED;
2263
2264 if(uFlags & SVSI_FOCUSED)
2265 lvItem.state &= ~LVIS_FOCUSED;
2266 }
2267 else
2268 {
2269 if (uFlags & SVSI_DESELECTOTHERS)
2270 lvItem.state &= ~LVIS_SELECTED;
2271 }
2272 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2273 lvItem.iItem++;
2274 }
2275
2276
2277 if(uFlags & SVSI_EDIT)
2278 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
2279
2280 }
2281 return S_OK;
2282 }
2283
2284 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2285 {
2286 HRESULT hr = E_FAIL;
2287
2288 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",this, uItem, debugstr_guid(&riid), ppvOut);
2289
2290 *ppvOut = NULL;
2291
2292 switch(uItem)
2293 {
2294 case SVGIO_BACKGROUND:
2295 if (IsEqualIID(riid, IID_IContextMenu))
2296 {
2297 //*ppvOut = ISvBgCm_Constructor(pSFParent, FALSE);
2298 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2299 if (!ppvOut)
2300 hr = E_OUTOFMEMORY;
2301 }
2302 break;
2303
2304 case SVGIO_SELECTION:
2305 GetSelections();
2306 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, riid, 0, ppvOut);
2307 break;
2308 }
2309 TRACE("-- (%p)->(interface=%p)\n",this, *ppvOut);
2310
2311 return hr;
2312 }
2313
2314 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2315 {
2316 return E_NOTIMPL;
2317 }
2318
2319 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2320 {
2321 return E_NOTIMPL;
2322 }
2323
2324 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2325 {
2326 if (pSFParent == NULL)
2327 return E_FAIL;
2328 return pSFParent->QueryInterface(riid, ppv);
2329 }
2330
2331 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2332 {
2333 return E_NOTIMPL;
2334 }
2335
2336 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2337 {
2338 return E_NOTIMPL;
2339 }
2340
2341 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2342 {
2343 return E_NOTIMPL;
2344 }
2345
2346 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2347 {
2348 return E_NOTIMPL;
2349 }
2350
2351 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2352 {
2353 return E_NOTIMPL;
2354 }
2355
2356 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2357 {
2358 return E_NOTIMPL;
2359 }
2360
2361 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2362 {
2363 return E_NOTIMPL;
2364 }
2365
2366 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2367 {
2368 return E_NOTIMPL;
2369 }
2370
2371 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2372 {
2373 return E_NOTIMPL;
2374 }
2375
2376 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2377 {
2378 return E_NOTIMPL;
2379 }
2380
2381 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2382 {
2383 return E_NOTIMPL;
2384 }
2385
2386 /**********************************************************
2387 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2388 */
2389 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2390 {
2391 UINT i;
2392
2393 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2394 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2395
2396 if (!prgCmds)
2397 return E_POINTER;
2398 for (i = 0; i < cCmds; i++)
2399 {
2400 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2401 prgCmds[i].cmdf = 0;
2402 }
2403 return OLECMDERR_E_UNKNOWNGROUP;
2404 }
2405
2406 /**********************************************************
2407 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2408 *
2409 * nCmdID is the OLECMDID_* enumeration
2410 */
2411 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2412 {
2413 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2414 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2415
2416 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2417 (nCmdID == 0x29) &&
2418 (nCmdexecopt == 4) && pvaOut)
2419 return S_OK;
2420 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2421 (nCmdID == 9) &&
2422 (nCmdexecopt == 0))
2423 return 1;
2424
2425 return OLECMDERR_E_UNKNOWNGROUP;
2426 }
2427
2428 /**********************************************************
2429 * ISVDropTarget implementation
2430 */
2431
2432 /******************************************************************************
2433 * drag_notify_subitem [Internal]
2434 *
2435 * Figure out the shellfolder object, which is currently under the mouse cursor
2436 * and notify it via the IDropTarget interface.
2437 */
2438
2439 #define SCROLLAREAWIDTH 20
2440
2441 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2442 {
2443 LVHITTESTINFO htinfo;
2444 LVITEMW lvItem;
2445 LONG lResult;
2446 HRESULT hr;
2447 RECT clientRect;
2448
2449 /* Map from global to client coordinates and query the index of the listview-item, which is
2450 * currently under the mouse cursor. */
2451 htinfo.pt.x = pt.x;
2452 htinfo.pt.y = pt.y;
2453 htinfo.flags = LVHT_ONITEM;
2454 ::ScreenToClient(hWndList, &htinfo.pt);
2455 lResult = SendMessageW(hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2456
2457 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2458 ::GetClientRect(hWndList, &clientRect);
2459 if (htinfo.pt.x == ptLastMousePos.x && htinfo.pt.y == ptLastMousePos.y &&
2460 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2461 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2462 {
2463 cScrollDelay = (cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2464 if (cScrollDelay == 0) { /* Mouse did hover another 250 ms over the scroll-area */
2465 if (htinfo.pt.x < SCROLLAREAWIDTH)
2466 SendMessageW(hWndList, WM_HSCROLL, SB_LINEUP, 0);
2467 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2468 SendMessageW(hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2469 if (htinfo.pt.y < SCROLLAREAWIDTH)
2470 SendMessageW(hWndList, WM_VSCROLL, SB_LINEUP, 0);
2471 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2472 SendMessageW(hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2473 }
2474 } else {
2475 cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2476 }
2477 ptLastMousePos = htinfo.pt;
2478
2479 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2480 if (pCurDropTarget && lResult == iDragOverItem)
2481 return pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2482
2483 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2484 if (pCurDropTarget) {
2485 pCurDropTarget->DragLeave();
2486 pCurDropTarget.Release();
2487 }
2488
2489 iDragOverItem = lResult;
2490 if (lResult == -1) {
2491 /* We are not above one of the listview's subitems. Bind to the parent folder's
2492 * DropTarget interface. */
2493 hr = pSFParent->QueryInterface(IID_IDropTarget,
2494 (LPVOID*)&pCurDropTarget);
2495 } else {
2496 /* Query the relative PIDL of the shellfolder object represented by the currently
2497 * dragged over listview-item ... */
2498 lvItem.mask = LVIF_PARAM;
2499 lvItem.iItem = lResult;
2500 lvItem.iSubItem = 0;
2501 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2502
2503 /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2504 hr = pSFParent->GetUIObjectOf(hWndList, 1,
2505 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&pCurDropTarget);
2506 }
2507
2508 /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2509 if (FAILED(hr))
2510 return hr;
2511
2512 /* Notify the item just entered via DragEnter. */
2513 return pCurDropTarget->DragEnter(pCurDataObject, grfKeyState, pt, pdwEffect);
2514 }
2515
2516 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2517 {
2518 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2519 pCurDataObject = pDataObject;
2520 pDataObject->AddRef();
2521
2522 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2523 }
2524
2525 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2526 {
2527 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2528 }
2529
2530 HRESULT WINAPI CDefView::DragLeave()
2531 {
2532 if (pCurDropTarget)
2533 {
2534 pCurDropTarget->DragLeave();
2535 pCurDropTarget.Release();
2536 }
2537
2538 if (pCurDataObject != NULL)
2539 {
2540 pCurDataObject.Release();
2541 }
2542
2543 iDragOverItem = 0;
2544
2545 return S_OK;
2546 }
2547
2548 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2549 {
2550 if (pCurDropTarget)
2551 {
2552 pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2553 pCurDropTarget.Release();
2554 }
2555
2556 pCurDataObject.Release();
2557 iDragOverItem = 0;
2558
2559 return S_OK;
2560 }
2561
2562 /**********************************************************
2563 * ISVDropSource implementation
2564 */
2565
2566 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2567 {
2568 TRACE("(%p)\n",this);
2569
2570 if (fEscapePressed)
2571 return DRAGDROP_S_CANCEL;
2572 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2573 return DRAGDROP_S_DROP;
2574 else
2575 return NOERROR;
2576 }
2577
2578 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2579 {
2580 TRACE("(%p)\n",this);
2581
2582 return DRAGDROP_S_USEDEFAULTCURSORS;
2583 }
2584
2585 /**********************************************************
2586 * ISVViewObject implementation
2587 */
2588
2589 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)
2590 {
2591 FIXME("Stub: this=%p\n",this);
2592
2593 return E_NOTIMPL;
2594 }
2595
2596 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2597 {
2598 FIXME("Stub: this=%p\n",this);
2599
2600 return E_NOTIMPL;
2601 }
2602
2603 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2604 {
2605 FIXME("Stub: this=%p\n",this);
2606
2607 return E_NOTIMPL;
2608 }
2609
2610 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2611 {
2612 FIXME("Stub: this=%p\n",this);
2613
2614 return E_NOTIMPL;
2615 }
2616
2617 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2618 {
2619 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2620
2621 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2622 pAdvSink = pAdvSink;
2623 dwAspects = aspects;
2624 dwAdvf = advf;
2625
2626 return S_OK;
2627 }
2628
2629 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2630 {
2631 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2632
2633 if( ppAdvSink )
2634 {
2635 *ppAdvSink = pAdvSink;
2636 pAdvSink.p->AddRef();
2637 }
2638 if( pAspects )
2639 *pAspects = dwAspects;
2640 if( pAdvf )
2641 *pAdvf = dwAdvf;
2642
2643 return S_OK;
2644 }
2645
2646 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2647 {
2648 if (IsEqualIID(guidService, SID_IShellBrowser))
2649 return pShellBrowser->QueryInterface(riid, ppvObject);
2650 return E_NOINTERFACE;
2651 }
2652
2653 /**********************************************************
2654 * IShellView_Constructor
2655 */
2656 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2657 {
2658 CComObject<CDefView> *theView;
2659 CComPtr<IShellView> result;
2660 HRESULT hResult;
2661
2662 if (newView == NULL)
2663 return E_POINTER;
2664 *newView = NULL;
2665 ATLTRY (theView = new CComObject<CDefView>);
2666 if (theView == NULL)
2667 return E_OUTOFMEMORY;
2668 hResult = theView->QueryInterface (IID_IShellView, (void **)&result);
2669 if (FAILED (hResult))
2670 {
2671 delete theView;
2672 return hResult;
2673 }
2674 hResult = theView->Initialize (pFolder);
2675 if (FAILED (hResult))
2676 return hResult;
2677 *newView = result.Detach ();
2678 return S_OK;
2679 }