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