[SHELL32]
[reactos.git] / reactos / 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 if (pds)
1691 {
1692 DWORD dwEffect2;
1693 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1694 if ((dwEffect2 & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
1695 this->Refresh();
1696 }
1697 pda->Release();
1698 }
1699 }
1700 break;
1701
1702 case LVN_BEGINLABELEDITW:
1703 {
1704 DWORD dwAttr = SFGAO_CANRENAME;
1705 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1706
1707 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1708
1709 m_pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1710 if (SFGAO_CANRENAME & dwAttr)
1711 {
1712 return FALSE;
1713 }
1714 return TRUE;
1715 }
1716
1717 case LVN_ENDLABELEDITW:
1718 {
1719 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1720 if (lpdi->item.pszText)
1721 {
1722 HRESULT hr;
1723 LVITEMW lvItem;
1724
1725 lvItem.iItem = lpdi->item.iItem;
1726 lvItem.iSubItem = 0;
1727 lvItem.mask = LVIF_PARAM;
1728 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1729
1730 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1731 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1732
1733 if (SUCCEEDED(hr) && pidl)
1734 {
1735 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1736 lvItem.lParam = (LPARAM)pidl;
1737 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1738 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1739 SendMessageW(m_hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1740
1741 return TRUE;
1742 }
1743 }
1744
1745 return FALSE;
1746 }
1747
1748 case LVN_KEYDOWN:
1749 {
1750 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1751
1752 /* initiate a rename of the selected file or directory */
1753 if (plvKeyDown->wVKey == VK_BACK)
1754 {
1755 LPSHELLBROWSER lpSb;
1756 if ((lpSb = (LPSHELLBROWSER)SendMessageW(m_hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1757 {
1758 lpSb->BrowseObject(NULL, SBSP_PARENT);
1759 }
1760 }
1761
1762 else
1763 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
1764 }
1765 break;
1766
1767 default:
1768 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1769 break;
1770 }
1771
1772 return 0;
1773 }
1774
1775 /**********************************************************
1776 * ShellView_OnChange()
1777 */
1778 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1779 {
1780 LPITEMIDLIST *Pidls;
1781
1782 Pidls = (LPITEMIDLIST *)wParam;
1783
1784 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1785
1786 switch (lParam)
1787 {
1788 case SHCNE_MKDIR:
1789 case SHCNE_CREATE:
1790 LV_AddItem(Pidls[0]);
1791 break;
1792
1793 case SHCNE_RMDIR:
1794 case SHCNE_DELETE:
1795 LV_DeleteItem(Pidls[0]);
1796 break;
1797
1798 case SHCNE_RENAMEFOLDER:
1799 case SHCNE_RENAMEITEM:
1800 LV_RenameItem(Pidls[0], Pidls[1]);
1801 break;
1802
1803 case SHCNE_UPDATEITEM:
1804 break;
1805 }
1806
1807 return TRUE;
1808 }
1809
1810 /**********************************************************
1811 * CDefView::OnCustomItem
1812 */
1813 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1814 {
1815 if (!m_pCM.p)
1816 {
1817 /* no menu */
1818 ERR("no menu!!!\n");
1819 return FALSE;
1820 }
1821
1822 CComPtr<IContextMenu2> pCM2;
1823 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1824 if(FAILED(hres))
1825 return FALSE;
1826
1827 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1828 return TRUE;
1829 else
1830 return FALSE;
1831 }
1832
1833 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1834 {
1835 /* Wallpaper setting affects drop shadows effect */
1836 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1837 UpdateListColors();
1838
1839 return S_OK;
1840 }
1841
1842 /**********************************************************
1843 *
1844 *
1845 * The INTERFACE of the IShellView object
1846 *
1847 *
1848 **********************************************************
1849 */
1850
1851 /**********************************************************
1852 * ShellView_GetWindow
1853 */
1854 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1855 {
1856 TRACE("(%p)\n", this);
1857
1858 *phWnd = m_hWnd;
1859
1860 return S_OK;
1861 }
1862
1863 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1864 {
1865 FIXME("(%p) stub\n", this);
1866
1867 return E_NOTIMPL;
1868 }
1869
1870 /**********************************************************
1871 * IShellView_TranslateAccelerator
1872 *
1873 * FIXME:
1874 * use the accel functions
1875 */
1876 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1877 {
1878 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1879 {
1880 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1881 return S_OK;
1882
1883 /* FIXME: should call TranslateAcceleratorSB */
1884
1885 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1886 }
1887
1888 return S_FALSE; /* not handled */
1889 }
1890
1891 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1892 {
1893 FIXME("(%p) stub\n", this);
1894
1895 return E_NOTIMPL;
1896 }
1897
1898 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1899 {
1900 /*
1901 CHAR szName[MAX_PATH];
1902 */
1903 LRESULT lResult;
1904 int nPartArray[1] = { -1};
1905
1906 TRACE("(%p)->(state=%x) stub\n", this, uState);
1907
1908 /*don't do anything if the state isn't really changing*/
1909 if (m_uState == uState)
1910 {
1911 return S_OK;
1912 }
1913
1914 /*OnActivate handles the menu merging and internal state*/
1915 DoActivate(uState);
1916
1917 /*only do This if we are active*/
1918 if (uState != SVUIA_DEACTIVATE)
1919 {
1920
1921 /*
1922 GetFolderPath is not a method of IShellFolder
1923 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1924 */
1925 /* set the number of parts */
1926 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1927
1928 /* set the text for the parts */
1929 /*
1930 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1931 */
1932 }
1933
1934 return S_OK;
1935 }
1936
1937 HRESULT WINAPI CDefView::Refresh()
1938 {
1939 TRACE("(%p)\n", this);
1940
1941 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1942 FillList();
1943
1944 return S_OK;
1945 }
1946
1947 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1948 {
1949 *phWnd = 0;
1950
1951 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1952
1953 if (lpfs != NULL)
1954 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1955 if (prcView != NULL)
1956 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1957
1958 /* Validate the Shell Browser */
1959 if (psb == NULL)
1960 return E_UNEXPECTED;
1961
1962 /*set up the member variables*/
1963 m_pShellBrowser = psb;
1964 m_FolderSettings = *lpfs;
1965
1966 /*get our parent window*/
1967 m_pShellBrowser->GetWindow(&m_hWndParent);
1968
1969 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
1970 m_pCommDlgBrowser = NULL;
1971 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
1972 {
1973 TRACE("-- CommDlgBrowser\n");
1974 }
1975
1976 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
1977 if (m_hWnd == NULL)
1978 return E_FAIL;
1979
1980 *phWnd = m_hWnd;
1981
1982 CheckToolbar();
1983
1984 if (!*phWnd)
1985 return E_FAIL;
1986
1987 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1988 UpdateWindow();
1989
1990 return S_OK;
1991 }
1992
1993 HRESULT WINAPI CDefView::DestroyViewWindow()
1994 {
1995 TRACE("(%p)\n", this);
1996
1997 /*Make absolutely sure all our UI is cleaned up.*/
1998 UIActivate(SVUIA_DEACTIVATE);
1999
2000 if (m_hMenu)
2001 {
2002 DestroyMenu(m_hMenu);
2003 }
2004
2005 DestroyWindow();
2006 m_pShellBrowser.Release();
2007 m_pCommDlgBrowser.Release();
2008
2009 return S_OK;
2010 }
2011
2012 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2013 {
2014 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2015 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2016
2017 if (!lpfs)
2018 return E_INVALIDARG;
2019
2020 *lpfs = m_FolderSettings;
2021 return S_OK;
2022 }
2023
2024 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2025 {
2026 FIXME("(%p) stub\n", this);
2027
2028 return E_NOTIMPL;
2029 }
2030
2031 HRESULT WINAPI CDefView::SaveViewState()
2032 {
2033 FIXME("(%p) stub\n", this);
2034
2035 return S_OK;
2036 }
2037
2038 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2039 {
2040 int i;
2041
2042 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2043
2044 i = LV_FindItemByPidl(pidl);
2045
2046 if (i != -1)
2047 {
2048 LVITEMW lvItem;
2049
2050 if(uFlags & SVSI_ENSUREVISIBLE)
2051 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2052
2053 lvItem.mask = LVIF_STATE;
2054 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2055 lvItem.iItem = 0;
2056 lvItem.iSubItem = 0;
2057
2058 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2059 {
2060 if (lvItem.iItem == i)
2061 {
2062 if (uFlags & SVSI_SELECT)
2063 lvItem.state |= LVIS_SELECTED;
2064 else
2065 lvItem.state &= ~LVIS_SELECTED;
2066
2067 if (uFlags & SVSI_FOCUSED)
2068 lvItem.state &= ~LVIS_FOCUSED;
2069 }
2070 else
2071 {
2072 if (uFlags & SVSI_DESELECTOTHERS)
2073 lvItem.state &= ~LVIS_SELECTED;
2074 }
2075
2076 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2077 lvItem.iItem++;
2078 }
2079
2080
2081 if(uFlags & SVSI_EDIT)
2082 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2083 }
2084
2085 return S_OK;
2086 }
2087
2088 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2089 {
2090 HRESULT hr = E_NOINTERFACE;
2091
2092 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2093
2094 *ppvOut = NULL;
2095
2096 switch (uItem)
2097 {
2098 case SVGIO_BACKGROUND:
2099 if (IsEqualIID(riid, IID_IContextMenu))
2100 {
2101 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2102 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2103 if (!ppvOut)
2104 hr = E_OUTOFMEMORY;
2105 else
2106 hr = S_OK;
2107 }
2108 break;
2109
2110 case SVGIO_SELECTION:
2111 GetSelections();
2112 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2113 break;
2114 }
2115
2116 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2117
2118 return hr;
2119 }
2120
2121 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2122 {
2123 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2124
2125 if (!pViewMode)
2126 return E_INVALIDARG;
2127
2128 *pViewMode = m_FolderSettings.ViewMode;
2129 return S_OK;
2130 }
2131
2132 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2133 {
2134 DWORD dwStyle;
2135 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2136
2137 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2138 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2139 return E_INVALIDARG;
2140
2141 /* Windows before Vista uses LVM_SETVIEW and possibly
2142 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2143 while later versions seem to accomplish this through other
2144 means. */
2145 switch (ViewMode)
2146 {
2147 case FVM_ICON:
2148 dwStyle = LVS_ICON;
2149 break;
2150 case FVM_DETAILS:
2151 dwStyle = LVS_REPORT;
2152 break;
2153 case FVM_SMALLICON:
2154 dwStyle = LVS_SMALLICON;
2155 break;
2156 case FVM_LIST:
2157 dwStyle = LVS_LIST;
2158 break;
2159 default:
2160 {
2161 FIXME("ViewMode %d not implemented\n", ViewMode);
2162 dwStyle = LVS_LIST;
2163 break;
2164 }
2165 }
2166
2167 SetStyle(dwStyle, LVS_TYPEMASK);
2168
2169 /* This will not necessarily be the actual mode set above.
2170 This mimics the behavior of Windows XP. */
2171 m_FolderSettings.ViewMode = ViewMode;
2172
2173 return S_OK;
2174 }
2175
2176 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2177 {
2178 if (m_pSFParent == NULL)
2179 return E_FAIL;
2180
2181 return m_pSFParent->QueryInterface(riid, ppv);
2182 }
2183
2184 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2185 {
2186 LVITEMW item;
2187
2188 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2189
2190 item.mask = LVIF_PARAM;
2191 item.iItem = iItemIndex;
2192
2193 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2194 {
2195 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2196 return S_OK;
2197 }
2198
2199 *ppidl = 0;
2200
2201 return E_INVALIDARG;
2202 }
2203
2204 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2205 {
2206 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2207
2208 if (uFlags != SVGIO_ALLVIEW)
2209 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2210
2211 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2212
2213 return S_OK;
2214 }
2215
2216 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2217 {
2218 return E_NOTIMPL;
2219 }
2220
2221 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2222 {
2223 TRACE("(%p)->(%p)\n", this, piItem);
2224
2225 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2226
2227 return S_OK;
2228 }
2229
2230 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2231 {
2232 TRACE("(%p)->(%p)\n", this, piItem);
2233
2234 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2235
2236 return S_OK;
2237 }
2238
2239 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2240 {
2241 return E_NOTIMPL;
2242 }
2243
2244 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2245 {
2246 TRACE("(%p)->(%p)\n", this, ppt);
2247
2248 if (NULL == m_hWndList) return S_FALSE;
2249
2250 if (ppt)
2251 {
2252 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2253
2254 ppt->x = LOWORD(ret);
2255 ppt->y = HIWORD(ret);
2256 }
2257
2258 return S_OK;
2259 }
2260
2261 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2262 {
2263 return E_NOTIMPL;
2264 }
2265
2266 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2267 {
2268 return E_NOTIMPL;
2269 }
2270
2271 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2272 {
2273 LVITEMW lvItem;
2274
2275 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2276
2277 lvItem.state = 0;
2278 lvItem.stateMask = LVIS_SELECTED;
2279
2280 if (dwFlags & SVSI_ENSUREVISIBLE)
2281 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2282
2283 /* all items */
2284 if (dwFlags & SVSI_DESELECTOTHERS)
2285 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2286
2287 /* this item */
2288 if (dwFlags & SVSI_SELECT)
2289 lvItem.state |= LVIS_SELECTED;
2290
2291 if (dwFlags & SVSI_FOCUSED)
2292 lvItem.stateMask |= LVIS_FOCUSED;
2293
2294 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2295
2296 if (dwFlags & SVSI_EDIT)
2297 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2298
2299 return S_OK;
2300 }
2301
2302 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2303 {
2304 return E_NOTIMPL;
2305 }
2306
2307 /**********************************************************
2308 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2309 */
2310 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2311 {
2312 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2313 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2314
2315 if (!prgCmds)
2316 return E_INVALIDARG;
2317
2318 for (UINT i = 0; i < cCmds; i++)
2319 {
2320 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2321 prgCmds[i].cmdf = 0;
2322 }
2323
2324 return OLECMDERR_E_UNKNOWNGROUP;
2325 }
2326
2327 /**********************************************************
2328 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2329 *
2330 * nCmdID is the OLECMDID_* enumeration
2331 */
2332 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2333 {
2334 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2335 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2336
2337 if (!pguidCmdGroup)
2338 return OLECMDERR_E_UNKNOWNGROUP;
2339
2340 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2341 (nCmdID == 0x29) &&
2342 (nCmdexecopt == 4) && pvaOut)
2343 return S_OK;
2344
2345 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2346 (nCmdID == 9) &&
2347 (nCmdexecopt == 0))
2348 return 1;
2349
2350 return OLECMDERR_E_UNKNOWNGROUP;
2351 }
2352
2353 /**********************************************************
2354 * ISVDropTarget implementation
2355 */
2356
2357 /******************************************************************************
2358 * drag_notify_subitem [Internal]
2359 *
2360 * Figure out the shellfolder object, which is currently under the mouse cursor
2361 * and notify it via the IDropTarget interface.
2362 */
2363
2364 #define SCROLLAREAWIDTH 20
2365
2366 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2367 {
2368 LVHITTESTINFO htinfo;
2369 LVITEMW lvItem;
2370 LONG lResult;
2371 HRESULT hr;
2372 RECT clientRect;
2373
2374 /* Map from global to client coordinates and query the index of the listview-item, which is
2375 * currently under the mouse cursor. */
2376 htinfo.pt.x = pt.x;
2377 htinfo.pt.y = pt.y;
2378 htinfo.flags = LVHT_ONITEM;
2379 ::ScreenToClient(m_hWndList, &htinfo.pt);
2380 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2381
2382 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2383 ::GetClientRect(m_hWndList, &clientRect);
2384 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2385 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2386 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2387 {
2388 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2389 if (m_cScrollDelay == 0)
2390 {
2391 /* Mouse did hover another 250 ms over the scroll-area */
2392 if (htinfo.pt.x < SCROLLAREAWIDTH)
2393 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2394
2395 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2396 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2397
2398 if (htinfo.pt.y < SCROLLAREAWIDTH)
2399 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2400
2401 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2402 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2403 }
2404 }
2405 else
2406 {
2407 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2408 }
2409
2410 m_ptLastMousePos = htinfo.pt;
2411
2412 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2413 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2414 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2415
2416 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2417 if (m_pCurDropTarget)
2418 {
2419 m_pCurDropTarget->DragLeave();
2420 m_pCurDropTarget.Release();
2421 }
2422
2423 m_iDragOverItem = lResult;
2424 if (lResult == -1)
2425 {
2426 /* We are not above one of the listview's subitems. Bind to the parent folder's
2427 * DropTarget interface. */
2428 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2429 }
2430 else
2431 {
2432 /* Query the relative PIDL of the shellfolder object represented by the currently
2433 * dragged over listview-item ... */
2434 lvItem.mask = LVIF_PARAM;
2435 lvItem.iItem = lResult;
2436 lvItem.iSubItem = 0;
2437 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2438
2439 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2440 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1,
2441 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&m_pCurDropTarget);
2442 }
2443
2444 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2445 if (FAILED(hr))
2446 return hr;
2447
2448 /* Notify the item just entered via DragEnter. */
2449 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2450 }
2451
2452 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2453 {
2454 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2455 m_pCurDataObject = pDataObject;
2456 pDataObject->AddRef();
2457
2458 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2459 }
2460
2461 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2462 {
2463 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2464 }
2465
2466 HRESULT WINAPI CDefView::DragLeave()
2467 {
2468 if (m_pCurDropTarget)
2469 {
2470 m_pCurDropTarget->DragLeave();
2471 m_pCurDropTarget.Release();
2472 }
2473
2474 if (m_pCurDataObject != NULL)
2475 {
2476 m_pCurDataObject.Release();
2477 }
2478
2479 m_iDragOverItem = 0;
2480
2481 return S_OK;
2482 }
2483
2484 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2485 {
2486 if (m_pCurDropTarget)
2487 {
2488 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2489 m_pCurDropTarget.Release();
2490
2491 this->Refresh();
2492 }
2493
2494 m_pCurDataObject.Release(); m_iDragOverItem = 0;
2495
2496 return S_OK;
2497 }
2498
2499 /**********************************************************
2500 * ISVDropSource implementation
2501 */
2502
2503 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2504 {
2505 TRACE("(%p)\n", this);
2506
2507 if (fEscapePressed)
2508 return DRAGDROP_S_CANCEL;
2509 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2510 return DRAGDROP_S_DROP;
2511 else
2512 return S_OK;
2513 }
2514
2515 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2516 {
2517 TRACE("(%p)\n", this);
2518
2519 return DRAGDROP_S_USEDEFAULTCURSORS;
2520 }
2521
2522 /**********************************************************
2523 * ISVViewObject implementation
2524 */
2525
2526 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)
2527 {
2528 FIXME("Stub: this=%p\n", this);
2529
2530 return E_NOTIMPL;
2531 }
2532
2533 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2534 {
2535 FIXME("Stub: this=%p\n", this);
2536
2537 return E_NOTIMPL;
2538 }
2539
2540 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2541 {
2542 FIXME("Stub: this=%p\n", this);
2543
2544 return E_NOTIMPL;
2545 }
2546
2547 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2548 {
2549 FIXME("Stub: this=%p\n", this);
2550
2551 return E_NOTIMPL;
2552 }
2553
2554 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2555 {
2556 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2557
2558 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2559 m_pAdvSink = pAdvSink;
2560 m_dwAspects = aspects;
2561 m_dwAdvf = advf;
2562
2563 return S_OK;
2564 }
2565
2566 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2567 {
2568 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2569
2570 if (ppAdvSink)
2571 {
2572 *ppAdvSink = m_pAdvSink;
2573 m_pAdvSink.p->AddRef();
2574 }
2575
2576 if (pAspects)
2577 *pAspects = m_dwAspects;
2578
2579 if (pAdvf)
2580 *pAdvf = m_dwAdvf;
2581
2582 return S_OK;
2583 }
2584
2585 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2586 {
2587 if (IsEqualIID(guidService, SID_IShellBrowser))
2588 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2589 else if(IsEqualIID(guidService, SID_IFolderView))
2590 return QueryInterface(riid, ppvObject);
2591
2592 return E_NOINTERFACE;
2593 }
2594
2595 /**********************************************************
2596 * IShellView_Constructor
2597 */
2598 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2599 {
2600 CComObject<CDefView> *theView;
2601 CComPtr<IShellView> result;
2602 HRESULT hResult;
2603
2604 if (newView == NULL)
2605 return E_POINTER;
2606
2607 *newView = NULL;
2608 ATLTRY (theView = new CComObject<CDefView>);
2609
2610 if (theView == NULL)
2611 return E_OUTOFMEMORY;
2612
2613 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2614 if (FAILED (hResult))
2615 {
2616 delete theView;
2617 return hResult;
2618 }
2619
2620 hResult = theView->Initialize (pFolder);
2621 if (FAILED (hResult))
2622 return hResult;
2623 *newView = result.Detach ();
2624
2625 return S_OK;
2626 }