Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / dll / win32 / shell32 / shlview.cpp
1 /*
2 * ShellView
3 *
4 * Copyright 1998,1999 <juergen.schmied@debitel.net>
5 *
6 * This is the view visualizing the data provided by the shellfolder.
7 * No direct access to data from pidls should be done from here.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 *
23 * FIXME: The order by part of the background context menu should be
24 * built according to the columns shown.
25 *
26 * FIXME: CheckToolbar: handle the "new folder" and "folder up" button
27 *
28 * FIXME: ShellView_FillList: consider sort orders
29 */
30
31 /*
32 TODO:
33 1. Load/Save the view state from/into the stream provided by the ShellBrowser.
34 2. Let the shell folder sort items.
35 3. Code to merge menus in the shellbrowser is incorrect.
36 4. Move the background context menu creation into shell view. It should store the
37 shell view HWND to send commands.
38 5. Send init, measure, and draw messages to context menu during tracking.
39 6. Shell view should do SetCommandTarget on internet toolbar.
40 7. When editing starts on item, set edit text to for editing value.
41 8. When shell view is called back for item info, let listview save the value.
42 9. Shell view should update status bar.
43 10. Fix shell view to handle view mode popup exec.
44 11. The background context menu should have a pidl just like foreground menus. This
45 causes crashes when dynamic handlers try to use the NULL pidl.
46 12. The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
47 annoying flashing of blue even on XP, and is not correct.
48 13. Reorder of columns doesn't work - might be bug in comctl32
49 */
50
51 #include "precomp.h"
52
53 #include <atlwin.h>
54
55 WINE_DEFAULT_DEBUG_CHANNEL(shell);
56
57 #undef SV_CLASS_NAME
58
59 static const WCHAR SV_CLASS_NAME[] = {'S', 'H', 'E', 'L', 'L', 'D', 'L', 'L', '_', 'D', 'e', 'f', 'V', 'i', 'e', 'w', 0};
60
61 typedef struct
62 { BOOL bIsAscending;
63 INT nHeaderID;
64 INT nLastHeaderID;
65 } LISTVIEW_SORT_INFO, *LPLISTVIEW_SORT_INFO;
66
67 #define SHV_CHANGE_NOTIFY WM_USER + 0x1111
68
69 class CDefView :
70 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
71 public CComObjectRootEx<CComMultiThreadModelNoCS>,
72 public IShellView,
73 public IFolderView,
74 public IOleCommandTarget,
75 public IDropTarget,
76 public IDropSource,
77 public IViewObject,
78 public IServiceProvider
79 {
80 private:
81 CComPtr<IShellFolder> m_pSFParent;
82 CComPtr<IShellFolder2> m_pSF2Parent;
83 CComPtr<IShellBrowser> m_pShellBrowser;
84 CComPtr<ICommDlgBrowser> m_pCommDlgBrowser;
85 HWND m_hWndList; /* ListView control */
86 HWND m_hWndParent;
87 FOLDERSETTINGS m_FolderSettings;
88 HMENU m_hMenu;
89 UINT m_uState;
90 UINT m_cidl;
91 LPITEMIDLIST *m_apidl;
92 LISTVIEW_SORT_INFO m_sortInfo;
93 ULONG m_hNotify; /* change notification handle */
94 HACCEL m_hAccel;
95 DWORD m_dwAspects;
96 DWORD m_dwAdvf;
97 CComPtr<IAdviseSink> m_pAdvSink;
98 // for drag and drop
99 CComPtr<IDropTarget> m_pCurDropTarget; /* The sub-item, which is currently dragged over */
100 CComPtr<IDataObject> m_pCurDataObject; /* The dragged data-object */
101 LONG m_iDragOverItem; /* Dragged over item's index, iff m_pCurDropTarget != NULL */
102 UINT m_cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
103 POINT m_ptLastMousePos; /* Mouse position at last DragOver call */
104 //
105 CComPtr<IContextMenu> m_pCM;
106 public:
107 CDefView();
108 ~CDefView();
109 HRESULT WINAPI Initialize(IShellFolder *shellFolder);
110 HRESULT IncludeObject(LPCITEMIDLIST pidl);
111 HRESULT OnDefaultCommand();
112 HRESULT OnStateChange(UINT uFlags);
113 void CheckToolbar();
114 void SetStyle(DWORD dwAdd, DWORD dwRemove);
115 BOOL CreateList();
116 void UpdateListColors();
117 BOOL InitList();
118 static INT CALLBACK CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
119 static INT CALLBACK ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
120 int LV_FindItemByPidl(LPCITEMIDLIST pidl);
121 BOOLEAN LV_AddItem(LPCITEMIDLIST pidl);
122 BOOLEAN LV_DeleteItem(LPCITEMIDLIST pidl);
123 BOOLEAN LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew);
124 static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg);
125 HRESULT FillList();
126 HMENU BuildFileMenu();
127 void MergeFileMenu(HMENU hSubMenu);
128 void MergeViewMenu(HMENU hSubMenu);
129 UINT GetSelections();
130 HRESULT OpenSelectedItems();
131 void OnDeactivate();
132 void DoActivate(UINT uState);
133 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
134 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
135
136 // *** IOleWindow methods ***
137 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
138 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
139
140 // *** IShellView methods ***
141 virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG *pmsg);
142 virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable);
143 virtual HRESULT STDMETHODCALLTYPE UIActivate(UINT uState);
144 virtual HRESULT STDMETHODCALLTYPE Refresh();
145 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
146 virtual HRESULT STDMETHODCALLTYPE DestroyViewWindow();
147 virtual HRESULT STDMETHODCALLTYPE GetCurrentInfo(LPFOLDERSETTINGS pfs);
148 virtual HRESULT STDMETHODCALLTYPE AddPropertySheetPages(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam);
149 virtual HRESULT STDMETHODCALLTYPE SaveViewState();
150 virtual HRESULT STDMETHODCALLTYPE SelectItem(LPCITEMIDLIST pidlItem, SVSIF uFlags);
151 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
152
153 // *** IFolderView methods ***
154 virtual HRESULT STDMETHODCALLTYPE GetCurrentViewMode(UINT *pViewMode);
155 virtual HRESULT STDMETHODCALLTYPE SetCurrentViewMode(UINT ViewMode);
156 virtual HRESULT STDMETHODCALLTYPE GetFolder(REFIID riid, void **ppv);
157 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, LPITEMIDLIST *ppidl);
158 virtual HRESULT STDMETHODCALLTYPE ItemCount(UINT uFlags, int *pcItems);
159 virtual HRESULT STDMETHODCALLTYPE Items(UINT uFlags, REFIID riid, void **ppv);
160 virtual HRESULT STDMETHODCALLTYPE GetSelectionMarkedItem(int *piItem);
161 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
162 virtual HRESULT STDMETHODCALLTYPE GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt);
163 virtual HRESULT STDMETHODCALLTYPE GetSpacing(POINT *ppt);
164 virtual HRESULT STDMETHODCALLTYPE GetDefaultSpacing(POINT *ppt);
165 virtual HRESULT STDMETHODCALLTYPE GetAutoArrange();
166 virtual HRESULT STDMETHODCALLTYPE SelectItem(int iItem, DWORD dwFlags);
167 virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags);
168
169 // *** IOleCommandTarget methods ***
170 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
171 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
172
173 // *** IDropTarget methods ***
174 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
175 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
176 virtual HRESULT STDMETHODCALLTYPE DragLeave();
177 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
178
179 // *** IDropSource methods ***
180 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
181 virtual HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
182
183 // *** IViewObject methods ***
184 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
185 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
186 BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
187 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
188 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
189 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
190 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
191 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
192 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
193
194 // *** IServiceProvider methods ***
195 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
196
197 // message handlers
198 LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
199 LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
200 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
201 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
202 LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
203 LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
204 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
205 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
206 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
207 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
208 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
209 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
210 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
211 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
212 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
213 LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
214 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
215
216 static ATL::CWndClassInfo& GetWndClassInfo()
217 {
218 static ATL::CWndClassInfo wc =
219 {
220 { sizeof(WNDCLASSEX), 0, StartWindowProc,
221 0, 0, NULL, NULL,
222 LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_BACKGROUND + 1), NULL, SV_CLASS_NAME, NULL
223 },
224 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
225 };
226 return wc;
227 }
228
229 virtual WNDPROC GetWindowProc()
230 {
231 return WindowProc;
232 }
233
234 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
235 {
236 CDefView *pThis;
237 LRESULT result;
238
239 // must hold a reference during message handling
240 pThis = reinterpret_cast<CDefView *>(hWnd);
241 pThis->AddRef();
242 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
243 pThis->Release();
244 return result;
245 }
246
247 BEGIN_MSG_MAP(CDefView)
248 MESSAGE_HANDLER(WM_SIZE, OnSize)
249 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
250 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
251 MESSAGE_HANDLER(WM_CREATE, OnCreate)
252 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
253 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
254 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
255 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
256 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
257 MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem)
258 MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem)
259 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
260 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
261 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
262 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
263 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
264 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser)
265 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
266 END_MSG_MAP()
267
268 BEGIN_COM_MAP(CDefView)
269 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
270 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
271 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
272 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
273 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
274 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
275 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject)
276 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
277 END_COM_MAP()
278 };
279
280 /* ListView Header ID's */
281 #define LISTVIEW_COLUMN_NAME 0
282 #define LISTVIEW_COLUMN_SIZE 1
283 #define LISTVIEW_COLUMN_TYPE 2
284 #define LISTVIEW_COLUMN_TIME 3
285 #define LISTVIEW_COLUMN_ATTRIB 4
286
287 /*menu items */
288 #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
289 #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
290 #define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
291
292 #define ID_LISTVIEW 1
293
294 /*windowsx.h */
295 #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
296 #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
297 #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
298
299 /*
300 Items merged into the toolbar and the filemenu
301 */
302 typedef struct
303 { int idCommand;
304 int iImage;
305 int idButtonString;
306 int idMenuString;
307 BYTE bState;
308 BYTE bStyle;
309 } MYTOOLINFO, *LPMYTOOLINFO;
310
311 static const MYTOOLINFO Tools[] =
312 {
313 { FCIDM_SHVIEW_BIGICON, 0, 0, IDS_VIEW_LARGE, TBSTATE_ENABLED, BTNS_BUTTON },
314 { FCIDM_SHVIEW_SMALLICON, 0, 0, IDS_VIEW_SMALL, TBSTATE_ENABLED, BTNS_BUTTON },
315 { FCIDM_SHVIEW_LISTVIEW, 0, 0, IDS_VIEW_LIST, TBSTATE_ENABLED, BTNS_BUTTON },
316 { FCIDM_SHVIEW_REPORTVIEW, 0, 0, IDS_VIEW_DETAILS, TBSTATE_ENABLED, BTNS_BUTTON },
317 { -1, 0, 0, 0, 0, 0}
318 };
319
320 typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
321
322 CDefView::CDefView()
323 {
324 m_hWndList = NULL;
325 m_hWndParent = NULL;
326 m_FolderSettings.fFlags = 0;
327 m_FolderSettings.ViewMode = 0;
328 m_hMenu = NULL;
329 m_uState = 0;
330 m_cidl = 0;
331 m_apidl = NULL;
332 m_sortInfo.bIsAscending = FALSE;
333 m_sortInfo.nHeaderID = 0;
334 m_sortInfo.nLastHeaderID = 0;
335 m_hNotify = 0;
336 m_hAccel = NULL;
337 m_dwAspects = 0;
338 m_dwAdvf = 0;
339 m_iDragOverItem = 0;
340 m_cScrollDelay = 0;
341 m_ptLastMousePos.x = 0;
342 m_ptLastMousePos.y = 0;
343 }
344
345 CDefView::~CDefView()
346 {
347 TRACE(" destroying IShellView(%p)\n", this);
348
349 SHFree(m_apidl);
350 }
351
352 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
353 {
354 m_pSFParent = shellFolder;
355 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &m_pSF2Parent));
356
357 return S_OK;
358 }
359
360 /**********************************************************
361 *
362 * ##### helperfunctions for communication with ICommDlgBrowser #####
363 */
364 HRESULT CDefView::IncludeObject(LPCITEMIDLIST pidl)
365 {
366 HRESULT ret = S_OK;
367
368 if (m_pCommDlgBrowser.p != NULL)
369 {
370 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
371 ret = m_pCommDlgBrowser->IncludeObject((IShellView *)this, pidl);
372 TRACE("--0x%08x\n", ret);
373 }
374
375 return ret;
376 }
377
378 HRESULT CDefView::OnDefaultCommand()
379 {
380 HRESULT ret = S_FALSE;
381
382 if (m_pCommDlgBrowser.p != NULL)
383 {
384 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
385 ret = m_pCommDlgBrowser->OnDefaultCommand((IShellView *)this);
386 TRACE("-- returns %08x\n", ret);
387 }
388
389 return ret;
390 }
391
392 HRESULT CDefView::OnStateChange(UINT uFlags)
393 {
394 HRESULT ret = S_FALSE;
395
396 if (m_pCommDlgBrowser.p != NULL)
397 {
398 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
399 ret = m_pCommDlgBrowser->OnStateChange((IShellView *)this, uFlags);
400 TRACE("--\n");
401 }
402
403 return ret;
404 }
405 /**********************************************************
406 * set the toolbar of the filedialog buttons
407 *
408 * - activates the buttons from the shellbrowser according to
409 * the view state
410 */
411 void CDefView::CheckToolbar()
412 {
413 LRESULT result;
414
415 TRACE("\n");
416
417 if (m_pCommDlgBrowser != NULL)
418 {
419 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
420 FCIDM_TB_SMALLICON, (m_FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result);
421 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
422 FCIDM_TB_REPORTVIEW, (m_FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result);
423 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
424 FCIDM_TB_SMALLICON, TRUE, &result);
425 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
426 FCIDM_TB_REPORTVIEW, TRUE, &result);
427 }
428 }
429
430 /**********************************************************
431 *
432 * ##### helperfunctions for initializing the view #####
433 */
434 /**********************************************************
435 * change the style of the listview control
436 */
437 void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
438 {
439 DWORD tmpstyle;
440
441 TRACE("(%p)\n", this);
442
443 tmpstyle = ::GetWindowLongPtrW(m_hWndList, GWL_STYLE);
444 ::SetWindowLongPtrW(m_hWndList, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
445 }
446
447 /**********************************************************
448 * ShellView_CreateList()
449 *
450 * - creates the list view window
451 */
452 BOOL CDefView::CreateList()
453 { DWORD dwStyle, dwExStyle;
454
455 TRACE("%p\n", this);
456
457 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
458 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
459 dwExStyle = WS_EX_CLIENTEDGE;
460
461 if (m_FolderSettings.fFlags & FWF_DESKTOP)
462 dwStyle |= LVS_ALIGNLEFT;
463 else
464 dwStyle |= LVS_ALIGNTOP;
465
466 switch (m_FolderSettings.ViewMode)
467 {
468 case FVM_ICON:
469 dwStyle |= LVS_ICON;
470 break;
471
472 case FVM_DETAILS:
473 dwStyle |= LVS_REPORT;
474 break;
475
476 case FVM_SMALLICON:
477 dwStyle |= LVS_SMALLICON;
478 break;
479
480 case FVM_LIST:
481 dwStyle |= LVS_LIST;
482 break;
483
484 default:
485 dwStyle |= LVS_LIST;
486 break;
487 }
488
489 if (m_FolderSettings.fFlags & FWF_AUTOARRANGE)
490 dwStyle |= LVS_AUTOARRANGE;
491
492 if (m_FolderSettings.fFlags & FWF_DESKTOP)
493 m_FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
494
495 if (m_FolderSettings.fFlags & FWF_SINGLESEL)
496 dwStyle |= LVS_SINGLESEL;
497
498 if (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE)
499 dwExStyle &= ~WS_EX_CLIENTEDGE;
500
501 m_hWndList = CreateWindowExW( dwExStyle,
502 WC_LISTVIEWW,
503 NULL,
504 dwStyle,
505 0, 0, 0, 0,
506 m_hWnd,
507 (HMENU)ID_LISTVIEW,
508 shell32_hInstance,
509 NULL);
510
511 if (!m_hWndList)
512 return FALSE;
513
514 m_sortInfo.bIsAscending = TRUE;
515 m_sortInfo.nHeaderID = -1;
516 m_sortInfo.nLastHeaderID = -1;
517
518 UpdateListColors();
519
520 /* UpdateShellSettings(); */
521 return TRUE;
522 }
523
524 void CDefView::UpdateListColors()
525 {
526 if (m_FolderSettings.fFlags & FWF_DESKTOP)
527 {
528 /* Check if drop shadows option is enabled */
529 BOOL bDropShadow = FALSE;
530 DWORD cbDropShadow = sizeof(bDropShadow);
531 WCHAR wszBuf[16] = L"";
532
533 RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
534 L"ListviewShadow", RRF_RT_DWORD, NULL, &bDropShadow, &cbDropShadow);
535 if (bDropShadow && SystemParametersInfoW(SPI_GETDESKWALLPAPER, _countof(wszBuf), wszBuf, 0) && wszBuf[0])
536 {
537 SendMessageW(m_hWndList, LVM_SETTEXTBKCOLOR, 0, CLR_NONE);
538 SendMessageW(m_hWndList, LVM_SETBKCOLOR, 0, CLR_NONE);
539 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
540 SendMessageW(m_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
541 }
542 else
543 {
544 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP);
545 SendMessageW(m_hWndList, LVM_SETTEXTBKCOLOR, 0, crDesktop);
546 SendMessageW(m_hWndList, LVM_SETBKCOLOR, 0, crDesktop);
547 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
548 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(0, 0, 0));
549 else
550 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
551 SendMessageW(m_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTSHADOWTEXT, 0);
552 }
553 }
554 }
555
556 /**********************************************************
557 * ShellView_InitList()
558 *
559 * - adds all needed columns to the shellview
560 */
561 BOOL CDefView::InitList()
562 {
563 LVCOLUMNW lvColumn;
564 SHELLDETAILS sd;
565 WCHAR szTemp[50];
566
567 TRACE("%p\n", this);
568
569 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
570
571 lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
572 lvColumn.pszText = szTemp;
573
574 if (m_pSF2Parent)
575 {
576 for (int i = 0; 1; i++)
577 {
578 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
579 break;
580
581 lvColumn.fmt = sd.fmt;
582 lvColumn.cx = sd.cxChar * 8; /* chars->pixel */
583 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
584 SendMessageW(m_hWndList, LVM_INSERTCOLUMNW, i, (LPARAM) &lvColumn);
585 }
586 }
587 else
588 {
589 FIXME("no SF2\n");
590 }
591
592 SendMessageW(m_hWndList, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)ShellSmallIconList);
593 SendMessageW(m_hWndList, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)ShellBigIconList);
594
595 return TRUE;
596 }
597
598 /**********************************************************
599 * ShellView_CompareItems()
600 *
601 * NOTES
602 * internal, CALLBACK for DSA_Sort
603 */
604 INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
605 {
606 int ret;
607 TRACE("pidl1=%p pidl2=%p lpsf=%p\n", lParam1, lParam2, (LPVOID) lpData);
608
609 if (!lpData)
610 return 0;
611
612 ret = (SHORT)SCODE_CODE(((IShellFolder *)lpData)->CompareIDs(0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2));
613 TRACE("ret=%i\n", ret);
614
615 return ret;
616 }
617
618 /*************************************************************************
619 * ShellView_ListViewCompareItems
620 *
621 * Compare Function for the Listview (FileOpen Dialog)
622 *
623 * PARAMS
624 * lParam1 [I] the first ItemIdList to compare with
625 * lParam2 [I] the second ItemIdList to compare with
626 * lpData [I] The column ID for the header Ctrl to process
627 *
628 * RETURNS
629 * A negative value if the first item should precede the second,
630 * a positive value if the first item should follow the second,
631 * or zero if the two items are equivalent
632 *
633 * NOTES
634 * FIXME: function does what ShellView_CompareItems is supposed to do.
635 * unify it and figure out how to use the undocumented first parameter
636 * of IShellFolder_CompareIDs to do the job this function does and
637 * move this code to IShellFolder.
638 * make LISTVIEW_SORT_INFO obsolete
639 * the way this function works is only usable if we had only
640 * filesystemfolders (25/10/99 jsch)
641 */
642 INT CALLBACK CDefView::ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
643 {
644 INT nDiff = 0;
645 FILETIME fd1, fd2;
646 char strName1[MAX_PATH], strName2[MAX_PATH];
647 BOOL bIsFolder1, bIsFolder2, bIsBothFolder;
648 LPITEMIDLIST pItemIdList1 = (LPITEMIDLIST) lParam1;
649 LPITEMIDLIST pItemIdList2 = (LPITEMIDLIST) lParam2;
650 LISTVIEW_SORT_INFO *pSortInfo = (LPLISTVIEW_SORT_INFO) lpData;
651
652
653 bIsFolder1 = _ILIsFolder(pItemIdList1);
654 bIsFolder2 = _ILIsFolder(pItemIdList2);
655 bIsBothFolder = bIsFolder1 && bIsFolder2;
656
657 /* When sorting between a File and a Folder, the Folder gets sorted first */
658 if ( (bIsFolder1 || bIsFolder2) && !bIsBothFolder)
659 {
660 nDiff = bIsFolder1 ? -1 : 1;
661 }
662 else
663 {
664 /* Sort by Time: Folders or Files can be sorted */
665
666 if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TIME)
667 {
668 _ILGetFileDateTime(pItemIdList1, &fd1);
669 _ILGetFileDateTime(pItemIdList2, &fd2);
670 nDiff = CompareFileTime(&fd2, &fd1);
671 }
672 /* Sort by Attribute: Folder or Files can be sorted */
673 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_ATTRIB)
674 {
675 _ILGetFileAttributes(pItemIdList1, strName1, MAX_PATH);
676 _ILGetFileAttributes(pItemIdList2, strName2, MAX_PATH);
677 nDiff = lstrcmpiA(strName1, strName2);
678 }
679 /* Sort by FileName: Folder or Files can be sorted */
680 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_NAME || bIsBothFolder)
681 {
682 /* Sort by Text */
683 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
684 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
685 nDiff = lstrcmpiA(strName1, strName2);
686 }
687 /* Sort by File Size, Only valid for Files */
688 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_SIZE)
689 {
690 nDiff = (INT)(_ILGetFileSize(pItemIdList1, NULL, 0) - _ILGetFileSize(pItemIdList2, NULL, 0));
691 }
692 /* Sort by File Type, Only valid for Files */
693 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_TYPE)
694 {
695 /* Sort by Type */
696 _ILGetFileType(pItemIdList1, strName1, MAX_PATH);
697 _ILGetFileType(pItemIdList2, strName2, MAX_PATH);
698 nDiff = lstrcmpiA(strName1, strName2);
699 }
700 }
701 /* If the Date, FileSize, FileType, Attrib was the same, sort by FileName */
702
703 if (nDiff == 0)
704 {
705 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
706 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
707 nDiff = lstrcmpiA(strName1, strName2);
708 }
709
710 if (!pSortInfo->bIsAscending)
711 {
712 nDiff = -nDiff;
713 }
714
715 return nDiff;
716 }
717
718 /**********************************************************
719 * LV_FindItemByPidl()
720 */
721 int CDefView::LV_FindItemByPidl(LPCITEMIDLIST pidl)
722 {
723 LVITEMW lvItem;
724 lvItem.iSubItem = 0;
725 lvItem.mask = LVIF_PARAM;
726
727 for (lvItem.iItem = 0;
728 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
729 lvItem.iItem++)
730 {
731 LPITEMIDLIST currentpidl = (LPITEMIDLIST) lvItem.lParam;
732 HRESULT hr = m_pSFParent->CompareIDs(0, pidl, currentpidl);
733
734 if (SUCCEEDED(hr) && !HRESULT_CODE(hr))
735 {
736 return lvItem.iItem;
737 }
738 }
739 return -1;
740 }
741
742 /**********************************************************
743 * LV_AddItem()
744 */
745 BOOLEAN CDefView::LV_AddItem(LPCITEMIDLIST pidl)
746 {
747 LVITEMW lvItem;
748
749 TRACE("(%p)(pidl=%p)\n", this, pidl);
750
751 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
752 lvItem.iItem = ListView_GetItemCount(m_hWndList); /*add the item to the end of the list*/
753 lvItem.iSubItem = 0;
754 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidl)); /*set the item's data*/
755 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
756 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
757
758 if (SendMessageW(m_hWndList, LVM_INSERTITEMW, 0, (LPARAM)&lvItem) == -1)
759 return FALSE;
760 else
761 return TRUE;
762 }
763
764 /**********************************************************
765 * LV_DeleteItem()
766 */
767 BOOLEAN CDefView::LV_DeleteItem(LPCITEMIDLIST pidl)
768 {
769 int nIndex;
770
771 TRACE("(%p)(pidl=%p)\n", this, pidl);
772
773 nIndex = LV_FindItemByPidl(ILFindLastID(pidl));
774
775 return (-1 == ListView_DeleteItem(m_hWndList, nIndex)) ? FALSE : TRUE;
776 }
777
778 /**********************************************************
779 * LV_RenameItem()
780 */
781 BOOLEAN CDefView::LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew)
782 {
783 int nItem;
784 LVITEMW lvItem;
785
786 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
787
788 nItem = LV_FindItemByPidl(ILFindLastID(pidlOld));
789
790 if ( -1 != nItem )
791 {
792 lvItem.mask = LVIF_PARAM; /* only the pidl */
793 lvItem.iItem = nItem;
794 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
795
796 SHFree((LPITEMIDLIST)lvItem.lParam);
797 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
798 lvItem.iItem = nItem;
799 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidlNew)); /* set the item's data */
800 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
801 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
802 SendMessageW(m_hWndList, LVM_UPDATE, nItem, 0);
803 return TRUE; /* FIXME: better handling */
804 }
805
806 return FALSE;
807 }
808
809 /**********************************************************
810 * ShellView_FillList()
811 *
812 * - gets the objectlist from the shellfolder
813 * - sorts the list
814 * - fills the list into the view
815 */
816 INT CALLBACK CDefView::fill_list( LPVOID ptr, LPVOID arg )
817 {
818 LPITEMIDLIST pidl = (LPITEMIDLIST)ptr;
819 CDefView *pThis = (CDefView *)arg;
820 /* in a commdlg This works as a filemask*/
821 if (pThis->IncludeObject(pidl) == S_OK)
822 pThis->LV_AddItem(pidl);
823
824 SHFree(pidl);
825 return TRUE;
826 }
827
828 HRESULT CDefView::FillList()
829 {
830 LPENUMIDLIST pEnumIDList;
831 LPITEMIDLIST pidl;
832 DWORD dwFetched;
833 HRESULT hRes;
834 HDPA hdpa;
835
836 TRACE("%p\n", this);
837
838 /* get the itemlist from the shfolder*/
839 hRes = m_pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
840 if (hRes != S_OK)
841 {
842 if (hRes == S_FALSE)
843 return(NOERROR);
844 return(hRes);
845 }
846
847 /* create a pointer array */
848 hdpa = DPA_Create(16);
849 if (!hdpa)
850 {
851 return(E_OUTOFMEMORY);
852 }
853
854 /* copy the items into the array*/
855 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
856 {
857 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
858 {
859 SHFree(pidl);
860 }
861 }
862
863 /* sort the array */
864 DPA_Sort(hdpa, CompareItems, (LPARAM)m_pSFParent.p);
865
866 /*turn the listview's redrawing off*/
867 SendMessageA(m_hWndList, WM_SETREDRAW, FALSE, 0);
868
869 DPA_DestroyCallback( hdpa, fill_list, (void *)this);
870
871 /*turn the listview's redrawing back on and force it to draw*/
872 SendMessageA(m_hWndList, WM_SETREDRAW, TRUE, 0);
873
874 pEnumIDList->Release(); /* destroy the list*/
875
876 return S_OK;
877 }
878
879 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
880 {
881 ::UpdateWindow(m_hWndList);
882 bHandled = FALSE;
883 return 0;
884 }
885
886 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
887 {
888 return SendMessageW(m_hWndList, uMsg, 0, 0);
889 }
890
891 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
892 {
893 RevokeDragDrop(m_hWnd);
894 SHChangeNotifyDeregister(m_hNotify);
895 bHandled = FALSE;
896 return 0;
897 }
898
899 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
900 {
901 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
902 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
903
904 bHandled = FALSE;
905 return 0;
906 }
907
908 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
909 {
910 /* Update desktop labels color */
911 UpdateListColors();
912
913 /* Forward WM_SYSCOLORCHANGE to common controls */
914 return SendMessageW(m_hWndList, uMsg, 0, 0);
915 }
916
917 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
918 {
919 return (LRESULT)m_pShellBrowser.p;
920 }
921
922 /**********************************************************
923 * ShellView_OnCreate()
924 */
925 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
926 {
927 CComPtr<IDropTarget> pdt;
928 SHChangeNotifyEntry ntreg;
929 CComPtr<IPersistFolder2> ppf2;
930
931 TRACE("%p\n", this);
932
933 if(CreateList())
934 {
935 if(InitList())
936 {
937 FillList();
938 }
939 }
940
941 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
942 {
943 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
944 ERR("Registering Drag Drop Failed");
945 }
946
947 /* register for receiving notifications */
948 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
949 if (ppf2)
950 {
951 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
952 ntreg.fRecursive = TRUE;
953 m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
954 SHFree((LPITEMIDLIST)ntreg.pidl);
955 }
956
957 m_hAccel = LoadAcceleratorsA(shell32_hInstance, MAKEINTRESOURCEA( IDA_SHELLVIEW));
958
959 return S_OK;
960 }
961
962 /**********************************************************
963 * #### Handling of the menus ####
964 */
965
966 /**********************************************************
967 * ShellView_BuildFileMenu()
968 */
969 HMENU CDefView::BuildFileMenu()
970 { WCHAR szText[MAX_PATH];
971 MENUITEMINFOW mii;
972 int nTools, i;
973 HMENU hSubMenu;
974
975 TRACE("(%p)\n", this);
976
977 hSubMenu = CreatePopupMenu();
978 if (hSubMenu)
979 {
980 /*get the number of items in our global array*/
981 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++) {}
982
983 /*add the menu items*/
984 for(i = 0; i < nTools; i++)
985 {
986 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
987
988 ZeroMemory(&mii, sizeof(mii));
989 mii.cbSize = sizeof(mii);
990 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
991
992 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
993 {
994 mii.fType = MFT_STRING;
995 mii.fState = MFS_ENABLED;
996 mii.dwTypeData = szText;
997 mii.wID = Tools[i].idCommand;
998 }
999 else
1000 {
1001 mii.fType = MFT_SEPARATOR;
1002 }
1003 /* tack This item onto the end of the menu */
1004 InsertMenuItemW(hSubMenu, (UINT) - 1, TRUE, &mii);
1005 }
1006 }
1007
1008 TRACE("-- return (menu=%p)\n", hSubMenu);
1009 return hSubMenu;
1010 }
1011
1012 /**********************************************************
1013 * ShellView_MergeFileMenu()
1014 */
1015 void CDefView::MergeFileMenu(HMENU hSubMenu)
1016 {
1017 TRACE("(%p)->(submenu=%p) stub\n", this, hSubMenu);
1018
1019 if (hSubMenu)
1020 { /*insert This item at the beginning of the menu */
1021 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1022 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
1023 }
1024
1025 TRACE("--\n");
1026 }
1027
1028 /**********************************************************
1029 * ShellView_MergeViewMenu()
1030 */
1031 void CDefView::MergeViewMenu(HMENU hSubMenu)
1032 {
1033 TRACE("(%p)->(submenu=%p)\n", this, hSubMenu);
1034
1035 if (hSubMenu)
1036 {
1037 /*add a separator at the correct position in the menu*/
1038 MENUITEMINFOW mii;
1039 static WCHAR view[] = L"View";
1040
1041 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1042
1043 ZeroMemory(&mii, sizeof(mii));
1044 mii.cbSize = sizeof(mii);
1045 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
1046 mii.fType = MFT_STRING;
1047 mii.dwTypeData = view;
1048 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
1049 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
1050 }
1051 }
1052
1053 /**********************************************************
1054 * ShellView_GetSelections()
1055 *
1056 * - fills the m_apidl list with the selected objects
1057 *
1058 * RETURNS
1059 * number of selected items
1060 */
1061 UINT CDefView::GetSelections()
1062 {
1063 LVITEMW lvItem;
1064 UINT i = 0;
1065
1066 SHFree(m_apidl);
1067
1068 m_cidl = ListView_GetSelectedCount(m_hWndList);
1069 m_apidl = (LPITEMIDLIST*)SHAlloc(m_cidl * sizeof(LPITEMIDLIST));
1070
1071 TRACE("selected=%i\n", m_cidl);
1072
1073 if (m_apidl)
1074 {
1075 TRACE("-- Items selected =%u\n", m_cidl);
1076
1077 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1078 lvItem.stateMask = LVIS_SELECTED;
1079 lvItem.iItem = 0;
1080 lvItem.iSubItem = 0;
1081 lvItem.state = 0;
1082
1083 while(SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < m_cidl))
1084 {
1085 if(lvItem.state & LVIS_SELECTED)
1086 {
1087 m_apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1088 i++;
1089 if (i == m_cidl)
1090 break;
1091 TRACE("-- selected Item found\n");
1092 }
1093 lvItem.iItem++;
1094 }
1095 }
1096
1097 return m_cidl;
1098 }
1099
1100 /**********************************************************
1101 * ShellView_OpenSelectedItems()
1102 */
1103 HRESULT CDefView::OpenSelectedItems()
1104 {
1105 HMENU hMenu;
1106 CMINVOKECOMMANDINFO cmi;
1107 UINT uCommand;
1108 HRESULT hResult;
1109
1110 m_cidl = ListView_GetSelectedCount(m_hWndList);
1111 if (m_cidl == 0)
1112 return S_OK;
1113
1114 hResult = OnDefaultCommand();
1115 if (hResult == S_OK)
1116 return hResult;
1117
1118 hMenu = CreatePopupMenu();
1119 if (!hMenu)
1120 return E_FAIL;
1121
1122 hResult = GetItemObject( SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1123 if (FAILED(hResult))
1124 goto cleanup;
1125
1126 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1127 //if (FAILED( hResult))
1128 // goto cleanup;
1129
1130 hResult = m_pCM->QueryContextMenu(hMenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1131 if (FAILED(hResult))
1132 goto cleanup;
1133
1134 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1135 if (uCommand == (UINT)-1)
1136 {
1137 hResult = E_FAIL;
1138 goto cleanup;
1139 }
1140
1141 ZeroMemory(&cmi, sizeof(cmi));
1142 cmi.cbSize = sizeof(cmi);
1143 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1144 cmi.hwnd = m_hWnd;
1145
1146 hResult = m_pCM->InvokeCommand(&cmi);
1147
1148 cleanup:
1149
1150 if (hMenu)
1151 DestroyMenu(hMenu);
1152
1153 if (m_pCM)
1154 {
1155 IUnknown_SetSite(m_pCM, NULL);
1156 m_pCM.Release();
1157 }
1158
1159 return hResult;
1160 }
1161
1162 /**********************************************************
1163 * ShellView_DoContextMenu()
1164 */
1165 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1166 {
1167 WORD x;
1168 WORD y;
1169 UINT uCommand;
1170 HMENU hMenu;
1171 CMINVOKECOMMANDINFO cmi;
1172 HRESULT hResult;
1173
1174 // for some reason I haven't figured out, we sometimes recurse into this method
1175 if (m_pCM != NULL)
1176 return 0;
1177
1178 x = LOWORD(lParam);
1179 y = HIWORD(lParam);
1180
1181 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1182
1183 hMenu = CreatePopupMenu();
1184 if (!hMenu)
1185 return E_FAIL;
1186
1187 m_cidl = ListView_GetSelectedCount(m_hWndList);
1188
1189 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1190 if (FAILED( hResult))
1191 goto cleanup;
1192
1193 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1194 //if (FAILED( hResult))
1195 // goto cleanup;
1196
1197 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1198 if (FAILED( hResult))
1199 goto cleanup;
1200
1201 if (m_FolderSettings.fFlags & FWF_DESKTOP)
1202 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1203
1204 uCommand = TrackPopupMenu(hMenu,
1205 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1206 x, y, 0, m_hWnd, NULL);
1207 if (uCommand == 0)
1208 goto cleanup;
1209
1210 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1211 goto cleanup;
1212
1213 ZeroMemory(&cmi, sizeof(cmi));
1214 cmi.cbSize = sizeof(cmi);
1215 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1216 cmi.hwnd = m_hWnd;
1217 m_pCM->InvokeCommand(&cmi);
1218
1219 cleanup:
1220
1221 if (m_pCM)
1222 {
1223 IUnknown_SetSite(m_pCM, NULL);
1224 m_pCM.Release();
1225 }
1226
1227 if (hMenu)
1228 DestroyMenu(hMenu);
1229
1230 return 0;
1231 }
1232
1233 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1234 {
1235 HRESULT hResult;
1236 CMINVOKECOMMANDINFO cmi;
1237 HMENU hMenu;
1238
1239 hMenu = CreatePopupMenu();
1240 if (!hMenu)
1241 return 0;
1242
1243 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1244 if (FAILED( hResult))
1245 goto cleanup;
1246
1247 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1248 //if (FAILED( hResult))
1249 // goto cleanup;
1250
1251 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1252 if (FAILED( hResult))
1253 goto cleanup;
1254
1255 ZeroMemory(&cmi, sizeof(cmi));
1256 cmi.cbSize = sizeof(cmi);
1257 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1258 cmi.hwnd = m_hWnd;
1259 m_pCM->InvokeCommand(&cmi);
1260
1261 cleanup:
1262
1263 if (m_pCM)
1264 {
1265 IUnknown_SetSite(m_pCM, NULL);
1266 m_pCM.Release();
1267 }
1268
1269 if (hMenu)
1270 DestroyMenu(hMenu);
1271
1272 return 0;
1273 }
1274
1275 /**********************************************************
1276 * ##### message handling #####
1277 */
1278
1279 /**********************************************************
1280 * ShellView_OnSize()
1281 */
1282 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1283 {
1284 WORD wWidth;
1285 WORD wHeight;
1286
1287 wWidth = LOWORD(lParam);
1288 wHeight = HIWORD(lParam);
1289
1290 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1291
1292 /*resize the ListView to fit our window*/
1293 if (m_hWndList)
1294 {
1295 ::MoveWindow(m_hWndList, 0, 0, wWidth, wHeight, TRUE);
1296 }
1297
1298 return 0;
1299 }
1300
1301 /**********************************************************
1302 * ShellView_OnDeactivate()
1303 *
1304 * NOTES
1305 * internal
1306 */
1307 void CDefView::OnDeactivate()
1308 {
1309 TRACE("%p\n", this);
1310
1311 if (m_uState != SVUIA_DEACTIVATE)
1312 {
1313 if (m_hMenu)
1314 {
1315 m_pShellBrowser->SetMenuSB(0, 0, 0);
1316 m_pShellBrowser->RemoveMenusSB(m_hMenu);
1317 DestroyMenu(m_hMenu);
1318 m_hMenu = 0;
1319 }
1320
1321 m_uState = SVUIA_DEACTIVATE;
1322 }
1323 }
1324
1325 void CDefView::DoActivate(UINT uState)
1326 {
1327 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1328 MENUITEMINFOA mii;
1329 CHAR szText[MAX_PATH];
1330
1331 TRACE("%p uState=%x\n", this, uState);
1332
1333 /*don't do anything if the state isn't really changing */
1334 if (m_uState == uState)
1335 {
1336 return;
1337 }
1338
1339 OnDeactivate();
1340
1341 /*only do This if we are active */
1342 if(uState != SVUIA_DEACTIVATE)
1343 {
1344 /*merge the menus */
1345 m_hMenu = CreateMenu();
1346
1347 if(m_hMenu)
1348 {
1349 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
1350 TRACE("-- after fnInsertMenusSB\n");
1351
1352 /*build the top level menu get the menu item's text*/
1353 strcpy(szText, "dummy 31");
1354
1355 ZeroMemory(&mii, sizeof(mii));
1356 mii.cbSize = sizeof(mii);
1357 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1358 mii.fType = MFT_STRING;
1359 mii.fState = MFS_ENABLED;
1360 mii.dwTypeData = szText;
1361 mii.hSubMenu = BuildFileMenu();
1362
1363 /*insert our menu into the menu bar*/
1364 if (mii.hSubMenu)
1365 {
1366 InsertMenuItemA(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1367 }
1368
1369 /*get the view menu so we can merge with it*/
1370 ZeroMemory(&mii, sizeof(mii));
1371 mii.cbSize = sizeof(mii);
1372 mii.fMask = MIIM_SUBMENU;
1373
1374 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1375 {
1376 MergeViewMenu(mii.hSubMenu);
1377 }
1378
1379 /*add the items that should only be added if we have the focus*/
1380 if (SVUIA_ACTIVATE_FOCUS == uState)
1381 {
1382 /*get the file menu so we can merge with it */
1383 ZeroMemory(&mii, sizeof(mii));
1384 mii.cbSize = sizeof(mii);
1385 mii.fMask = MIIM_SUBMENU;
1386
1387 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1388 {
1389 MergeFileMenu(mii.hSubMenu);
1390 }
1391 }
1392
1393 TRACE("-- before fnSetMenuSB\n");
1394 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1395 }
1396 }
1397 m_uState = uState;
1398 TRACE("--\n");
1399 }
1400
1401 /**********************************************************
1402 * ShellView_OnActivate()
1403 */
1404 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1405 {
1406 DoActivate(SVUIA_ACTIVATE_FOCUS);
1407 return 0;
1408 }
1409
1410 /**********************************************************
1411 * ShellView_OnSetFocus()
1412 *
1413 */
1414 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1415 {
1416 TRACE("%p\n", this);
1417
1418 /* Tell the browser one of our windows has received the focus. This
1419 should always be done before merging menus (OnActivate merges the
1420 menus) if one of our windows has the focus.*/
1421
1422 m_pShellBrowser->OnViewWindowActive((IShellView *)this);
1423 DoActivate(SVUIA_ACTIVATE_FOCUS);
1424
1425 /* Set the focus to the listview */
1426 ::SetFocus(m_hWndList);
1427
1428 /* Notify the ICommDlgBrowser interface */
1429 OnStateChange(CDBOSC_SETFOCUS);
1430
1431 return 0;
1432 }
1433
1434 /**********************************************************
1435 * ShellView_OnKillFocus()
1436 */
1437 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1438 {
1439 TRACE("(%p) stub\n", this);
1440
1441 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1442 /* Notify the ICommDlgBrowser */
1443 OnStateChange(CDBOSC_KILLFOCUS);
1444
1445 return 0;
1446 }
1447
1448 /**********************************************************
1449 * ShellView_OnCommand()
1450 *
1451 * NOTES
1452 * the CmdID's are the ones from the context menu
1453 */
1454 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1455 {
1456 DWORD dwCmdID;
1457 DWORD dwCmd;
1458 HWND hwndCmd;
1459
1460 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1461 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1462 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1463
1464 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1465
1466 switch (dwCmdID)
1467 {
1468 case FCIDM_SHVIEW_SMALLICON:
1469 m_FolderSettings.ViewMode = FVM_SMALLICON;
1470 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1471 CheckToolbar();
1472 break;
1473
1474 case FCIDM_SHVIEW_BIGICON:
1475 m_FolderSettings.ViewMode = FVM_ICON;
1476 SetStyle (LVS_ICON, LVS_TYPEMASK);
1477 CheckToolbar();
1478 break;
1479
1480 case FCIDM_SHVIEW_LISTVIEW:
1481 m_FolderSettings.ViewMode = FVM_LIST;
1482 SetStyle (LVS_LIST, LVS_TYPEMASK);
1483 CheckToolbar();
1484 break;
1485
1486 case FCIDM_SHVIEW_REPORTVIEW:
1487 m_FolderSettings.ViewMode = FVM_DETAILS;
1488 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1489 CheckToolbar();
1490 break;
1491
1492 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1493 case 0x30:
1494 case 0x31:
1495 case 0x32:
1496 case 0x33:
1497 m_sortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1498 m_sortInfo.bIsAscending = TRUE;
1499 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1500 SendMessageA(m_hWndList, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1501 break;
1502
1503 case FCIDM_SHVIEW_REFRESH:
1504 Refresh();
1505 break;
1506
1507 case FCIDM_SHVIEW_DELETE:
1508 case FCIDM_SHVIEW_CUT:
1509 case FCIDM_SHVIEW_COPY:
1510 case FCIDM_SHVIEW_RENAME:
1511 return OnExplorerCommand(dwCmdID, TRUE);
1512
1513 case FCIDM_SHVIEW_INSERT:
1514 case FCIDM_SHVIEW_UNDO:
1515 case FCIDM_SHVIEW_INSERTLINK:
1516 case FCIDM_SHVIEW_NEWFOLDER:
1517 return OnExplorerCommand(dwCmdID, FALSE);
1518 default:
1519 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1520 }
1521
1522 return 0;
1523 }
1524
1525 /**********************************************************
1526 * ShellView_OnNotify()
1527 */
1528
1529 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1530 {
1531 UINT CtlID;
1532 LPNMHDR lpnmh;
1533 LPNMLISTVIEW lpnmlv;
1534 NMLVDISPINFOW *lpdi;
1535 LPITEMIDLIST pidl;
1536 BOOL unused;
1537
1538 CtlID = wParam;
1539 lpnmh = (LPNMHDR)lParam;
1540 lpnmlv = (LPNMLISTVIEW)lpnmh;
1541 lpdi = (NMLVDISPINFOW *)lpnmh;
1542
1543 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1544
1545 switch (lpnmh->code)
1546 {
1547 case NM_SETFOCUS:
1548 TRACE("-- NM_SETFOCUS %p\n", this);
1549 OnSetFocus(0, 0, 0, unused);
1550 break;
1551
1552 case NM_KILLFOCUS:
1553 TRACE("-- NM_KILLFOCUS %p\n", this);
1554 OnDeactivate();
1555 /* Notify the ICommDlgBrowser interface */
1556 OnStateChange(CDBOSC_KILLFOCUS);
1557 break;
1558
1559 case NM_CUSTOMDRAW:
1560 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1561 return CDRF_DODEFAULT;
1562
1563 case NM_RELEASEDCAPTURE:
1564 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1565 break;
1566
1567 case NM_CLICK:
1568 TRACE("-- NM_CLICK %p\n", this);
1569 break;
1570
1571 case NM_RCLICK:
1572 TRACE("-- NM_RCLICK %p\n", this);
1573 break;
1574
1575 case NM_DBLCLK:
1576 TRACE("-- NM_DBLCLK %p\n", this);
1577 OpenSelectedItems();
1578 break;
1579
1580 case NM_RETURN:
1581 TRACE("-- NM_RETURN %p\n", this);
1582 OpenSelectedItems();
1583 break;
1584
1585 case HDN_ENDTRACKW:
1586 TRACE("-- HDN_ENDTRACKW %p\n", this);
1587 /*nColumn1 = ListView_GetColumnWidth(m_hWndList, 0);
1588 nColumn2 = ListView_GetColumnWidth(m_hWndList, 1);*/
1589 break;
1590
1591 case LVN_DELETEITEM:
1592 TRACE("-- LVN_DELETEITEM %p\n", this);
1593 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1594 break;
1595
1596 case LVN_DELETEALLITEMS:
1597 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1598 return FALSE;
1599
1600 case LVN_INSERTITEM:
1601 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1602 break;
1603
1604 case LVN_ITEMACTIVATE:
1605 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1606 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1607 break;
1608
1609 case LVN_COLUMNCLICK:
1610 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1611 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1612 {
1613 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1614 }
1615 else
1616 {
1617 m_sortInfo.bIsAscending = TRUE;
1618 }
1619 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1620
1621 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1622 break;
1623
1624 case LVN_GETDISPINFOA:
1625 case LVN_GETDISPINFOW:
1626 TRACE("-- LVN_GETDISPINFO %p\n", this);
1627 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1628
1629 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1630 {
1631 if (m_pSF2Parent)
1632 {
1633 SHELLDETAILS sd;
1634 if (FAILED(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1635 {
1636 FIXME("failed to get details\n");
1637 break;
1638 }
1639
1640 if (lpnmh->code == LVN_GETDISPINFOA)
1641 {
1642 /* shouldn't happen */
1643 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1644 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1645 TRACE("-- text=%s\n", lpdiA->item.pszText);
1646 }
1647 else /* LVN_GETDISPINFOW */
1648 {
1649 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1650 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1651 }
1652 }
1653 else
1654 {
1655 FIXME("no SF2\n");
1656 }
1657 }
1658 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1659 {
1660 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1661 }
1662 lpdi->item.mask |= LVIF_DI_SETITEM;
1663 break;
1664
1665 case LVN_ITEMCHANGED:
1666 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1667 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1668 break;
1669
1670 case LVN_BEGINDRAG:
1671 case LVN_BEGINRDRAG:
1672 TRACE("-- LVN_BEGINDRAG\n");
1673
1674 if (GetSelections())
1675 {
1676 IDataObject * pda;
1677 DWORD dwAttributes = SFGAO_CANLINK;
1678 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1679
1680 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1681 {
1682 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1683
1684 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, (LPCITEMIDLIST*)m_apidl, &dwAttributes)))
1685 {
1686 if (dwAttributes & SFGAO_CANLINK)
1687 {
1688 dwEffect |= DROPEFFECT_LINK;
1689 }
1690 }
1691
1692 CComPtr<IAsyncOperation> piaso;
1693 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
1694 {
1695 piaso->SetAsyncMode(TRUE);
1696 piaso->Release();
1697 }
1698
1699 if (pds)
1700 { DWORD dwEffect2;
1701 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1702 }
1703 pda->Release();
1704 }
1705 }
1706 break;
1707
1708 case LVN_BEGINLABELEDITW:
1709 {
1710 DWORD dwAttr = SFGAO_CANRENAME;
1711 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1712
1713 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1714
1715 m_pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1716 if (SFGAO_CANRENAME & dwAttr)
1717 {
1718 return FALSE;
1719 }
1720 return TRUE;
1721 }
1722
1723 case LVN_ENDLABELEDITW:
1724 {
1725 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1726 if (lpdi->item.pszText)
1727 {
1728 HRESULT hr;
1729 LVITEMW lvItem;
1730
1731 lvItem.iItem = lpdi->item.iItem;
1732 lvItem.iSubItem = 0;
1733 lvItem.mask = LVIF_PARAM;
1734 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1735
1736 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1737 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1738
1739 if (SUCCEEDED(hr) && pidl)
1740 {
1741 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1742 lvItem.lParam = (LPARAM)pidl;
1743 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1744 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1745 SendMessageW(m_hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1746
1747 return TRUE;
1748 }
1749 }
1750
1751 return FALSE;
1752 }
1753
1754 case LVN_KEYDOWN:
1755 {
1756 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1757
1758 /* initiate a rename of the selected file or directory */
1759 if (plvKeyDown->wVKey == VK_BACK)
1760 {
1761 LPSHELLBROWSER lpSb;
1762 if ((lpSb = (LPSHELLBROWSER)SendMessageW(m_hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1763 {
1764 lpSb->BrowseObject(NULL, SBSP_PARENT);
1765 }
1766 }
1767
1768 else
1769 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
1770 }
1771 break;
1772
1773 default:
1774 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1775 break;
1776 }
1777
1778 return 0;
1779 }
1780
1781 /**********************************************************
1782 * ShellView_OnChange()
1783 */
1784 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1785 {
1786 LPITEMIDLIST *Pidls;
1787
1788 Pidls = (LPITEMIDLIST *)wParam;
1789
1790 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1791
1792 switch (lParam)
1793 {
1794 case SHCNE_MKDIR:
1795 case SHCNE_CREATE:
1796 LV_AddItem(Pidls[0]);
1797 break;
1798
1799 case SHCNE_RMDIR:
1800 case SHCNE_DELETE:
1801 LV_DeleteItem(Pidls[0]);
1802 break;
1803
1804 case SHCNE_RENAMEFOLDER:
1805 case SHCNE_RENAMEITEM:
1806 LV_RenameItem(Pidls[0], Pidls[1]);
1807 break;
1808
1809 case SHCNE_UPDATEITEM:
1810 break;
1811 }
1812
1813 return TRUE;
1814 }
1815
1816 /**********************************************************
1817 * CDefView::OnCustomItem
1818 */
1819 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1820 {
1821 if (!m_pCM.p)
1822 {
1823 /* no menu */
1824 ERR("no menu!!!\n");
1825 return FALSE;
1826 }
1827
1828 CComPtr<IContextMenu2> pCM2;
1829 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1830 if(FAILED(hres))
1831 return FALSE;
1832
1833 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1834 return TRUE;
1835 else
1836 return FALSE;
1837 }
1838
1839 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1840 {
1841 /* Wallpaper setting affects drop shadows effect */
1842 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1843 UpdateListColors();
1844
1845 return S_OK;
1846 }
1847
1848 /**********************************************************
1849 *
1850 *
1851 * The INTERFACE of the IShellView object
1852 *
1853 *
1854 **********************************************************
1855 */
1856
1857 /**********************************************************
1858 * ShellView_GetWindow
1859 */
1860 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1861 {
1862 TRACE("(%p)\n", this);
1863
1864 *phWnd = m_hWnd;
1865
1866 return S_OK;
1867 }
1868
1869 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1870 {
1871 FIXME("(%p) stub\n", this);
1872
1873 return E_NOTIMPL;
1874 }
1875
1876 /**********************************************************
1877 * IShellView_TranslateAccelerator
1878 *
1879 * FIXME:
1880 * use the accel functions
1881 */
1882 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1883 {
1884 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1885 {
1886 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1887 return S_OK;
1888
1889 /* FIXME: should call TranslateAcceleratorSB */
1890
1891 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1892 }
1893
1894 return S_FALSE; /* not handled */
1895 }
1896
1897 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1898 {
1899 FIXME("(%p) stub\n", this);
1900
1901 return E_NOTIMPL;
1902 }
1903
1904 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1905 {
1906 /*
1907 CHAR szName[MAX_PATH];
1908 */
1909 LRESULT lResult;
1910 int nPartArray[1] = { -1};
1911
1912 TRACE("(%p)->(state=%x) stub\n", this, uState);
1913
1914 /*don't do anything if the state isn't really changing*/
1915 if (m_uState == uState)
1916 {
1917 return S_OK;
1918 }
1919
1920 /*OnActivate handles the menu merging and internal state*/
1921 DoActivate(uState);
1922
1923 /*only do This if we are active*/
1924 if (uState != SVUIA_DEACTIVATE)
1925 {
1926
1927 /*
1928 GetFolderPath is not a method of IShellFolder
1929 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1930 */
1931 /* set the number of parts */
1932 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1933
1934 /* set the text for the parts */
1935 /*
1936 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1937 */
1938 }
1939
1940 return S_OK;
1941 }
1942
1943 HRESULT WINAPI CDefView::Refresh()
1944 {
1945 TRACE("(%p)\n", this);
1946
1947 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1948 FillList();
1949
1950 return S_OK;
1951 }
1952
1953 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1954 {
1955 *phWnd = 0;
1956
1957 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1958
1959 if (lpfs != NULL)
1960 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1961 if (prcView != NULL)
1962 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1963
1964 /* Validate the Shell Browser */
1965 if (psb == NULL)
1966 return E_UNEXPECTED;
1967
1968 /*set up the member variables*/
1969 m_pShellBrowser = psb;
1970 m_FolderSettings = *lpfs;
1971
1972 /*get our parent window*/
1973 m_pShellBrowser->GetWindow(&m_hWndParent);
1974
1975 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
1976 m_pCommDlgBrowser = NULL;
1977 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
1978 {
1979 TRACE("-- CommDlgBrowser\n");
1980 }
1981
1982 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
1983 if (m_hWnd == NULL)
1984 return E_FAIL;
1985
1986 *phWnd = m_hWnd;
1987
1988 CheckToolbar();
1989
1990 if (!*phWnd)
1991 return E_FAIL;
1992
1993 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1994 UpdateWindow();
1995
1996 return S_OK;
1997 }
1998
1999 HRESULT WINAPI CDefView::DestroyViewWindow()
2000 {
2001 TRACE("(%p)\n", this);
2002
2003 /*Make absolutely sure all our UI is cleaned up.*/
2004 UIActivate(SVUIA_DEACTIVATE);
2005
2006 if (m_hMenu)
2007 {
2008 DestroyMenu(m_hMenu);
2009 }
2010
2011 DestroyWindow();
2012 m_pShellBrowser.Release();
2013 m_pCommDlgBrowser.Release();
2014
2015 return S_OK;
2016 }
2017
2018 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2019 {
2020 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2021 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2022
2023 if (!lpfs)
2024 return E_INVALIDARG;
2025
2026 *lpfs = m_FolderSettings;
2027 return S_OK;
2028 }
2029
2030 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2031 {
2032 FIXME("(%p) stub\n", this);
2033
2034 return E_NOTIMPL;
2035 }
2036
2037 HRESULT WINAPI CDefView::SaveViewState()
2038 {
2039 FIXME("(%p) stub\n", this);
2040
2041 return S_OK;
2042 }
2043
2044 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2045 {
2046 int i;
2047
2048 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2049
2050 i = LV_FindItemByPidl(pidl);
2051
2052 if (i != -1)
2053 {
2054 LVITEMW lvItem;
2055
2056 if(uFlags & SVSI_ENSUREVISIBLE)
2057 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2058
2059 lvItem.mask = LVIF_STATE;
2060 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2061 lvItem.iItem = 0;
2062 lvItem.iSubItem = 0;
2063
2064 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2065 {
2066 if (lvItem.iItem == i)
2067 {
2068 if (uFlags & SVSI_SELECT)
2069 lvItem.state |= LVIS_SELECTED;
2070 else
2071 lvItem.state &= ~LVIS_SELECTED;
2072
2073 if (uFlags & SVSI_FOCUSED)
2074 lvItem.state &= ~LVIS_FOCUSED;
2075 }
2076 else
2077 {
2078 if (uFlags & SVSI_DESELECTOTHERS)
2079 lvItem.state &= ~LVIS_SELECTED;
2080 }
2081
2082 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2083 lvItem.iItem++;
2084 }
2085
2086
2087 if(uFlags & SVSI_EDIT)
2088 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2089 }
2090
2091 return S_OK;
2092 }
2093
2094 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2095 {
2096 HRESULT hr = E_NOINTERFACE;
2097
2098 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2099
2100 *ppvOut = NULL;
2101
2102 switch (uItem)
2103 {
2104 case SVGIO_BACKGROUND:
2105 if (IsEqualIID(riid, IID_IContextMenu))
2106 {
2107 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2108 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2109 if (!ppvOut)
2110 hr = E_OUTOFMEMORY;
2111 else
2112 hr = S_OK;
2113 }
2114 break;
2115
2116 case SVGIO_SELECTION:
2117 GetSelections();
2118 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2119 break;
2120 }
2121
2122 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2123
2124 return hr;
2125 }
2126
2127 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2128 {
2129 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2130
2131 if (!pViewMode)
2132 return E_INVALIDARG;
2133
2134 *pViewMode = m_FolderSettings.ViewMode;
2135 return S_OK;
2136 }
2137
2138 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2139 {
2140 DWORD dwStyle;
2141 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2142
2143 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2144 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2145 return E_INVALIDARG;
2146
2147 /* Windows before Vista uses LVM_SETVIEW and possibly
2148 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2149 while later versions seem to accomplish this through other
2150 means. */
2151 switch (ViewMode)
2152 {
2153 case FVM_ICON:
2154 dwStyle = LVS_ICON;
2155 break;
2156 case FVM_DETAILS:
2157 dwStyle = LVS_REPORT;
2158 break;
2159 case FVM_SMALLICON:
2160 dwStyle = LVS_SMALLICON;
2161 break;
2162 case FVM_LIST:
2163 dwStyle = LVS_LIST;
2164 break;
2165 default:
2166 {
2167 FIXME("ViewMode %d not implemented\n", ViewMode);
2168 dwStyle = LVS_LIST;
2169 break;
2170 }
2171 }
2172
2173 SetStyle(dwStyle, LVS_TYPEMASK);
2174
2175 /* This will not necessarily be the actual mode set above.
2176 This mimics the behavior of Windows XP. */
2177 m_FolderSettings.ViewMode = ViewMode;
2178
2179 return S_OK;
2180 }
2181
2182 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2183 {
2184 if (m_pSFParent == NULL)
2185 return E_FAIL;
2186
2187 return m_pSFParent->QueryInterface(riid, ppv);
2188 }
2189
2190 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2191 {
2192 LVITEMW item;
2193
2194 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2195
2196 item.mask = LVIF_PARAM;
2197 item.iItem = iItemIndex;
2198
2199 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2200 {
2201 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2202 return S_OK;
2203 }
2204
2205 *ppidl = 0;
2206
2207 return E_INVALIDARG;
2208 }
2209
2210 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2211 {
2212 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2213
2214 if (uFlags != SVGIO_ALLVIEW)
2215 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2216
2217 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2218
2219 return S_OK;
2220 }
2221
2222 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2223 {
2224 return E_NOTIMPL;
2225 }
2226
2227 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2228 {
2229 TRACE("(%p)->(%p)\n", this, piItem);
2230
2231 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2232
2233 return S_OK;
2234 }
2235
2236 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2237 {
2238 TRACE("(%p)->(%p)\n", this, piItem);
2239
2240 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2241
2242 return S_OK;
2243 }
2244
2245 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2246 {
2247 return E_NOTIMPL;
2248 }
2249
2250 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2251 {
2252 TRACE("(%p)->(%p)\n", this, ppt);
2253
2254 if (NULL == m_hWndList) return S_FALSE;
2255
2256 if (ppt)
2257 {
2258 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2259
2260 ppt->x = LOWORD(ret);
2261 ppt->y = HIWORD(ret);
2262 }
2263
2264 return S_OK;
2265 }
2266
2267 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2268 {
2269 return E_NOTIMPL;
2270 }
2271
2272 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2273 {
2274 return E_NOTIMPL;
2275 }
2276
2277 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2278 {
2279 LVITEMW lvItem;
2280
2281 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2282
2283 lvItem.state = 0;
2284 lvItem.stateMask = LVIS_SELECTED;
2285
2286 if (dwFlags & SVSI_ENSUREVISIBLE)
2287 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2288
2289 /* all items */
2290 if (dwFlags & SVSI_DESELECTOTHERS)
2291 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2292
2293 /* this item */
2294 if (dwFlags & SVSI_SELECT)
2295 lvItem.state |= LVIS_SELECTED;
2296
2297 if (dwFlags & SVSI_FOCUSED)
2298 lvItem.stateMask |= LVIS_FOCUSED;
2299
2300 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2301
2302 if (dwFlags & SVSI_EDIT)
2303 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2304
2305 return S_OK;
2306 }
2307
2308 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2309 {
2310 return E_NOTIMPL;
2311 }
2312
2313 /**********************************************************
2314 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2315 */
2316 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2317 {
2318 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2319 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2320
2321 if (!prgCmds)
2322 return E_INVALIDARG;
2323
2324 for (UINT i = 0; i < cCmds; i++)
2325 {
2326 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2327 prgCmds[i].cmdf = 0;
2328 }
2329
2330 return OLECMDERR_E_UNKNOWNGROUP;
2331 }
2332
2333 /**********************************************************
2334 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2335 *
2336 * nCmdID is the OLECMDID_* enumeration
2337 */
2338 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2339 {
2340 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2341 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2342
2343 if (!pguidCmdGroup)
2344 return OLECMDERR_E_UNKNOWNGROUP;
2345
2346 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2347 (nCmdID == 0x29) &&
2348 (nCmdexecopt == 4) && pvaOut)
2349 return S_OK;
2350
2351 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2352 (nCmdID == 9) &&
2353 (nCmdexecopt == 0))
2354 return 1;
2355
2356 return OLECMDERR_E_UNKNOWNGROUP;
2357 }
2358
2359 /**********************************************************
2360 * ISVDropTarget implementation
2361 */
2362
2363 /******************************************************************************
2364 * drag_notify_subitem [Internal]
2365 *
2366 * Figure out the shellfolder object, which is currently under the mouse cursor
2367 * and notify it via the IDropTarget interface.
2368 */
2369
2370 #define SCROLLAREAWIDTH 20
2371
2372 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2373 {
2374 LVHITTESTINFO htinfo;
2375 LVITEMW lvItem;
2376 LONG lResult;
2377 HRESULT hr;
2378 RECT clientRect;
2379
2380 /* Map from global to client coordinates and query the index of the listview-item, which is
2381 * currently under the mouse cursor. */
2382 htinfo.pt.x = pt.x;
2383 htinfo.pt.y = pt.y;
2384 htinfo.flags = LVHT_ONITEM;
2385 ::ScreenToClient(m_hWndList, &htinfo.pt);
2386 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2387
2388 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2389 ::GetClientRect(m_hWndList, &clientRect);
2390 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2391 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2392 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2393 {
2394 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2395 if (m_cScrollDelay == 0)
2396 {
2397 /* Mouse did hover another 250 ms over the scroll-area */
2398 if (htinfo.pt.x < SCROLLAREAWIDTH)
2399 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2400
2401 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2402 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2403
2404 if (htinfo.pt.y < SCROLLAREAWIDTH)
2405 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2406
2407 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2408 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2409 }
2410 }
2411 else
2412 {
2413 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2414 }
2415
2416 m_ptLastMousePos = htinfo.pt;
2417
2418 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2419 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2420 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2421
2422 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2423 if (m_pCurDropTarget)
2424 {
2425 m_pCurDropTarget->DragLeave();
2426 m_pCurDropTarget.Release();
2427 }
2428
2429 m_iDragOverItem = lResult;
2430 if (lResult == -1)
2431 {
2432 /* We are not above one of the listview's subitems. Bind to the parent folder's
2433 * DropTarget interface. */
2434 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2435 }
2436 else
2437 {
2438 /* Query the relative PIDL of the shellfolder object represented by the currently
2439 * dragged over listview-item ... */
2440 lvItem.mask = LVIF_PARAM;
2441 lvItem.iItem = lResult;
2442 lvItem.iSubItem = 0;
2443 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2444
2445 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2446 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1,
2447 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&m_pCurDropTarget);
2448 }
2449
2450 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2451 if (FAILED(hr))
2452 return hr;
2453
2454 /* Notify the item just entered via DragEnter. */
2455 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2456 }
2457
2458 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2459 {
2460 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2461 m_pCurDataObject = pDataObject;
2462 pDataObject->AddRef();
2463
2464 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2465 }
2466
2467 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2468 {
2469 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2470 }
2471
2472 HRESULT WINAPI CDefView::DragLeave()
2473 {
2474 if (m_pCurDropTarget)
2475 {
2476 m_pCurDropTarget->DragLeave();
2477 m_pCurDropTarget.Release();
2478 }
2479
2480 if (m_pCurDataObject != NULL)
2481 {
2482 m_pCurDataObject.Release();
2483 }
2484
2485 m_iDragOverItem = 0;
2486
2487 return S_OK;
2488 }
2489
2490 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2491 {
2492 if (m_pCurDropTarget)
2493 {
2494 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2495 m_pCurDropTarget.Release();
2496
2497 this->Refresh();
2498 }
2499
2500 m_pCurDataObject.Release(); m_iDragOverItem = 0;
2501
2502 return S_OK;
2503 }
2504
2505 /**********************************************************
2506 * ISVDropSource implementation
2507 */
2508
2509 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2510 {
2511 TRACE("(%p)\n", this);
2512
2513 if (fEscapePressed)
2514 return DRAGDROP_S_CANCEL;
2515 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2516 return DRAGDROP_S_DROP;
2517 else
2518 return S_OK;
2519 }
2520
2521 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2522 {
2523 TRACE("(%p)\n", this);
2524
2525 return DRAGDROP_S_USEDEFAULTCURSORS;
2526 }
2527
2528 /**********************************************************
2529 * ISVViewObject implementation
2530 */
2531
2532 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)
2533 {
2534 FIXME("Stub: this=%p\n", this);
2535
2536 return E_NOTIMPL;
2537 }
2538
2539 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2540 {
2541 FIXME("Stub: this=%p\n", this);
2542
2543 return E_NOTIMPL;
2544 }
2545
2546 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2547 {
2548 FIXME("Stub: this=%p\n", this);
2549
2550 return E_NOTIMPL;
2551 }
2552
2553 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2554 {
2555 FIXME("Stub: this=%p\n", this);
2556
2557 return E_NOTIMPL;
2558 }
2559
2560 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2561 {
2562 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2563
2564 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2565 m_pAdvSink = pAdvSink;
2566 m_dwAspects = aspects;
2567 m_dwAdvf = advf;
2568
2569 return S_OK;
2570 }
2571
2572 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2573 {
2574 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2575
2576 if (ppAdvSink)
2577 {
2578 *ppAdvSink = m_pAdvSink;
2579 m_pAdvSink.p->AddRef();
2580 }
2581
2582 if (pAspects)
2583 *pAspects = m_dwAspects;
2584
2585 if (pAdvf)
2586 *pAdvf = m_dwAdvf;
2587
2588 return S_OK;
2589 }
2590
2591 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2592 {
2593 if (IsEqualIID(guidService, SID_IShellBrowser))
2594 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2595 else if(IsEqualIID(guidService, SID_IFolderView))
2596 return QueryInterface(riid, ppvObject);
2597
2598 return E_NOINTERFACE;
2599 }
2600
2601 /**********************************************************
2602 * IShellView_Constructor
2603 */
2604 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2605 {
2606 CComObject<CDefView> *theView;
2607 CComPtr<IShellView> result;
2608 HRESULT hResult;
2609
2610 if (newView == NULL)
2611 return E_POINTER;
2612
2613 *newView = NULL;
2614 ATLTRY (theView = new CComObject<CDefView>);
2615
2616 if (theView == NULL)
2617 return E_OUTOFMEMORY;
2618
2619 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2620 if (FAILED (hResult))
2621 {
2622 delete theView;
2623 return hResult;
2624 }
2625
2626 hResult = theView->Initialize (pFolder);
2627 if (FAILED (hResult))
2628 return hResult;
2629 *newView = result.Detach ();
2630
2631 return S_OK;
2632 }