[SHELL32] CDefView: Query SFVM_DEFVIEWMODE before creating the list view.
[reactos.git] / dll / win32 / shell32 / CDefView.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: CheckToolbar: handle the "new folder" and "folder up" button
24 */
25
26 /*
27 TODO:
28 - Load/Save the view state from/into the stream provided by the ShellBrowser.
29 - When editing starts on item, set edit text to for editing value.
30 - Fix shell view to handle view mode popup exec.
31 - The background context menu should have a pidl just like foreground menus. This
32 causes crashes when dynamic handlers try to use the NULL pidl.
33 - Reorder of columns doesn't work - might be bug in comctl32
34 */
35
36 #include "precomp.h"
37
38 #include <atlwin.h>
39 #include <rosctrls.h>
40
41 WINE_DEFAULT_DEBUG_CHANNEL(shell);
42
43 #undef SV_CLASS_NAME
44
45 static const WCHAR SV_CLASS_NAME[] = {'S', 'H', 'E', 'L', 'L', 'D', 'L', 'L', '_', 'D', 'e', 'f', 'V', 'i', 'e', 'w', 0};
46
47 typedef struct
48 {
49 BOOL bIsAscending;
50 INT nHeaderID;
51 INT nLastHeaderID;
52 } LISTVIEW_SORT_INFO, *LPLISTVIEW_SORT_INFO;
53
54 #define SHV_CHANGE_NOTIFY WM_USER + 0x1111
55
56 /* For the context menu of the def view, the id of the items are based on 1 because we need
57 to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled */
58 #define CONTEXT_MENU_BASE_ID 1
59
60 class CDefView :
61 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
62 public CComObjectRootEx<CComMultiThreadModelNoCS>,
63 public IShellView2,
64 public IFolderView,
65 public IShellFolderView,
66 public IOleCommandTarget,
67 public IDropTarget,
68 public IDropSource,
69 public IViewObject,
70 public IServiceProvider
71 {
72 private:
73 CComPtr<IShellFolder> m_pSFParent;
74 CComPtr<IShellFolder2> m_pSF2Parent;
75 CComPtr<IShellFolderViewCB> m_pShellFolderViewCB;
76 CComPtr<IShellBrowser> m_pShellBrowser;
77 CComPtr<ICommDlgBrowser> m_pCommDlgBrowser;
78 CComPtr<IShellFolderViewDual> m_pShellFolderViewDual;
79 CListView m_ListView;
80 HWND m_hWndParent;
81 FOLDERSETTINGS m_FolderSettings;
82 HMENU m_hMenu; /* Handle to the menu bar of the browser */
83 HMENU m_hMenuArrangeModes; /* Handle to the popup menu with the arrange modes */
84 HMENU m_hMenuViewModes; /* Handle to the popup menu with the view modes */
85 HMENU m_hContextMenu; /* Handle to the open context menu */
86 BOOL m_bmenuBarInitialized;
87 UINT m_uState;
88 UINT m_cidl;
89 PCUITEMID_CHILD *m_apidl;
90 PIDLIST_ABSOLUTE m_pidlParent;
91 LISTVIEW_SORT_INFO m_sortInfo;
92 ULONG m_hNotify; /* Change notification handle */
93 HACCEL m_hAccel;
94 DWORD m_dwAspects;
95 DWORD m_dwAdvf;
96 CComPtr<IAdviseSink> m_pAdvSink;
97 // for drag and drop
98 CComPtr<IDataObject> m_pSourceDataObject;
99 CComPtr<IDropTarget> m_pCurDropTarget; /* The sub-item, which is currently dragged over */
100 CComPtr<IDataObject> m_pCurDataObject; /* The dragged data-object */
101 LONG m_iDragOverItem; /* Dragged over item's index, iff m_pCurDropTarget != NULL */
102 UINT m_cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
103 POINT m_ptLastMousePos; /* Mouse position at last DragOver call */
104 POINT m_ptFirstMousePos; /* Mouse position when the drag operation started */
105 DWORD m_grfKeyState;
106 //
107 CComPtr<IContextMenu> m_pCM;
108
109 BOOL m_isEditing;
110
111 CLSID m_Category;
112 BOOL m_Destroyed;
113
114 private:
115 HRESULT _MergeToolbar();
116 BOOL _Sort();
117 HRESULT _DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
118
119 public:
120 CDefView();
121 ~CDefView();
122 HRESULT WINAPI Initialize(IShellFolder *shellFolder);
123 HRESULT IncludeObject(PCUITEMID_CHILD pidl);
124 HRESULT OnDefaultCommand();
125 HRESULT OnStateChange(UINT uFlags);
126 void UpdateStatusbar();
127 void CheckToolbar();
128 void SetStyle(DWORD dwAdd, DWORD dwRemove);
129 BOOL CreateList();
130 void UpdateListColors();
131 BOOL InitList();
132 static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
133
134 PCUITEMID_CHILD _PidlByItem(int i);
135 PCUITEMID_CHILD _PidlByItem(LVITEM& lvItem);
136 int LV_FindItemByPidl(PCUITEMID_CHILD pidl);
137 BOOLEAN LV_AddItem(PCUITEMID_CHILD pidl);
138 BOOLEAN LV_DeleteItem(PCUITEMID_CHILD pidl);
139 BOOLEAN LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew);
140 BOOLEAN LV_ProdItem(PCUITEMID_CHILD pidl);
141 static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg);
142 HRESULT FillList();
143 HRESULT FillFileMenu();
144 HRESULT FillEditMenu();
145 HRESULT FillViewMenu();
146 HRESULT FillArrangeAsMenu(HMENU hmenuArrange);
147 HRESULT CheckViewMode(HMENU hmenuView);
148 UINT GetSelections();
149 HRESULT OpenSelectedItems();
150 void OnDeactivate();
151 void DoActivate(UINT uState);
152 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
153 HRESULT InvokeContextMenuCommand(UINT uCommand);
154 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
155
156 // *** IOleWindow methods ***
157 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
158 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
159
160 // *** IShellView methods ***
161 virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG *pmsg);
162 virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable);
163 virtual HRESULT STDMETHODCALLTYPE UIActivate(UINT uState);
164 virtual HRESULT STDMETHODCALLTYPE Refresh();
165 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
166 virtual HRESULT STDMETHODCALLTYPE DestroyViewWindow();
167 virtual HRESULT STDMETHODCALLTYPE GetCurrentInfo(LPFOLDERSETTINGS pfs);
168 virtual HRESULT STDMETHODCALLTYPE AddPropertySheetPages(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam);
169 virtual HRESULT STDMETHODCALLTYPE SaveViewState();
170 virtual HRESULT STDMETHODCALLTYPE SelectItem(PCUITEMID_CHILD pidlItem, SVSIF uFlags);
171 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
172
173 // *** IShellView2 methods ***
174 virtual HRESULT STDMETHODCALLTYPE GetView(SHELLVIEWID *view_guid, ULONG view_type);
175 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow2(LPSV2CVW2_PARAMS view_params);
176 virtual HRESULT STDMETHODCALLTYPE HandleRename(LPCITEMIDLIST new_pidl);
177 virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point);
178
179 // *** IShellView3 methods ***
180 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow3(IShellBrowser *psb, IShellView *psvPrevious, SV3CVW3_FLAGS view_flags, FOLDERFLAGS mask, FOLDERFLAGS flags, FOLDERVIEWMODE mode, const SHELLVIEWID *view_id, RECT *prcView, HWND *hwnd);
181
182 // *** IFolderView methods ***
183 virtual HRESULT STDMETHODCALLTYPE GetCurrentViewMode(UINT *pViewMode);
184 virtual HRESULT STDMETHODCALLTYPE SetCurrentViewMode(UINT ViewMode);
185 virtual HRESULT STDMETHODCALLTYPE GetFolder(REFIID riid, void **ppv);
186 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, PITEMID_CHILD *ppidl);
187 virtual HRESULT STDMETHODCALLTYPE ItemCount(UINT uFlags, int *pcItems);
188 virtual HRESULT STDMETHODCALLTYPE Items(UINT uFlags, REFIID riid, void **ppv);
189 virtual HRESULT STDMETHODCALLTYPE GetSelectionMarkedItem(int *piItem);
190 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
191 virtual HRESULT STDMETHODCALLTYPE GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt);
192 virtual HRESULT STDMETHODCALLTYPE GetSpacing(POINT *ppt);
193 virtual HRESULT STDMETHODCALLTYPE GetDefaultSpacing(POINT *ppt);
194 virtual HRESULT STDMETHODCALLTYPE GetAutoArrange();
195 virtual HRESULT STDMETHODCALLTYPE SelectItem(int iItem, DWORD dwFlags);
196 virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags);
197
198 // *** IShellFolderView methods ***
199 virtual HRESULT STDMETHODCALLTYPE Rearrange(LPARAM sort);
200 virtual HRESULT STDMETHODCALLTYPE GetArrangeParam(LPARAM *sort);
201 virtual HRESULT STDMETHODCALLTYPE ArrangeGrid();
202 virtual HRESULT STDMETHODCALLTYPE AutoArrange();
203 virtual HRESULT STDMETHODCALLTYPE AddObject(PITEMID_CHILD pidl, UINT *item);
204 virtual HRESULT STDMETHODCALLTYPE GetObject(PITEMID_CHILD *pidl, UINT item);
205 virtual HRESULT STDMETHODCALLTYPE RemoveObject(PITEMID_CHILD pidl, UINT *item);
206 virtual HRESULT STDMETHODCALLTYPE GetObjectCount(UINT *count);
207 virtual HRESULT STDMETHODCALLTYPE SetObjectCount(UINT count, UINT flags);
208 virtual HRESULT STDMETHODCALLTYPE UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item);
209 virtual HRESULT STDMETHODCALLTYPE RefreshObject(PITEMID_CHILD pidl, UINT *item);
210 virtual HRESULT STDMETHODCALLTYPE SetRedraw(BOOL redraw);
211 virtual HRESULT STDMETHODCALLTYPE GetSelectedCount(UINT *count);
212 virtual HRESULT STDMETHODCALLTYPE GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items);
213 virtual HRESULT STDMETHODCALLTYPE IsDropOnSource(IDropTarget *drop_target);
214 virtual HRESULT STDMETHODCALLTYPE GetDragPoint(POINT *pt);
215 virtual HRESULT STDMETHODCALLTYPE GetDropPoint(POINT *pt);
216 virtual HRESULT STDMETHODCALLTYPE MoveIcons(IDataObject *obj);
217 virtual HRESULT STDMETHODCALLTYPE SetItemPos(PCUITEMID_CHILD pidl, POINT *pt);
218 virtual HRESULT STDMETHODCALLTYPE IsBkDropTarget(IDropTarget *drop_target);
219 virtual HRESULT STDMETHODCALLTYPE SetClipboard(BOOL move);
220 virtual HRESULT STDMETHODCALLTYPE SetPoints(IDataObject *obj);
221 virtual HRESULT STDMETHODCALLTYPE GetItemSpacing(ITEMSPACING *spacing);
222 virtual HRESULT STDMETHODCALLTYPE SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb);
223 virtual HRESULT STDMETHODCALLTYPE Select(UINT flags);
224 virtual HRESULT STDMETHODCALLTYPE QuerySupport(UINT *support);
225 virtual HRESULT STDMETHODCALLTYPE SetAutomationObject(IDispatch *disp);
226
227 // *** IOleCommandTarget methods ***
228 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
229 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
230
231 // *** IDropTarget methods ***
232 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
233 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
234 virtual HRESULT STDMETHODCALLTYPE DragLeave();
235 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
236
237 // *** IDropSource methods ***
238 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
239 virtual HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
240
241 // *** IViewObject methods ***
242 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
243 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
244 BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
245 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
246 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
247 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
248 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
249 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
250 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
251
252 // *** IServiceProvider methods ***
253 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
254
255 // Message handlers
256 LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
257 LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
258 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
259 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
260 LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
261 LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
262 LRESULT OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
263 LRESULT OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
264 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
265 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
266 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
267 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
268 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
269 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
270 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
271 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
272 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
273 LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
274 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
275 LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
276
277 static ATL::CWndClassInfo& GetWndClassInfo()
278 {
279 static ATL::CWndClassInfo wc =
280 {
281 { sizeof(WNDCLASSEX), CS_PARENTDC, StartWindowProc,
282 0, 0, NULL, NULL,
283 LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, SV_CLASS_NAME, NULL
284 },
285 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
286 };
287 return wc;
288 }
289
290 virtual WNDPROC GetWindowProc()
291 {
292 return WindowProc;
293 }
294
295 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
296 {
297 CDefView *pThis;
298 LRESULT result;
299
300 // Must hold a reference during message handling
301 pThis = reinterpret_cast<CDefView *>(hWnd);
302 pThis->AddRef();
303 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
304 pThis->Release();
305 return result;
306 }
307
308 BEGIN_MSG_MAP(CDefView)
309 MESSAGE_HANDLER(WM_SIZE, OnSize)
310 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
311 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
312 MESSAGE_HANDLER(WM_NCCREATE, OnNCCreate)
313 MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)
314 MESSAGE_HANDLER(WM_CREATE, OnCreate)
315 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
316 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
317 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
318 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
319 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
320 MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem)
321 MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem)
322 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
323 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
324 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
325 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
326 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
327 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser)
328 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
329 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
330 END_MSG_MAP()
331
332 BEGIN_COM_MAP(CDefView)
333 // Windows returns E_NOINTERFACE for IOleWindow
334 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
335 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
336 COM_INTERFACE_ENTRY_IID(IID_CDefView, IShellView)
337 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2)
338 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
339 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView)
340 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
341 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
342 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
343 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject)
344 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
345 END_COM_MAP()
346 };
347
348 /*menu items */
349 #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
350 #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
351 #define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
352
353 #define ID_LISTVIEW 1
354
355 /*windowsx.h */
356 #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
357 #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
358 #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
359
360 typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
361
362 CDefView::CDefView() :
363 m_ListView(),
364 m_hWndParent(NULL),
365 m_hMenu(NULL),
366 m_hMenuArrangeModes(NULL),
367 m_hMenuViewModes(NULL),
368 m_hContextMenu(NULL),
369 m_bmenuBarInitialized(FALSE),
370 m_uState(0),
371 m_cidl(0),
372 m_apidl(NULL),
373 m_pidlParent(NULL),
374 m_hNotify(0),
375 m_hAccel(NULL),
376 m_dwAspects(0),
377 m_dwAdvf(0),
378 m_iDragOverItem(0),
379 m_cScrollDelay(0),
380 m_isEditing(FALSE),
381 m_Destroyed(FALSE)
382 {
383 ZeroMemory(&m_FolderSettings, sizeof(m_FolderSettings));
384 ZeroMemory(&m_sortInfo, sizeof(m_sortInfo));
385 ZeroMemory(&m_ptLastMousePos, sizeof(m_ptLastMousePos));
386 ZeroMemory(&m_Category, sizeof(m_Category));
387 }
388
389 CDefView::~CDefView()
390 {
391 TRACE(" destroying IShellView(%p)\n", this);
392
393 if (m_hWnd)
394 {
395 DestroyViewWindow();
396 }
397
398 SHFree(m_apidl);
399 }
400
401 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
402 {
403 m_pSFParent = shellFolder;
404 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &m_pSF2Parent));
405
406 return S_OK;
407 }
408
409 /**********************************************************
410 *
411 * ##### helperfunctions for communication with ICommDlgBrowser #####
412 */
413 HRESULT CDefView::IncludeObject(PCUITEMID_CHILD pidl)
414 {
415 HRESULT ret = S_OK;
416
417 if (m_pCommDlgBrowser.p != NULL)
418 {
419 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
420 ret = m_pCommDlgBrowser->IncludeObject(this, pidl);
421 TRACE("-- returns 0x%08x\n", ret);
422 }
423
424 return ret;
425 }
426
427 HRESULT CDefView::OnDefaultCommand()
428 {
429 HRESULT ret = S_FALSE;
430
431 if (m_pCommDlgBrowser.p != NULL)
432 {
433 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
434 ret = m_pCommDlgBrowser->OnDefaultCommand(this);
435 TRACE("-- returns 0x%08x\n", ret);
436 }
437
438 return ret;
439 }
440
441 HRESULT CDefView::OnStateChange(UINT uFlags)
442 {
443 HRESULT ret = S_FALSE;
444
445 if (m_pCommDlgBrowser.p != NULL)
446 {
447 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
448 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags);
449 TRACE("--\n");
450 }
451
452 return ret;
453 }
454 /**********************************************************
455 * set the toolbar of the filedialog buttons
456 *
457 * - activates the buttons from the shellbrowser according to
458 * the view state
459 */
460 void CDefView::CheckToolbar()
461 {
462 LRESULT result;
463
464 TRACE("\n");
465
466 if (m_pCommDlgBrowser != NULL)
467 {
468 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
469 FCIDM_TB_SMALLICON, (m_FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result);
470 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
471 FCIDM_TB_REPORTVIEW, (m_FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result);
472 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
473 FCIDM_TB_SMALLICON, TRUE, &result);
474 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
475 FCIDM_TB_REPORTVIEW, TRUE, &result);
476 }
477 }
478
479 void CDefView::UpdateStatusbar()
480 {
481 WCHAR szFormat[MAX_PATH] = {0};
482 WCHAR szObjects[MAX_PATH] = {0};
483 UINT cSelectedItems;
484
485 cSelectedItems = m_ListView.GetSelectedCount();
486 if (cSelectedItems)
487 {
488 LoadStringW(shell32_hInstance, IDS_OBJECTS_SELECTED, szFormat, _countof(szFormat));
489 StringCchPrintfW(szObjects, MAX_PATH, szFormat, cSelectedItems);
490 }
491 else
492 {
493 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat));
494 StringCchPrintfW(szObjects, MAX_PATH, szFormat, m_ListView.GetItemCount());
495 }
496 m_pShellBrowser->SetStatusTextSB(szObjects);
497 }
498
499 /**********************************************************
500 *
501 * ##### helperfunctions for initializing the view #####
502 */
503 /**********************************************************
504 * change the style of the listview control
505 */
506 void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
507 {
508 DWORD tmpstyle;
509
510 TRACE("(%p)\n", this);
511
512 tmpstyle = ::GetWindowLongPtrW(m_ListView, GWL_STYLE);
513 ::SetWindowLongPtrW(m_ListView, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
514 }
515
516 /**********************************************************
517 * ShellView_CreateList()
518 *
519 * - creates the list view window
520 */
521 BOOL CDefView::CreateList()
522 {
523 HRESULT hr;
524 DWORD dwStyle, dwExStyle;
525 UINT ViewMode;
526
527 TRACE("%p\n", this);
528
529 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
530 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
531 dwExStyle = WS_EX_CLIENTEDGE;
532
533 if (m_FolderSettings.fFlags & FWF_DESKTOP)
534 dwStyle |= LVS_ALIGNLEFT;
535 else
536 dwStyle |= LVS_ALIGNTOP | LVS_SHOWSELALWAYS;
537
538 ViewMode = m_FolderSettings.ViewMode;
539 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, NULL, (LPARAM)&ViewMode);
540 if (SUCCEEDED(hr))
541 {
542 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST)
543 m_FolderSettings.ViewMode = ViewMode;
544 else
545 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode);
546 }
547
548 switch (m_FolderSettings.ViewMode)
549 {
550 case FVM_ICON:
551 dwStyle |= LVS_ICON;
552 break;
553
554 case FVM_DETAILS:
555 dwStyle |= LVS_REPORT;
556 break;
557
558 case FVM_SMALLICON:
559 dwStyle |= LVS_SMALLICON;
560 break;
561
562 case FVM_LIST:
563 dwStyle |= LVS_LIST;
564 break;
565
566 default:
567 dwStyle |= LVS_LIST;
568 break;
569 }
570
571 if (m_FolderSettings.fFlags & FWF_AUTOARRANGE)
572 dwStyle |= LVS_AUTOARRANGE;
573
574 if (m_FolderSettings.fFlags & FWF_DESKTOP)
575 m_FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
576
577 if (m_FolderSettings.fFlags & FWF_SINGLESEL)
578 dwStyle |= LVS_SINGLESEL;
579
580 if (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE)
581 dwExStyle &= ~WS_EX_CLIENTEDGE;
582
583 RECT rcListView = {0,0,0,0};
584 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW);
585
586 if (!m_ListView)
587 return FALSE;
588
589 m_sortInfo.bIsAscending = TRUE;
590 m_sortInfo.nHeaderID = -1;
591 m_sortInfo.nLastHeaderID = -1;
592
593 UpdateListColors();
594
595 /* UpdateShellSettings(); */
596 return TRUE;
597 }
598
599 void CDefView::UpdateListColors()
600 {
601 if (m_FolderSettings.fFlags & FWF_DESKTOP)
602 {
603 /* Check if drop shadows option is enabled */
604 BOOL bDropShadow = FALSE;
605 DWORD cbDropShadow = sizeof(bDropShadow);
606
607 /*
608 * The desktop ListView always take the default desktop colours, by
609 * remaining transparent and letting user32/win32k paint itself the
610 * desktop background color, if any.
611 */
612 m_ListView.SetBkColor(CLR_NONE);
613
614 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
615 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow);
616 if (bDropShadow)
617 {
618 /* Set the icon background transparent */
619 m_ListView.SetTextBkColor(CLR_NONE);
620 m_ListView.SetTextColor(RGB(255, 255, 255));
621 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
622 }
623 else
624 {
625 /* Set the icon background as the same colour as the desktop */
626 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP);
627 m_ListView.SetTextBkColor(crDesktop);
628 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
629 m_ListView.SetTextColor(RGB(0, 0, 0));
630 else
631 m_ListView.SetTextColor(RGB(255, 255, 255));
632 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT);
633 }
634 }
635 }
636
637 /**********************************************************
638 * ShellView_InitList()
639 *
640 * - adds all needed columns to the shellview
641 */
642 BOOL CDefView::InitList()
643 {
644 SHELLDETAILS sd;
645 WCHAR szTemp[50];
646 HIMAGELIST big_icons, small_icons;
647
648 TRACE("%p\n", this);
649
650 m_ListView.DeleteAllItems();
651
652 m_hMenuArrangeModes = CreateMenu();
653
654 if (m_pSF2Parent)
655 {
656 for (int i = 0; 1; i++)
657 {
658 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
659 break;
660 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
661 m_ListView.InsertColumn(i, szTemp, sd.fmt, sd.cxChar * 8);
662
663 InsertMenuW(m_hMenuArrangeModes, -1, MF_STRING, 0x30 + i, szTemp);
664 }
665
666 InsertMenuW(m_hMenuArrangeModes, -1, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
667 }
668 else
669 {
670 FIXME("no m_pSF2Parent\n");
671 }
672
673 Shell_GetImageLists(&big_icons, &small_icons);
674 m_ListView.SetImageList(big_icons, LVSIL_NORMAL);
675 m_ListView.SetImageList(small_icons, LVSIL_SMALL);
676
677 return TRUE;
678 }
679
680 /*************************************************************************
681 * ShellView_ListViewCompareItems
682 *
683 * Compare Function for the Listview (FileOpen Dialog)
684 *
685 * PARAMS
686 * lParam1 [I] the first ItemIdList to compare with
687 * lParam2 [I] the second ItemIdList to compare with
688 * lpData [I] The column ID for the header Ctrl to process
689 *
690 * RETURNS
691 * A negative value if the first item should precede the second,
692 * a positive value if the first item should follow the second,
693 * or zero if the two items are equivalent
694 */
695 INT CALLBACK CDefView::ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
696 {
697 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
698 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
699 CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
700
701 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2);
702 if (FAILED_UNEXPECTEDLY(hres))
703 return 0;
704
705 SHORT nDiff = HRESULT_CODE(hres);
706 if (!pThis->m_sortInfo.bIsAscending)
707 nDiff = -nDiff;
708 return nDiff;
709 }
710
711 BOOL CDefView::_Sort()
712 {
713 HWND hHeader;
714 HDITEM hColumn;
715
716 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER)
717 return TRUE;
718
719 hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0);
720 ZeroMemory(&hColumn, sizeof(hColumn));
721
722 /* If the sorting column changed, remove the sorting style from the old column */
723 if ( (m_sortInfo.nLastHeaderID != -1) &&
724 (m_sortInfo.nLastHeaderID != m_sortInfo.nHeaderID) )
725 {
726 hColumn.mask = HDI_FORMAT;
727 Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
728 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
729 Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
730 }
731
732 /* Set the sorting style to the new column */
733 hColumn.mask = HDI_FORMAT;
734 Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
735
736 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
737 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
738 Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
739
740 /* Sort the list, using the current values of nHeaderID and bIsAscending */
741 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
742 return m_ListView.SortItems(ListViewCompareItems, this);
743 }
744
745 PCUITEMID_CHILD CDefView::_PidlByItem(int i)
746 {
747 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
748 }
749
750 PCUITEMID_CHILD CDefView::_PidlByItem(LVITEM& lvItem)
751 {
752 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
753 }
754
755 /**********************************************************
756 * LV_FindItemByPidl()
757 */
758 int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
759 {
760 int cItems = m_ListView.GetItemCount();
761
762 for (int i = 0; i<cItems; i++)
763 {
764 PCUITEMID_CHILD currentpidl = _PidlByItem(i);
765 HRESULT hr = m_pSFParent->CompareIDs(0, pidl, currentpidl);
766
767 if (SUCCEEDED(hr) && !HRESULT_CODE(hr))
768 {
769 return i;
770 }
771 }
772 return -1;
773 }
774
775 /**********************************************************
776 * LV_AddItem()
777 */
778 BOOLEAN CDefView::LV_AddItem(PCUITEMID_CHILD pidl)
779 {
780 LVITEMW lvItem;
781
782 TRACE("(%p)(pidl=%p)\n", this, pidl);
783
784 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
785 lvItem.iItem = m_ListView.GetItemCount(); /*add the item to the end of the list*/
786 lvItem.iSubItem = 0;
787 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); /*set the item's data*/
788 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
789 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
790 lvItem.stateMask = LVIS_CUT;
791
792 if (m_ListView.InsertItem(&lvItem) == -1)
793 return FALSE;
794 else
795 return TRUE;
796 }
797
798 /**********************************************************
799 * LV_DeleteItem()
800 */
801 BOOLEAN CDefView::LV_DeleteItem(PCUITEMID_CHILD pidl)
802 {
803 int nIndex;
804
805 TRACE("(%p)(pidl=%p)\n", this, pidl);
806
807 nIndex = LV_FindItemByPidl(pidl);
808
809 return (-1 == m_ListView.DeleteItem(nIndex)) ? FALSE : TRUE;
810 }
811
812 /**********************************************************
813 * LV_RenameItem()
814 */
815 BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew)
816 {
817 int nItem;
818 LVITEMW lvItem;
819
820 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
821
822 nItem = LV_FindItemByPidl(pidlOld);
823
824 if ( -1 != nItem )
825 {
826 lvItem.mask = LVIF_PARAM; /* only the pidl */
827 lvItem.iItem = nItem;
828 lvItem.iSubItem = 0;
829 m_ListView.GetItem(&lvItem);
830
831 SHFree(reinterpret_cast<LPVOID>(lvItem.lParam));
832 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
833 lvItem.iItem = nItem;
834 lvItem.iSubItem = 0;
835 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); /* set the item's data */
836 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
837 m_ListView.SetItem(&lvItem);
838 m_ListView.Update(nItem);
839 return TRUE; /* FIXME: better handling */
840 }
841
842 return FALSE;
843 }
844
845 /**********************************************************
846 * LV_ProdItem()
847 */
848 BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl)
849 {
850 int nItem;
851 LVITEMW lvItem;
852
853 TRACE("(%p)(pidl=%p)\n", this, pidl);
854
855 nItem = LV_FindItemByPidl(pidl);
856
857 if (-1 != nItem)
858 {
859 lvItem.mask = LVIF_IMAGE;
860 lvItem.iItem = nItem;
861 lvItem.iSubItem = 0;
862 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
863 m_ListView.SetItem(&lvItem);
864 m_ListView.Update(nItem);
865 return TRUE;
866 }
867
868 return FALSE;
869 }
870
871 /**********************************************************
872 * ShellView_FillList()
873 *
874 * - gets the objectlist from the shellfolder
875 * - sorts the list
876 * - fills the list into the view
877 */
878 INT CALLBACK CDefView::fill_list(LPVOID ptr, LPVOID arg)
879 {
880 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
881 CDefView *pThis = static_cast<CDefView *>(arg);
882
883 /* in a commdlg This works as a filemask*/
884 if (pThis->IncludeObject(pidl) == S_OK)
885 pThis->LV_AddItem(pidl);
886
887 SHFree(pidl);
888 return TRUE;
889 }
890
891 HRESULT CDefView::FillList()
892 {
893 CComPtr<IEnumIDList> pEnumIDList;
894 PITEMID_CHILD pidl;
895 DWORD dwFetched;
896 HRESULT hRes;
897 HDPA hdpa;
898 HKEY hKey;
899 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
900
901 TRACE("%p\n", this);
902
903 /* determine if there is a setting to show all the hidden files/folders */
904 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
905 {
906 DWORD dataLength, flagVal;
907
908 dataLength = sizeof(flagVal);
909 if (RegQueryValueExW(hKey, L"Hidden", NULL, NULL, (LPBYTE)&flagVal, &dataLength) == ERROR_SUCCESS)
910 {
911 /* if the value is 1, then show all hidden files/folders */
912 if (flagVal == 1)
913 {
914 dFlags |= SHCONTF_INCLUDEHIDDEN;
915 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
916 }
917 }
918
919 /* close the key */
920 RegCloseKey(hKey);
921 }
922
923 /* get the itemlist from the shfolder */
924 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
925 if (hRes != S_OK)
926 {
927 if (hRes == S_FALSE)
928 return(NOERROR);
929 return(hRes);
930 }
931
932 /* create a pointer array */
933 hdpa = DPA_Create(16);
934 if (!hdpa)
935 {
936 return(E_OUTOFMEMORY);
937 }
938
939 /* copy the items into the array*/
940 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
941 {
942 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
943 {
944 SHFree(pidl);
945 }
946 }
947
948 /*turn the listview's redrawing off*/
949 m_ListView.SetRedraw(FALSE);
950
951 DPA_DestroyCallback( hdpa, fill_list, this);
952
953 /* sort the array */
954 if (m_pSF2Parent)
955 {
956 m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
957 }
958 else
959 {
960 FIXME("no m_pSF2Parent\n");
961 }
962 m_sortInfo.bIsAscending = TRUE;
963 _Sort();
964
965 /*turn the listview's redrawing back on and force it to draw*/
966 m_ListView.SetRedraw(TRUE);
967
968 _DoFolderViewCB(SFVM_LISTREFRESHED, NULL, NULL);
969
970 return S_OK;
971 }
972
973 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
974 {
975 m_ListView.UpdateWindow();
976 bHandled = FALSE;
977 return 0;
978 }
979
980 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
981 {
982 return m_ListView.SendMessageW(uMsg, 0, 0);
983 }
984
985 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
986 {
987 if (!m_Destroyed)
988 {
989 m_Destroyed = TRUE;
990 if (m_hMenu)
991 {
992 DestroyMenu(m_hMenu);
993 m_hMenu = NULL;
994 }
995 RevokeDragDrop(m_hWnd);
996 SHChangeNotifyDeregister(m_hNotify);
997 m_hNotify = NULL;
998 SHFree(m_pidlParent);
999 m_pidlParent = NULL;
1000 }
1001 bHandled = FALSE;
1002 return 0;
1003 }
1004
1005 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1006 {
1007 /* redirect to parent */
1008 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
1009 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam);
1010
1011 bHandled = FALSE;
1012 return 0;
1013 }
1014
1015 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1016 {
1017 /* Update desktop labels color */
1018 UpdateListColors();
1019
1020 /* Forward WM_SYSCOLORCHANGE to common controls */
1021 return m_ListView.SendMessageW(uMsg, 0, 0);
1022 }
1023
1024 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1025 {
1026 return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1027 }
1028
1029 LRESULT CDefView::OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1030 {
1031 this->AddRef();
1032 bHandled = FALSE;
1033 return 0;
1034 }
1035
1036 LRESULT CDefView::OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1037 {
1038 this->Release();
1039 bHandled = FALSE;
1040 return 0;
1041 }
1042
1043 /**********************************************************
1044 * ShellView_OnCreate()
1045 */
1046 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1047 {
1048 CComPtr<IDropTarget> pdt;
1049 SHChangeNotifyEntry ntreg;
1050 CComPtr<IPersistFolder2> ppf2;
1051
1052 TRACE("%p\n", this);
1053
1054 if (CreateList())
1055 {
1056 if (InitList())
1057 {
1058 FillList();
1059 }
1060 }
1061
1062 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
1063 {
1064 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1065 ERR("Registering Drag Drop Failed");
1066 }
1067
1068 /* register for receiving notifications */
1069 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1070 if (ppf2)
1071 {
1072 ppf2->GetCurFolder(&m_pidlParent);
1073 ntreg.fRecursive = TRUE;
1074 ntreg.pidl = m_pidlParent;
1075 m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNRF_InterruptLevel | SHCNRF_ShellLevel, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
1076 }
1077
1078 /* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */
1079
1080 m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_SHELLVIEW));
1081
1082 UpdateStatusbar();
1083
1084 return S_OK;
1085 }
1086
1087 /**********************************************************
1088 * #### Handling of the menus ####
1089 */
1090
1091 extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1092
1093 HMENU GetSubmenuByID(HMENU hmenu, UINT id)
1094 {
1095 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
1096 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
1097 return mii.hSubMenu;
1098
1099 return NULL;
1100 }
1101
1102 /* ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
1103 GetMenuItemID returns -1 if the specified item opens a submenu */
1104 UINT ReallyGetMenuItemID(HMENU hmenu, int i)
1105 {
1106 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
1107 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
1108 return mii.wID;
1109
1110 return UINT_MAX;
1111 }
1112
1113 HRESULT CDefView::FillFileMenu()
1114 {
1115 HMENU hFileMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_FILE);
1116 if (!hFileMenu)
1117 return E_FAIL;
1118
1119 /* Cleanup the items added previously */
1120 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1121 {
1122 UINT id = GetMenuItemID(hFileMenu, i);
1123 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1124 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1125 }
1126
1127 /* Store the context menu in m_pCM and keep it in order to invoke the selected command later on */
1128 HRESULT hr = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1129 if (FAILED_UNEXPECTEDLY(hr))
1130 return hr;
1131
1132 HMENU hmenu = CreatePopupMenu();
1133
1134 hr = m_pCM->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1135 if (FAILED_UNEXPECTEDLY(hr))
1136 return hr;
1137
1138 // TODO: filter or something
1139
1140 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1141
1142 ::DestroyMenu(hmenu);
1143
1144 return S_OK;
1145 }
1146
1147 HRESULT CDefView::FillEditMenu()
1148 {
1149 HMENU hEditMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_EDIT);
1150 if (!hEditMenu)
1151 return E_FAIL;
1152
1153 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1154 if (!hmenuContents)
1155 return E_FAIL;
1156
1157 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1158
1159 ::DestroyMenu(hmenuContents);
1160
1161 return S_OK;
1162 }
1163
1164 HRESULT CDefView::FillViewMenu()
1165 {
1166 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
1167 if (!hViewMenu)
1168 return E_FAIL;
1169
1170 m_hMenuViewModes = ::LoadMenuW(shell32_hInstance, L"MENU_001");
1171 if (!m_hMenuViewModes)
1172 return E_FAIL;
1173
1174 UINT i = SHMenuIndexFromID(hViewMenu, FCIDM_MENU_VIEW_SEP_OPTIONS);
1175 Shell_MergeMenus(hViewMenu, m_hMenuViewModes, i, 0, 0xFFFF, MM_ADDSEPARATOR | MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
1176
1177 return S_OK;
1178 }
1179
1180 HRESULT CDefView::FillArrangeAsMenu(HMENU hmenuArrange)
1181 {
1182 /* We only need to fill this once */
1183 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE)
1184 {
1185 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF,0);
1186 }
1187
1188 /* Also check the menu item according to which we sort */
1189 CheckMenuRadioItem(hmenuArrange,
1190 0x30,
1191 0x100,
1192 m_sortInfo.nHeaderID + 0x30,
1193 MF_BYCOMMAND);
1194
1195 return S_OK;
1196 }
1197
1198 HRESULT CDefView::CheckViewMode(HMENU hmenuView)
1199 {
1200 if (m_FolderSettings.ViewMode >= FVM_FIRST && m_FolderSettings.ViewMode <= FVM_LAST)
1201 {
1202 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1203 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1204 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1205 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1206 }
1207
1208 return S_OK;
1209 }
1210
1211 /**********************************************************
1212 * ShellView_GetSelections()
1213 *
1214 * - fills the m_apidl list with the selected objects
1215 *
1216 * RETURNS
1217 * number of selected items
1218 */
1219 UINT CDefView::GetSelections()
1220 {
1221 SHFree(m_apidl);
1222
1223 m_cidl = m_ListView.GetSelectedCount();
1224 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
1225 if (!m_apidl)
1226 {
1227 m_cidl = 0;
1228 return 0;
1229 }
1230
1231 TRACE("-- Items selected =%u\n", m_cidl);
1232
1233 UINT i = 0;
1234 int lvIndex = -1;
1235 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1236 {
1237 m_apidl[i] = _PidlByItem(lvIndex);
1238 i++;
1239 if (i == m_cidl)
1240 break;
1241 TRACE("-- selected Item found\n");
1242 }
1243
1244 return m_cidl;
1245 }
1246
1247 HRESULT CDefView::InvokeContextMenuCommand(UINT uCommand)
1248 {
1249 CMINVOKECOMMANDINFO cmi;
1250
1251 ZeroMemory(&cmi, sizeof(cmi));
1252 cmi.cbSize = sizeof(cmi);
1253 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
1254 cmi.hwnd = m_hWnd;
1255
1256 if (GetKeyState(VK_SHIFT) & 0x8000)
1257 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1258
1259 if (GetKeyState(VK_CONTROL) & 0x8000)
1260 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1261
1262 HRESULT hr = m_pCM->InvokeCommand(&cmi);
1263 if (FAILED_UNEXPECTEDLY(hr))
1264 return hr;
1265
1266 return S_OK;
1267 }
1268
1269 /**********************************************************
1270 * ShellView_OpenSelectedItems()
1271 */
1272 HRESULT CDefView::OpenSelectedItems()
1273 {
1274 HMENU hMenu;
1275 UINT uCommand;
1276 HRESULT hResult;
1277
1278 m_cidl = m_ListView.GetSelectedCount();
1279 if (m_cidl == 0)
1280 return S_OK;
1281
1282 hResult = OnDefaultCommand();
1283 if (hResult == S_OK)
1284 return hResult;
1285
1286 hMenu = CreatePopupMenu();
1287 if (!hMenu)
1288 return E_FAIL;
1289
1290 hResult = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1291 if (FAILED_UNEXPECTEDLY(hResult))
1292 goto cleanup;
1293
1294 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY);
1295 if (FAILED_UNEXPECTEDLY(hResult))
1296 goto cleanup;
1297
1298 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1299 if (uCommand == (UINT)-1)
1300 {
1301 hResult = E_FAIL;
1302 goto cleanup;
1303 }
1304
1305 InvokeContextMenuCommand(uCommand);
1306
1307 cleanup:
1308
1309 if (hMenu)
1310 DestroyMenu(hMenu);
1311
1312 if (m_pCM)
1313 {
1314 IUnknown_SetSite(m_pCM, NULL);
1315 m_pCM.Release();
1316 }
1317
1318 return hResult;
1319 }
1320
1321 /**********************************************************
1322 * ShellView_DoContextMenu()
1323 */
1324 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1325 {
1326 WORD x, y;
1327 UINT uCommand;
1328 HRESULT hResult;
1329
1330 x = LOWORD(lParam);
1331 y = HIWORD(lParam);
1332
1333 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1334
1335 m_hContextMenu = CreatePopupMenu();
1336 if (!m_hContextMenu)
1337 return E_FAIL;
1338
1339 m_cidl = m_ListView.GetSelectedCount();
1340
1341 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1342 if (FAILED_UNEXPECTEDLY(hResult))
1343 goto cleanup;
1344
1345 /* Use 1 as the first id as we want 0 the mean that the user canceled the menu */
1346 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL);
1347 if (FAILED_UNEXPECTEDLY(hResult))
1348 goto cleanup;
1349
1350 uCommand = TrackPopupMenu(m_hContextMenu,
1351 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1352 x, y, 0, m_hWnd, NULL);
1353 if (uCommand == 0)
1354 goto cleanup;
1355
1356 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1357 goto cleanup;
1358
1359 InvokeContextMenuCommand(uCommand - CONTEXT_MENU_BASE_ID);
1360
1361 cleanup:
1362 if (m_pCM)
1363 {
1364 IUnknown_SetSite(m_pCM, NULL);
1365 m_pCM.Release();
1366 }
1367
1368 if (m_hContextMenu)
1369 {
1370 DestroyMenu(m_hContextMenu);
1371 m_hContextMenu = NULL;
1372 }
1373
1374 return 0;
1375 }
1376
1377 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1378 {
1379 HRESULT hResult;
1380 HMENU hMenu;
1381
1382 hMenu = CreatePopupMenu();
1383 if (!hMenu)
1384 return 0;
1385
1386 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1387 if (FAILED_UNEXPECTEDLY( hResult))
1388 goto cleanup;
1389
1390 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1391 if (FAILED_UNEXPECTEDLY( hResult))
1392 goto cleanup;
1393
1394 InvokeContextMenuCommand(uCommand);
1395
1396 cleanup:
1397 if (m_pCM)
1398 {
1399 IUnknown_SetSite(m_pCM, NULL);
1400 m_pCM.Release();
1401 }
1402
1403 if (hMenu)
1404 DestroyMenu(hMenu);
1405
1406 return 0;
1407 }
1408
1409 /**********************************************************
1410 * ##### message handling #####
1411 */
1412
1413 /**********************************************************
1414 * ShellView_OnSize()
1415 */
1416 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1417 {
1418 WORD wWidth, wHeight;
1419
1420 wWidth = LOWORD(lParam);
1421 wHeight = HIWORD(lParam);
1422
1423 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1424
1425 /* Resize the ListView to fit our window */
1426 if (m_ListView)
1427 {
1428 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1429 }
1430
1431 _DoFolderViewCB(SFVM_SIZE, 0, 0);
1432
1433 return 0;
1434 }
1435
1436 /**********************************************************
1437 * ShellView_OnDeactivate()
1438 *
1439 * NOTES
1440 * internal
1441 */
1442 void CDefView::OnDeactivate()
1443 {
1444 TRACE("%p\n", this);
1445
1446 if (m_uState != SVUIA_DEACTIVATE)
1447 {
1448 // TODO: cleanup menu after deactivation
1449
1450 m_uState = SVUIA_DEACTIVATE;
1451 }
1452 }
1453
1454 void CDefView::DoActivate(UINT uState)
1455 {
1456 TRACE("%p uState=%x\n", this, uState);
1457
1458 /*don't do anything if the state isn't really changing */
1459 if (m_uState == uState)
1460 {
1461 return;
1462 }
1463
1464 if (uState == SVUIA_DEACTIVATE)
1465 {
1466 OnDeactivate();
1467 }
1468 else
1469 {
1470 if(m_hMenu && !m_bmenuBarInitialized)
1471 {
1472 FillEditMenu();
1473 FillViewMenu();
1474 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1475 m_bmenuBarInitialized = TRUE;
1476 }
1477
1478 if (SVUIA_ACTIVATE_FOCUS == uState)
1479 {
1480 m_ListView.SetFocus();
1481 }
1482 }
1483
1484 m_uState = uState;
1485 TRACE("--\n");
1486 }
1487
1488 /**********************************************************
1489 * ShellView_OnActivate()
1490 */
1491 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1492 {
1493 DoActivate(SVUIA_ACTIVATE_FOCUS);
1494 return 0;
1495 }
1496
1497 /**********************************************************
1498 * ShellView_OnSetFocus()
1499 *
1500 */
1501 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1502 {
1503 TRACE("%p\n", this);
1504
1505 /* Tell the browser one of our windows has received the focus. This
1506 should always be done before merging menus (OnActivate merges the
1507 menus) if one of our windows has the focus.*/
1508
1509 m_pShellBrowser->OnViewWindowActive(this);
1510 DoActivate(SVUIA_ACTIVATE_FOCUS);
1511
1512 /* Set the focus to the listview */
1513 m_ListView.SetFocus();
1514
1515 /* Notify the ICommDlgBrowser interface */
1516 OnStateChange(CDBOSC_SETFOCUS);
1517
1518 return 0;
1519 }
1520
1521 /**********************************************************
1522 * ShellView_OnKillFocus()
1523 */
1524 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1525 {
1526 TRACE("(%p) stub\n", this);
1527
1528 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1529 /* Notify the ICommDlgBrowser */
1530 OnStateChange(CDBOSC_KILLFOCUS);
1531
1532 return 0;
1533 }
1534
1535 /**********************************************************
1536 * ShellView_OnCommand()
1537 *
1538 * NOTES
1539 * the CmdID's are the ones from the context menu
1540 */
1541 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1542 {
1543 DWORD dwCmdID;
1544 DWORD dwCmd;
1545 HWND hwndCmd;
1546 int nCount;
1547
1548 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1549 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1550 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1551
1552 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1553
1554 switch (dwCmdID)
1555 {
1556 case FCIDM_SHVIEW_SMALLICON:
1557 m_FolderSettings.ViewMode = FVM_SMALLICON;
1558 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1559 CheckToolbar();
1560 break;
1561
1562 case FCIDM_SHVIEW_BIGICON:
1563 m_FolderSettings.ViewMode = FVM_ICON;
1564 SetStyle (LVS_ICON, LVS_TYPEMASK);
1565 CheckToolbar();
1566 break;
1567
1568 case FCIDM_SHVIEW_LISTVIEW:
1569 m_FolderSettings.ViewMode = FVM_LIST;
1570 SetStyle (LVS_LIST, LVS_TYPEMASK);
1571 CheckToolbar();
1572 break;
1573
1574 case FCIDM_SHVIEW_REPORTVIEW:
1575 m_FolderSettings.ViewMode = FVM_DETAILS;
1576 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1577 CheckToolbar();
1578 break;
1579
1580 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1581 case 0x30:
1582 case 0x31:
1583 case 0x32:
1584 case 0x33:
1585 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1586 m_sortInfo.bIsAscending = TRUE;
1587 _Sort();
1588 break;
1589
1590 case FCIDM_SHVIEW_SNAPTOGRID:
1591 case FCIDM_SHVIEW_AUTOARRANGE:
1592 //FIXME
1593 break;
1594 case FCIDM_SHVIEW_SELECTALL:
1595 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
1596 break;
1597
1598 case FCIDM_SHVIEW_INVERTSELECTION:
1599 nCount = m_ListView.GetItemCount();
1600 for (int i=0; i < nCount; i++)
1601 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED);
1602 break;
1603
1604 case FCIDM_SHVIEW_REFRESH:
1605 Refresh();
1606 break;
1607
1608 case FCIDM_SHVIEW_DELETE:
1609 case FCIDM_SHVIEW_CUT:
1610 case FCIDM_SHVIEW_COPY:
1611 case FCIDM_SHVIEW_RENAME:
1612 case FCIDM_SHVIEW_PROPERTIES:
1613 return OnExplorerCommand(dwCmdID, TRUE);
1614
1615 case FCIDM_SHVIEW_INSERT:
1616 case FCIDM_SHVIEW_UNDO:
1617 case FCIDM_SHVIEW_INSERTLINK:
1618 case FCIDM_SHVIEW_NEWFOLDER:
1619 return OnExplorerCommand(dwCmdID, FALSE);
1620 default:
1621 /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pCM handle the command */
1622 if (m_pCM && dwCmd == 0)
1623 {
1624 InvokeContextMenuCommand(dwCmdID);
1625 }
1626 }
1627
1628 return 0;
1629 }
1630
1631 /**********************************************************
1632 * ShellView_OnNotify()
1633 */
1634
1635 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1636 {
1637 UINT CtlID;
1638 LPNMHDR lpnmh;
1639 LPNMLISTVIEW lpnmlv;
1640 NMLVDISPINFOW *lpdi;
1641 PCUITEMID_CHILD pidl;
1642 BOOL unused;
1643
1644 CtlID = wParam;
1645 lpnmh = (LPNMHDR)lParam;
1646 lpnmlv = (LPNMLISTVIEW)lpnmh;
1647 lpdi = (NMLVDISPINFOW *)lpnmh;
1648
1649 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1650
1651 switch (lpnmh->code)
1652 {
1653 case NM_SETFOCUS:
1654 TRACE("-- NM_SETFOCUS %p\n", this);
1655 OnSetFocus(0, 0, 0, unused);
1656 break;
1657
1658 case NM_KILLFOCUS:
1659 TRACE("-- NM_KILLFOCUS %p\n", this);
1660 OnDeactivate();
1661 /* Notify the ICommDlgBrowser interface */
1662 OnStateChange(CDBOSC_KILLFOCUS);
1663 break;
1664
1665 case NM_CUSTOMDRAW:
1666 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1667 return CDRF_DODEFAULT;
1668
1669 case NM_RELEASEDCAPTURE:
1670 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1671 break;
1672
1673 case NM_CLICK:
1674 TRACE("-- NM_CLICK %p\n", this);
1675 break;
1676
1677 case NM_RCLICK:
1678 TRACE("-- NM_RCLICK %p\n", this);
1679 break;
1680
1681 case NM_DBLCLK:
1682 TRACE("-- NM_DBLCLK %p\n", this);
1683 OpenSelectedItems();
1684 break;
1685
1686 case NM_RETURN:
1687 TRACE("-- NM_RETURN %p\n", this);
1688 OpenSelectedItems();
1689 break;
1690
1691 case HDN_ENDTRACKW:
1692 TRACE("-- HDN_ENDTRACKW %p\n", this);
1693 /*nColumn1 = m_ListView.GetColumnWidth(0);
1694 nColumn2 = m_ListView.GetColumnWidth(1);*/
1695 break;
1696
1697 case LVN_DELETEITEM:
1698 TRACE("-- LVN_DELETEITEM %p\n", this);
1699
1700 /*delete the pidl because we made a copy of it*/
1701 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
1702
1703 break;
1704
1705 case LVN_DELETEALLITEMS:
1706 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1707 return FALSE;
1708
1709 case LVN_INSERTITEM:
1710 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1711 break;
1712
1713 case LVN_ITEMACTIVATE:
1714 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1715 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1716 break;
1717
1718 case LVN_COLUMNCLICK:
1719 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1720 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1721 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1722 else
1723 m_sortInfo.bIsAscending = TRUE;
1724 _Sort();
1725 break;
1726
1727 case LVN_GETDISPINFOA:
1728 case LVN_GETDISPINFOW:
1729 TRACE("-- LVN_GETDISPINFO %p\n", this);
1730 pidl = _PidlByItem(lpdi->item);
1731
1732 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1733 {
1734 if (m_pSF2Parent)
1735 {
1736 SHELLDETAILS sd;
1737 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1738 break;
1739
1740 if (lpnmh->code == LVN_GETDISPINFOA)
1741 {
1742 /* shouldn't happen */
1743 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1744 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1745 TRACE("-- text=%s\n", lpdiA->item.pszText);
1746 }
1747 else /* LVN_GETDISPINFOW */
1748 {
1749 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1750 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1751 }
1752 }
1753 else
1754 {
1755 FIXME("no m_pSF2Parent\n");
1756 }
1757 }
1758 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1759 {
1760 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1761 }
1762 if(lpdi->item.mask & LVIF_STATE)
1763 {
1764 ULONG attributes = SFGAO_HIDDEN;
1765 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
1766 {
1767 if (attributes & SFGAO_HIDDEN)
1768 {
1769 lpdi->item.state |= LVIS_CUT;
1770 }
1771 }
1772 }
1773 lpdi->item.mask |= LVIF_DI_SETITEM;
1774 break;
1775
1776 case LVN_ITEMCHANGED:
1777 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1778 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1779 UpdateStatusbar();
1780 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
1781 break;
1782
1783 case LVN_BEGINDRAG:
1784 case LVN_BEGINRDRAG:
1785 TRACE("-- LVN_BEGINDRAG\n");
1786
1787 if (GetSelections())
1788 {
1789 CComPtr<IDataObject> pda;
1790 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
1791 DWORD dwEffect = DROPEFFECT_MOVE;
1792
1793 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
1794 {
1795 LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
1796
1797 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
1798 {
1799 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
1800 }
1801
1802 CComPtr<IAsyncOperation> piaso;
1803 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
1804 {
1805 piaso->SetAsyncMode(TRUE);
1806 }
1807
1808 DWORD dwEffect2;
1809
1810 m_pSourceDataObject = pda;
1811 m_ptFirstMousePos = params->ptAction;
1812 ClientToScreen(&m_ptFirstMousePos);
1813
1814 HIMAGELIST big_icons, small_icons;
1815 Shell_GetImageLists(&big_icons, &small_icons);
1816 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
1817 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1818 POINT ptItem;
1819 m_ListView.GetItemPosition(params->iItem, &ptItem);
1820
1821 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
1822
1823 DoDragDrop(pda, this, dwEffect, &dwEffect2);
1824
1825 m_pSourceDataObject.Release();
1826 }
1827 }
1828 break;
1829
1830 case LVN_BEGINLABELEDITW:
1831 {
1832 DWORD dwAttr = SFGAO_CANRENAME;
1833 pidl = _PidlByItem(lpdi->item);
1834
1835 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1836
1837 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
1838 if (SFGAO_CANRENAME & dwAttr)
1839 {
1840 m_isEditing = TRUE;
1841 return FALSE;
1842 }
1843 return TRUE;
1844 }
1845
1846 case LVN_ENDLABELEDITW:
1847 {
1848 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1849
1850 m_isEditing = FALSE;
1851
1852 if (lpdi->item.pszText)
1853 {
1854 HRESULT hr;
1855 LVITEMW lvItem;
1856
1857 pidl = _PidlByItem(lpdi->item);
1858 PITEMID_CHILD pidlNew;
1859 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
1860
1861 if (SUCCEEDED(hr) && pidlNew)
1862 {
1863 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1864 lvItem.iItem = lpdi->item.iItem;
1865 lvItem.iSubItem = 0;
1866 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
1867 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
1868 m_ListView.SetItem(&lvItem);
1869 m_ListView.Update(lpdi->item.iItem);
1870 return TRUE;
1871 }
1872 }
1873
1874 return FALSE;
1875 }
1876
1877 default:
1878 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1879 break;
1880 }
1881
1882 return 0;
1883 }
1884
1885 /*
1886 * This is just a quick hack to make the desktop work correctly.
1887 * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
1888 * a folder should know if it should update upon a change notification.
1889 * It is exported by merged folders at a minimum.
1890 */
1891 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
1892 {
1893 if (!pidl1 || !pidl2)
1894 return FALSE;
1895 if (ILIsParent(pidl1, pidl2, TRUE))
1896 return TRUE;
1897
1898 if (_ILIsDesktop(pidl1))
1899 {
1900 PIDLIST_ABSOLUTE deskpidl;
1901 SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
1902 if (ILIsParent(deskpidl, pidl2, TRUE))
1903 {
1904 ILFree(deskpidl);
1905 return TRUE;
1906 }
1907 ILFree(deskpidl);
1908 SHGetFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
1909 if (ILIsParent(deskpidl, pidl2, TRUE))
1910 {
1911 ILFree(deskpidl);
1912 return TRUE;
1913 }
1914 ILFree(deskpidl);
1915 }
1916 return FALSE;
1917 }
1918
1919 /**********************************************************
1920 * ShellView_OnChange()
1921 */
1922 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1923 {
1924 PCIDLIST_ABSOLUTE *Pidls = reinterpret_cast<PCIDLIST_ABSOLUTE*>(wParam);
1925 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
1926 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
1927
1928 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1929
1930 switch (lParam &~ SHCNE_INTERRUPT)
1931 {
1932 case SHCNE_MKDIR:
1933 case SHCNE_CREATE:
1934 if (bParent0)
1935 {
1936 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
1937 {
1938 LV_AddItem(ILFindLastID(Pidls[0]));
1939 }
1940 else
1941 {
1942 LV_ProdItem(ILFindLastID(Pidls[0]));
1943 }
1944 }
1945 break;
1946
1947 case SHCNE_RMDIR:
1948 case SHCNE_DELETE:
1949 if (bParent0)
1950 LV_DeleteItem(ILFindLastID(Pidls[0]));
1951 break;
1952
1953 case SHCNE_RENAMEFOLDER:
1954 case SHCNE_RENAMEITEM:
1955 if (bParent0 && bParent1)
1956 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
1957 else if (bParent0)
1958 LV_DeleteItem(ILFindLastID(Pidls[0]));
1959 else if (bParent1)
1960 LV_AddItem(ILFindLastID(Pidls[1]));
1961 break;
1962
1963 case SHCNE_UPDATEITEM:
1964 if (bParent0)
1965 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
1966 break;
1967
1968 case SHCNE_UPDATEDIR:
1969 Refresh();
1970 break;
1971 }
1972 return TRUE;
1973 }
1974
1975 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
1976 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
1977
1978 /**********************************************************
1979 * CDefView::OnCustomItem
1980 */
1981 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1982 {
1983 if (!m_pCM.p)
1984 {
1985 /* no menu */
1986 ERR("no menu!!!\n");
1987 return FALSE;
1988 }
1989
1990 /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
1991 be changed to a menu identifier offset */
1992 UINT CmdID;
1993 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
1994 if (SUCCEEDED(hres))
1995 SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
1996
1997 /* Forward the message to the IContextMenu2 */
1998 LRESULT result;
1999 hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
2000
2001 return (SUCCEEDED(hres));
2002 }
2003
2004 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2005 {
2006 /* Wallpaper setting affects drop shadows effect */
2007 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2008 UpdateListColors();
2009
2010 return S_OK;
2011 }
2012
2013 /**********************************************************
2014 * CDefView::OnInitMenuPopup
2015 */
2016 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2017 {
2018 HMENU hmenu = (HMENU) wParam;
2019 int nPos = LOWORD(lParam);
2020 UINT menuItemId;
2021
2022 OnCustomItem(uMsg, wParam, lParam, bHandled);
2023
2024 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2025
2026 /* Lets try to find out what the hell wParam is */
2027 if (hmenu == GetSubMenu(m_hMenu, nPos))
2028 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2029 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2030 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2031 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2032 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2033 else
2034 return FALSE;
2035
2036 switch (menuItemId)
2037 {
2038 case FCIDM_MENU_FILE:
2039 FillFileMenu();
2040 break;
2041 case FCIDM_MENU_VIEW:
2042 case FCIDM_SHVIEW_VIEW:
2043 CheckViewMode(hmenu);
2044 break;
2045 case FCIDM_SHVIEW_ARRANGE:
2046 FillArrangeAsMenu(hmenu);
2047 break;
2048 }
2049
2050 return FALSE;
2051 }
2052
2053 /**********************************************************
2054 *
2055 *
2056 * The INTERFACE of the IShellView object
2057 *
2058 *
2059 **********************************************************
2060 */
2061
2062 /**********************************************************
2063 * ShellView_GetWindow
2064 */
2065 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2066 {
2067 TRACE("(%p)\n", this);
2068
2069 *phWnd = m_hWnd;
2070
2071 return S_OK;
2072 }
2073
2074 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2075 {
2076 FIXME("(%p) stub\n", this);
2077
2078 return E_NOTIMPL;
2079 }
2080
2081 /**********************************************************
2082 * IShellView_TranslateAccelerator
2083 *
2084 * FIXME:
2085 * use the accel functions
2086 */
2087 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2088 {
2089 if (m_isEditing)
2090 return S_FALSE;
2091
2092 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2093 {
2094 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2095 return S_OK;
2096
2097 TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2098 }
2099
2100 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2101 }
2102
2103 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2104 {
2105 FIXME("(%p) stub\n", this);
2106
2107 return E_NOTIMPL;
2108 }
2109
2110 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2111 {
2112 // CHAR szName[MAX_PATH];
2113 LRESULT lResult;
2114 int nPartArray[1] = { -1};
2115
2116 TRACE("(%p)->(state=%x) stub\n", this, uState);
2117
2118 /* don't do anything if the state isn't really changing */
2119 if (m_uState == uState)
2120 {
2121 return S_OK;
2122 }
2123
2124 /* OnActivate handles the menu merging and internal state */
2125 DoActivate(uState);
2126
2127 /* only do This if we are active */
2128 if (uState != SVUIA_DEACTIVATE)
2129 {
2130
2131 /*
2132 GetFolderPath is not a method of IShellFolder
2133 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
2134 */
2135 /* set the number of parts */
2136 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2137
2138 /* set the text for the parts */
2139 /*
2140 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2141 */
2142 }
2143
2144 return S_OK;
2145 }
2146
2147 HRESULT WINAPI CDefView::Refresh()
2148 {
2149 TRACE("(%p)\n", this);
2150
2151 m_ListView.DeleteAllItems();
2152 FillList();
2153
2154 return S_OK;
2155 }
2156
2157 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2158 {
2159 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2160 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2161 }
2162
2163 HRESULT WINAPI CDefView::DestroyViewWindow()
2164 {
2165 TRACE("(%p)\n", this);
2166
2167 /* Make absolutely sure all our UI is cleaned up */
2168 UIActivate(SVUIA_DEACTIVATE);
2169
2170 if (m_hAccel)
2171 {
2172 // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2173 m_hAccel = NULL;
2174 }
2175
2176 if (m_hMenuArrangeModes)
2177 {
2178 DestroyMenu(m_hMenuArrangeModes);
2179 m_hMenuArrangeModes = NULL;
2180 }
2181
2182 if (m_hMenuViewModes)
2183 {
2184 DestroyMenu(m_hMenuViewModes);
2185 m_hMenuViewModes = NULL;
2186 }
2187
2188 if (m_hMenu)
2189 {
2190 DestroyMenu(m_hMenu);
2191 m_hMenu = NULL;
2192 }
2193
2194 if (m_ListView)
2195 {
2196 m_ListView.DestroyWindow();
2197 }
2198
2199 if (m_hWnd)
2200 {
2201 DestroyWindow();
2202 }
2203
2204 m_pShellBrowser.Release();
2205 m_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 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2214
2215 if (!lpfs)
2216 return E_INVALIDARG;
2217
2218 *lpfs = m_FolderSettings;
2219 return S_OK;
2220 }
2221
2222 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2223 {
2224 FIXME("(%p) stub\n", this);
2225
2226 return E_NOTIMPL;
2227 }
2228
2229 HRESULT WINAPI CDefView::SaveViewState()
2230 {
2231 FIXME("(%p) stub\n", this);
2232
2233 return S_OK;
2234 }
2235
2236 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
2237 {
2238 int i;
2239
2240 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2241
2242 i = LV_FindItemByPidl(pidl);
2243 if (i == -1)
2244 return S_OK;
2245
2246 if(uFlags & SVSI_ENSUREVISIBLE)
2247 m_ListView.EnsureVisible(i, FALSE);
2248
2249 LVITEMW lvItem = {0};
2250 lvItem.mask = LVIF_STATE;
2251 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2252
2253 while (m_ListView.GetItem(&lvItem))
2254 {
2255 if (lvItem.iItem == i)
2256 {
2257 if (uFlags & SVSI_SELECT)
2258 lvItem.state |= LVIS_SELECTED;
2259 else
2260 lvItem.state &= ~LVIS_SELECTED;
2261
2262 if (uFlags & SVSI_FOCUSED)
2263 lvItem.state &= ~LVIS_FOCUSED;
2264 }
2265 else
2266 {
2267 if (uFlags & SVSI_DESELECTOTHERS)
2268 lvItem.state &= ~LVIS_SELECTED;
2269 }
2270
2271 m_ListView.SetItem(&lvItem);
2272 lvItem.iItem++;
2273 }
2274
2275 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2276 m_ListView.EditLabel(i);
2277
2278 return S_OK;
2279 }
2280
2281 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2282 {
2283 HRESULT hr = E_NOINTERFACE;
2284
2285 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2286
2287 *ppvOut = NULL;
2288
2289 switch (uItem)
2290 {
2291 case SVGIO_BACKGROUND:
2292 if (IsEqualIID(riid, IID_IContextMenu))
2293 {
2294 if (!ppvOut)
2295 hr = E_OUTOFMEMORY;
2296
2297 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
2298 if (FAILED_UNEXPECTEDLY(hr))
2299 return hr;
2300
2301 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2302 }
2303 else if (IsEqualIID(riid, IID_IDispatch))
2304 {
2305 if (m_pShellFolderViewDual == NULL)
2306 {
2307 hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
2308 if (FAILED_UNEXPECTEDLY(hr))
2309 return hr;
2310 }
2311 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2312 }
2313 break;
2314
2315 case SVGIO_SELECTION:
2316 GetSelections();
2317 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2318 if (FAILED_UNEXPECTEDLY(hr))
2319 return hr;
2320
2321 if (IsEqualIID(riid, IID_IContextMenu))
2322 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2323
2324 break;
2325 }
2326
2327 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2328
2329 return hr;
2330 }
2331
2332 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2333 {
2334 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2335
2336 if (!pViewMode)
2337 return E_INVALIDARG;
2338
2339 *pViewMode = m_FolderSettings.ViewMode;
2340 return S_OK;
2341 }
2342
2343 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2344 {
2345 DWORD dwStyle;
2346 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2347
2348 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2349 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2350 return E_INVALIDARG;
2351
2352 /* Windows before Vista uses LVM_SETVIEW and possibly
2353 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2354 while later versions seem to accomplish this through other
2355 means. */
2356 switch (ViewMode)
2357 {
2358 case FVM_ICON:
2359 dwStyle = LVS_ICON;
2360 break;
2361 case FVM_DETAILS:
2362 dwStyle = LVS_REPORT;
2363 break;
2364 case FVM_SMALLICON:
2365 dwStyle = LVS_SMALLICON;
2366 break;
2367 case FVM_LIST:
2368 dwStyle = LVS_LIST;
2369 break;
2370 default:
2371 {
2372 FIXME("ViewMode %d not implemented\n", ViewMode);
2373 dwStyle = LVS_LIST;
2374 break;
2375 }
2376 }
2377
2378 SetStyle(dwStyle, LVS_TYPEMASK);
2379
2380 /* This will not necessarily be the actual mode set above.
2381 This mimics the behavior of Windows XP. */
2382 m_FolderSettings.ViewMode = ViewMode;
2383
2384 return S_OK;
2385 }
2386
2387 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2388 {
2389 if (m_pSFParent == NULL)
2390 return E_FAIL;
2391
2392 return m_pSFParent->QueryInterface(riid, ppv);
2393 }
2394
2395 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
2396 {
2397 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2398 if (pidl)
2399 {
2400 *ppidl = ILClone(pidl);
2401 return S_OK;
2402 }
2403
2404 *ppidl = 0;
2405 return E_INVALIDARG;
2406 }
2407
2408 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2409 {
2410 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2411
2412 if (uFlags != SVGIO_ALLVIEW)
2413 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2414
2415 *pcItems = m_ListView.GetItemCount();
2416
2417 return S_OK;
2418 }
2419
2420 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2421 {
2422 return E_NOTIMPL;
2423 }
2424
2425 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2426 {
2427 TRACE("(%p)->(%p)\n", this, piItem);
2428
2429 *piItem = m_ListView.GetSelectionMark();
2430
2431 return S_OK;
2432 }
2433
2434 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2435 {
2436 TRACE("(%p)->(%p)\n", this, piItem);
2437
2438 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2439
2440 return S_OK;
2441 }
2442
2443 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
2444 {
2445 int lvIndex = LV_FindItemByPidl(pidl);
2446 if (lvIndex == -1 || ppt == NULL)
2447 return E_INVALIDARG;
2448
2449 m_ListView.GetItemPosition(lvIndex, ppt);
2450 return S_OK;
2451 }
2452
2453 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2454 {
2455 TRACE("(%p)->(%p)\n", this, ppt);
2456
2457 if (!m_ListView)
2458 return S_FALSE;
2459
2460 if (ppt)
2461 {
2462 SIZE spacing;
2463 m_ListView.GetItemSpacing(spacing);
2464
2465 ppt->x = spacing.cx;
2466 ppt->y = spacing.cy;
2467 }
2468
2469 return S_OK;
2470 }
2471
2472 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2473 {
2474 return E_NOTIMPL;
2475 }
2476
2477 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2478 {
2479 return E_NOTIMPL;
2480 }
2481
2482 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2483 {
2484 LVITEMW lvItem;
2485
2486 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2487
2488 lvItem.state = 0;
2489 lvItem.stateMask = LVIS_SELECTED;
2490
2491 if (dwFlags & SVSI_ENSUREVISIBLE)
2492 m_ListView.EnsureVisible(iItem, 0);
2493
2494 /* all items */
2495 if (dwFlags & SVSI_DESELECTOTHERS)
2496 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2497
2498 /* this item */
2499 if (dwFlags & SVSI_SELECT)
2500 lvItem.state |= LVIS_SELECTED;
2501
2502 if (dwFlags & SVSI_FOCUSED)
2503 lvItem.stateMask |= LVIS_FOCUSED;
2504
2505 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2506
2507 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2508 m_ListView.EditLabel(iItem);
2509
2510 return S_OK;
2511 }
2512
2513 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
2514 {
2515 /* Reset the selection */
2516 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2517
2518 int lvIndex;
2519 for (UINT i = 0 ; i < m_cidl; i++)
2520 {
2521 lvIndex = LV_FindItemByPidl(apidl[i]);
2522 if (lvIndex != -1)
2523 {
2524 SelectItem(lvIndex, dwFlags);
2525 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2526 }
2527 }
2528
2529 return S_OK;
2530 }
2531
2532 /**********************************************************
2533 * IShellView2 implementation
2534 */
2535
2536 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
2537 {
2538 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2539 return E_NOTIMPL;
2540 }
2541
2542 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
2543 {
2544 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2545 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2546 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2547 }
2548
2549 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow3(IShellBrowser *psb, IShellView *psvPrevious, SV3CVW3_FLAGS view_flags, FOLDERFLAGS mask, FOLDERFLAGS flags, FOLDERVIEWMODE mode, const SHELLVIEWID *view_id, RECT *prcView, HWND *hwnd)
2550 {
2551 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2552
2553 *hwnd = NULL;
2554
2555 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2556 if (prcView != NULL)
2557 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2558
2559 /* Validate the Shell Browser */
2560 if (psb == NULL || m_hWnd)
2561 return E_UNEXPECTED;
2562
2563 if (view_flags != SV3CVW3_DEFAULT)
2564 FIXME("unsupported view flags 0x%08x\n", view_flags);
2565
2566 /* Set up the member variables */
2567 m_pShellBrowser = psb;
2568 m_FolderSettings.ViewMode = mode;
2569 m_FolderSettings.fFlags = mask & flags;
2570
2571 if (view_id)
2572 {
2573 if (IsEqualIID(*view_id, VID_LargeIcons))
2574 m_FolderSettings.ViewMode = FVM_ICON;
2575 else if (IsEqualIID(*view_id, VID_SmallIcons))
2576 m_FolderSettings.ViewMode = FVM_SMALLICON;
2577 else if (IsEqualIID(*view_id, VID_List))
2578 m_FolderSettings.ViewMode = FVM_LIST;
2579 else if (IsEqualIID(*view_id, VID_Details))
2580 m_FolderSettings.ViewMode = FVM_DETAILS;
2581 else if (IsEqualIID(*view_id, VID_Thumbnails))
2582 m_FolderSettings.ViewMode = FVM_THUMBNAIL;
2583 else if (IsEqualIID(*view_id, VID_Tile))
2584 m_FolderSettings.ViewMode = FVM_TILE;
2585 else if (IsEqualIID(*view_id, VID_ThumbStrip))
2586 m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
2587 else
2588 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2589 }
2590
2591 /* Get our parent window */
2592 m_pShellBrowser->GetWindow(&m_hWndParent);
2593
2594 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2595 m_pCommDlgBrowser = NULL;
2596 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2597 {
2598 TRACE("-- CommDlgBrowser\n");
2599 }
2600
2601 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
2602 if (m_hWnd == NULL)
2603 return E_FAIL;
2604
2605 *hwnd = m_hWnd;
2606
2607 CheckToolbar();
2608
2609 if (!*hwnd)
2610 return E_FAIL;
2611
2612 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, NULL);
2613
2614 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2615 UpdateWindow();
2616
2617 if (!m_hMenu)
2618 {
2619 m_hMenu = CreateMenu();
2620 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2621 TRACE("-- after fnInsertMenusSB\n");
2622 }
2623
2624 _MergeToolbar();
2625
2626 return S_OK;
2627 }
2628
2629 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
2630 {
2631 FIXME("(%p)->(%p) stub\n", this, new_pidl);
2632 return E_NOTIMPL;
2633 }
2634
2635 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
2636 {
2637 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2638 return E_NOTIMPL;
2639 }
2640
2641 /**********************************************************
2642 * IShellFolderView implementation
2643 */
2644 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2645 {
2646 FIXME("(%p)->(%ld) stub\n", this, sort);
2647 return E_NOTIMPL;
2648 }
2649
2650 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2651 {
2652 FIXME("(%p)->(%p) stub\n", this, sort);
2653 return E_NOTIMPL;
2654 }
2655
2656 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2657 {
2658 FIXME("(%p) stub\n", this);
2659 return E_NOTIMPL;
2660 }
2661
2662 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2663 {
2664 FIXME("(%p) stub\n", this);
2665 return E_NOTIMPL;
2666 }
2667
2668 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2669 {
2670 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2671 return E_NOTIMPL;
2672 }
2673
2674 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
2675 {
2676 TRACE("(%p)->(%p %d)\n", this, pidl, item);
2677 return Item(item, pidl);
2678 }
2679
2680 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
2681 {
2682
2683 TRACE("(%p)->(%p %p)\n", this, pidl, item);
2684
2685 if (pidl)
2686 {
2687 *item = LV_FindItemByPidl(ILFindLastID(pidl));
2688 m_ListView.DeleteItem(*item);
2689 }
2690 else
2691 {
2692 *item = 0;
2693 m_ListView.DeleteAllItems();
2694 }
2695
2696 return S_OK;
2697 }
2698
2699 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
2700 {
2701 TRACE("(%p)->(%p)\n", this, count);
2702 *count = m_ListView.GetItemCount();
2703 return S_OK;
2704 }
2705
2706 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
2707 {
2708 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
2709 return E_NOTIMPL;
2710 }
2711
2712 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
2713 {
2714 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
2715 return E_NOTIMPL;
2716 }
2717
2718 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
2719 {
2720 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2721 return E_NOTIMPL;
2722 }
2723
2724 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
2725 {
2726 TRACE("(%p)->(%d)\n", this, redraw);
2727 m_ListView.SetRedraw(redraw);
2728 return S_OK;
2729 }
2730
2731 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
2732 {
2733 FIXME("(%p)->(%p) stub\n", this, count);
2734 return E_NOTIMPL;
2735 }
2736
2737 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
2738 {
2739 TRACE("(%p)->(%p %p)\n", this, pidl, items);
2740
2741 *items = GetSelections();
2742
2743 if (*items)
2744 {
2745 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
2746 if (!*pidl)
2747 {
2748 return E_OUTOFMEMORY;
2749 }
2750
2751 /* it's documented that caller shouldn't PIDLs, only array itself */
2752 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
2753 }
2754
2755 return S_OK;
2756 }
2757
2758 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
2759 {
2760 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
2761 (m_pSourceDataObject.p))
2762 {
2763 return S_OK;
2764 }
2765
2766 return S_FALSE;
2767 }
2768
2769 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
2770 {
2771 if (!pt)
2772 return E_INVALIDARG;
2773
2774 *pt = m_ptFirstMousePos;
2775 return S_OK;
2776 }
2777
2778 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
2779 {
2780 FIXME("(%p)->(%p) stub\n", this, pt);
2781 return E_NOTIMPL;
2782 }
2783
2784 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
2785 {
2786 TRACE("(%p)->(%p)\n", this, obj);
2787 return E_NOTIMPL;
2788 }
2789
2790 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
2791 {
2792 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
2793 return E_NOTIMPL;
2794 }
2795
2796 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
2797 {
2798 FIXME("(%p)->(%p) stub\n", this, drop_target);
2799 return E_NOTIMPL;
2800 }
2801
2802 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
2803 {
2804 FIXME("(%p)->(%d) stub\n", this, move);
2805 return E_NOTIMPL;
2806 }
2807
2808 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
2809 {
2810 FIXME("(%p)->(%p) stub\n", this, obj);
2811 return E_NOTIMPL;
2812 }
2813
2814 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
2815 {
2816 FIXME("(%p)->(%p) stub\n", this, spacing);
2817 return E_NOTIMPL;
2818 }
2819
2820 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
2821 {
2822 if (old_cb)
2823 *old_cb = m_pShellFolderViewCB.Detach();
2824
2825 m_pShellFolderViewCB = new_cb;
2826 return S_OK;
2827 }
2828
2829 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
2830 {
2831 FIXME("(%p)->(%d) stub\n", this, flags);
2832 return E_NOTIMPL;
2833 }
2834
2835 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
2836 {
2837 TRACE("(%p)->(%p)\n", this, support);
2838 return S_OK;
2839 }
2840
2841 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
2842 {
2843 FIXME("(%p)->(%p) stub\n", this, disp);
2844 return E_NOTIMPL;
2845 }
2846
2847 /**********************************************************
2848 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2849 */
2850 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2851 {
2852 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2853 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2854
2855 if (!prgCmds)
2856 return E_INVALIDARG;
2857
2858 for (UINT i = 0; i < cCmds; i++)
2859 {
2860 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2861 prgCmds[i].cmdf = 0;
2862 }
2863
2864 return OLECMDERR_E_UNKNOWNGROUP;
2865 }
2866
2867 /**********************************************************
2868 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2869 *
2870 * nCmdID is the OLECMDID_* enumeration
2871 */
2872 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2873 {
2874 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2875 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2876
2877 if (!pguidCmdGroup)
2878 return OLECMDERR_E_UNKNOWNGROUP;
2879
2880 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
2881 {
2882 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
2883 {
2884 if (V_VT(pvaIn) != VT_INT_PTR)
2885 return OLECMDERR_E_NOTSUPPORTED;
2886
2887 TPMPARAMS params;
2888 params.cbSize = sizeof(params);
2889 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
2890
2891 if (m_hMenuViewModes)
2892 {
2893 /* Duplicate all but the last two items of the view modes menu */
2894 HMENU hmenuViewPopup = CreatePopupMenu();
2895 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
2896 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
2897 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
2898 CheckViewMode(hmenuViewPopup);
2899 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
2900 ::DestroyMenu(hmenuViewPopup);
2901 }
2902
2903 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
2904 V_VT(pvaOut) = VT_I4;
2905 V_I4(pvaOut) = 0x403;
2906 }
2907 }
2908
2909 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2910 (nCmdID == 0x29) &&
2911 (nCmdexecopt == 4) && pvaOut)
2912 return S_OK;
2913
2914 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2915 (nCmdID == 9) &&
2916 (nCmdexecopt == 0))
2917 return 1;
2918
2919 return OLECMDERR_E_UNKNOWNGROUP;
2920 }
2921
2922 /**********************************************************
2923 * ISVDropTarget implementation
2924 */
2925
2926 /******************************************************************************
2927 * drag_notify_subitem [Internal]
2928 *
2929 * Figure out the shellfolder object, which is currently under the mouse cursor
2930 * and notify it via the IDropTarget interface.
2931 */
2932
2933 #define SCROLLAREAWIDTH 20
2934
2935 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2936 {
2937 LONG lResult;
2938 HRESULT hr;
2939 RECT clientRect;
2940
2941 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
2942 reflects the key state after the user released the button, so we need
2943 to remember the last key state when the button was pressed */
2944 m_grfKeyState = grfKeyState;
2945
2946 /* Map from global to client coordinates and query the index of the listview-item, which is
2947 * currently under the mouse cursor. */
2948 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
2949 ScreenToClient(&htinfo.pt);
2950 lResult = m_ListView.HitTest(&htinfo);
2951
2952 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2953 ::GetClientRect(m_ListView, &clientRect);
2954 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2955 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2956 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2957 {
2958 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2959 if (m_cScrollDelay == 0)
2960 {
2961 /* Mouse did hover another 250 ms over the scroll-area */
2962 if (htinfo.pt.x < SCROLLAREAWIDTH)
2963 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
2964
2965 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2966 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
2967
2968 if (htinfo.pt.y < SCROLLAREAWIDTH)
2969 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
2970
2971 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2972 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
2973 }
2974 }
2975 else
2976 {
2977 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2978 }
2979
2980 m_ptLastMousePos = htinfo.pt;
2981
2982 /* We need to check if we drag the selection over itself */
2983 if (lResult != -1 && m_pSourceDataObject.p != NULL)
2984 {
2985 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
2986
2987 for (UINT i = 0; i < m_cidl; i++)
2988 {
2989 if (pidl == m_apidl[i])
2990 {
2991 /* The item that is being draged is hovering itself. */
2992 lResult = -1;
2993 break;
2994 }
2995 }
2996 }
2997
2998 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2999 if (m_pCurDropTarget && lResult == m_iDragOverItem)
3000 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3001
3002 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3003 if (m_pCurDropTarget)
3004 {
3005 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
3006 if (pidl)
3007 SelectItem(pidl, 0);
3008
3009 m_pCurDropTarget->DragLeave();
3010 m_pCurDropTarget.Release();
3011 }
3012
3013 m_iDragOverItem = lResult;
3014
3015 if (lResult == -1)
3016 {
3017 /* We are not above one of the listview's subitems. Bind to the parent folder's
3018 * DropTarget interface. */
3019 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3020 }
3021 else
3022 {
3023 /* Query the relative PIDL of the shellfolder object represented by the currently
3024 * dragged over listview-item ... */
3025 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3026
3027 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3028 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3029 }
3030
3031 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3032
3033 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3034 if (FAILED(hr))
3035 {
3036 *pdwEffect = DROPEFFECT_NONE;
3037 return hr;
3038 }
3039
3040 if (m_iDragOverItem != -1)
3041 {
3042 SelectItem(m_iDragOverItem, SVSI_SELECT);
3043 }
3044
3045 /* Notify the item just entered via DragEnter. */
3046 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3047 }
3048
3049 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3050 {
3051 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3052 m_pCurDataObject = pDataObject;
3053
3054 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3055 if (SUCCEEDED(hr))
3056 {
3057 POINT ptClient = {pt.x, pt.y};
3058 ScreenToClient(&ptClient);
3059 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3060 }
3061
3062 return hr;
3063 }
3064
3065 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3066 {
3067 POINT ptClient = {pt.x, pt.y};
3068 ScreenToClient(&ptClient);
3069 ImageList_DragMove(ptClient.x, ptClient.y);
3070 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3071 }
3072
3073 HRESULT WINAPI CDefView::DragLeave()
3074 {
3075 ImageList_DragLeave(m_hWnd);
3076
3077 if (m_pCurDropTarget)
3078 {
3079 m_pCurDropTarget->DragLeave();
3080 m_pCurDropTarget.Release();
3081 }
3082
3083 if (m_pCurDataObject != NULL)
3084 {
3085 m_pCurDataObject.Release();
3086 }
3087
3088 m_iDragOverItem = 0;
3089
3090 return S_OK;
3091 }
3092
3093 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3094 {
3095 ImageList_DragLeave(m_hWnd);
3096 ImageList_EndDrag();
3097
3098 if ((IsDropOnSource(NULL) == S_OK) &&
3099 (*pdwEffect & DROPEFFECT_MOVE) &&
3100 (m_grfKeyState & MK_LBUTTON))
3101 {
3102 if (m_pCurDropTarget)
3103 {
3104 m_pCurDropTarget->DragLeave();
3105 m_pCurDropTarget.Release();
3106 }
3107
3108 /* Restore the selection */
3109 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
3110 for (UINT i = 0 ; i < m_cidl; i++)
3111 SelectItem(m_apidl[i], SVSI_SELECT);
3112
3113 /* Reposition the items */
3114 int lvIndex = -1;
3115 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
3116 {
3117 POINT ptItem;
3118 if (m_ListView.GetItemPosition(lvIndex, &ptItem))
3119 {
3120 ptItem.x += pt.x - m_ptFirstMousePos.x;
3121 ptItem.y += pt.y - m_ptFirstMousePos.y;
3122 m_ListView.SetItemPosition(lvIndex, &ptItem);
3123 }
3124 }
3125 }
3126 else if (m_pCurDropTarget)
3127 {
3128 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3129 m_pCurDropTarget.Release();
3130 }
3131
3132 m_pCurDataObject.Release();
3133 m_iDragOverItem = 0;
3134 return S_OK;
3135 }
3136
3137 /**********************************************************
3138 * ISVDropSource implementation
3139 */
3140
3141 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3142 {
3143 TRACE("(%p)\n", this);
3144
3145 if (fEscapePressed)
3146 return DRAGDROP_S_CANCEL;
3147 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3148 return DRAGDROP_S_DROP;
3149 else
3150 return S_OK;
3151 }
3152
3153 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3154 {
3155 TRACE("(%p)\n", this);
3156
3157 return DRAGDROP_S_USEDEFAULTCURSORS;
3158 }
3159
3160 /**********************************************************
3161 * ISVViewObject implementation
3162 */
3163
3164 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)
3165 {
3166 FIXME("Stub: this=%p\n", this);
3167
3168 return E_NOTIMPL;
3169 }
3170
3171 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3172 {
3173 FIXME("Stub: this=%p\n", this);
3174
3175 return E_NOTIMPL;
3176 }
3177
3178 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3179 {
3180 FIXME("Stub: this=%p\n", this);
3181
3182 return E_NOTIMPL;
3183 }
3184
3185 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3186 {
3187 FIXME("Stub: this=%p\n", this);
3188
3189 return E_NOTIMPL;
3190 }
3191
3192 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3193 {
3194 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3195
3196 /* FIXME: we set the AdviseSink, but never use it to send any advice */
3197 m_pAdvSink = pAdvSink;
3198 m_dwAspects = aspects;
3199 m_dwAdvf = advf;
3200
3201 return S_OK;
3202 }
3203
3204 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3205 {
3206 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3207
3208 if (ppAdvSink)
3209 {
3210 *ppAdvSink = m_pAdvSink;
3211 m_pAdvSink.p->AddRef();
3212 }
3213
3214 if (pAspects)
3215 *pAspects = m_dwAspects;