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