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