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