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