f4ca004bb744642407ad41af0ed10fce5fa3e7f8
[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 RegisterDragDrop(m_hWnd, pdt);
941
942 /* register for receiving notifications */
943 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
944 if (ppf2)
945 {
946 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
947 ntreg.fRecursive = TRUE;
948 m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
949 SHFree((LPITEMIDLIST)ntreg.pidl);
950 }
951
952 m_hAccel = LoadAcceleratorsA(shell32_hInstance, MAKEINTRESOURCEA( IDA_SHELLVIEW));
953
954 return S_OK;
955 }
956
957 /**********************************************************
958 * #### Handling of the menus ####
959 */
960
961 /**********************************************************
962 * ShellView_BuildFileMenu()
963 */
964 HMENU CDefView::BuildFileMenu()
965 { WCHAR szText[MAX_PATH];
966 MENUITEMINFOW mii;
967 int nTools, i;
968 HMENU hSubMenu;
969
970 TRACE("(%p)\n", this);
971
972 hSubMenu = CreatePopupMenu();
973 if (hSubMenu)
974 {
975 /*get the number of items in our global array*/
976 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++) {}
977
978 /*add the menu items*/
979 for(i = 0; i < nTools; i++)
980 {
981 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
982
983 ZeroMemory(&mii, sizeof(mii));
984 mii.cbSize = sizeof(mii);
985 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
986
987 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
988 {
989 mii.fType = MFT_STRING;
990 mii.fState = MFS_ENABLED;
991 mii.dwTypeData = szText;
992 mii.wID = Tools[i].idCommand;
993 }
994 else
995 {
996 mii.fType = MFT_SEPARATOR;
997 }
998 /* tack This item onto the end of the menu */
999 InsertMenuItemW(hSubMenu, (UINT) - 1, TRUE, &mii);
1000 }
1001 }
1002
1003 TRACE("-- return (menu=%p)\n", hSubMenu);
1004 return hSubMenu;
1005 }
1006
1007 /**********************************************************
1008 * ShellView_MergeFileMenu()
1009 */
1010 void CDefView::MergeFileMenu(HMENU hSubMenu)
1011 {
1012 TRACE("(%p)->(submenu=%p) stub\n", this, hSubMenu);
1013
1014 if (hSubMenu)
1015 { /*insert This item at the beginning of the menu */
1016 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1017 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
1018 }
1019
1020 TRACE("--\n");
1021 }
1022
1023 /**********************************************************
1024 * ShellView_MergeViewMenu()
1025 */
1026 void CDefView::MergeViewMenu(HMENU hSubMenu)
1027 {
1028 TRACE("(%p)->(submenu=%p)\n", this, hSubMenu);
1029
1030 if (hSubMenu)
1031 {
1032 /*add a separator at the correct position in the menu*/
1033 MENUITEMINFOW mii;
1034 static WCHAR view[] = L"View";
1035
1036 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1037
1038 ZeroMemory(&mii, sizeof(mii));
1039 mii.cbSize = sizeof(mii);
1040 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
1041 mii.fType = MFT_STRING;
1042 mii.dwTypeData = view;
1043 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
1044 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
1045 }
1046 }
1047
1048 /**********************************************************
1049 * ShellView_GetSelections()
1050 *
1051 * - fills the m_apidl list with the selected objects
1052 *
1053 * RETURNS
1054 * number of selected items
1055 */
1056 UINT CDefView::GetSelections()
1057 {
1058 LVITEMW lvItem;
1059 UINT i = 0;
1060
1061 SHFree(m_apidl);
1062
1063 m_cidl = ListView_GetSelectedCount(m_hWndList);
1064 m_apidl = (LPITEMIDLIST*)SHAlloc(m_cidl * sizeof(LPITEMIDLIST));
1065
1066 TRACE("selected=%i\n", m_cidl);
1067
1068 if (m_apidl)
1069 {
1070 TRACE("-- Items selected =%u\n", m_cidl);
1071
1072 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1073 lvItem.stateMask = LVIS_SELECTED;
1074 lvItem.iItem = 0;
1075 lvItem.iSubItem = 0;
1076 lvItem.state = 0;
1077
1078 while(SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < m_cidl))
1079 {
1080 if(lvItem.state & LVIS_SELECTED)
1081 {
1082 m_apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1083 i++;
1084 if (i == m_cidl)
1085 break;
1086 TRACE("-- selected Item found\n");
1087 }
1088 lvItem.iItem++;
1089 }
1090 }
1091
1092 return m_cidl;
1093 }
1094
1095 /**********************************************************
1096 * ShellView_OpenSelectedItems()
1097 */
1098 HRESULT CDefView::OpenSelectedItems()
1099 {
1100 HMENU hMenu;
1101 CMINVOKECOMMANDINFO cmi;
1102 UINT uCommand;
1103 HRESULT hResult;
1104
1105 m_cidl = ListView_GetSelectedCount(m_hWndList);
1106 if (m_cidl == 0)
1107 return S_OK;
1108
1109 hResult = OnDefaultCommand();
1110 if (hResult == S_OK)
1111 return hResult;
1112
1113 hMenu = CreatePopupMenu();
1114 if (!hMenu)
1115 return E_FAIL;
1116
1117 hResult = GetItemObject( SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1118 if (FAILED(hResult))
1119 goto cleanup;
1120
1121 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1122 //if (FAILED( hResult))
1123 // goto cleanup;
1124
1125 hResult = m_pCM->QueryContextMenu(hMenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1126 if (FAILED(hResult))
1127 goto cleanup;
1128
1129 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1130 if (uCommand == (UINT)-1)
1131 {
1132 hResult = E_FAIL;
1133 goto cleanup;
1134 }
1135
1136 ZeroMemory(&cmi, sizeof(cmi));
1137 cmi.cbSize = sizeof(cmi);
1138 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1139 cmi.hwnd = m_hWnd;
1140
1141 hResult = m_pCM->InvokeCommand(&cmi);
1142
1143 cleanup:
1144
1145 if (hMenu)
1146 DestroyMenu(hMenu);
1147
1148 if (m_pCM)
1149 {
1150 IUnknown_SetSite(m_pCM, NULL);
1151 m_pCM.Release();
1152 }
1153
1154 return hResult;
1155 }
1156
1157 /**********************************************************
1158 * ShellView_DoContextMenu()
1159 */
1160 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1161 {
1162 WORD x;
1163 WORD y;
1164 UINT uCommand;
1165 HMENU hMenu;
1166 CMINVOKECOMMANDINFO cmi;
1167 HRESULT hResult;
1168
1169 // for some reason I haven't figured out, we sometimes recurse into this method
1170 if (m_pCM != NULL)
1171 return 0;
1172
1173 x = LOWORD(lParam);
1174 y = HIWORD(lParam);
1175
1176 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1177
1178 hMenu = CreatePopupMenu();
1179 if (!hMenu)
1180 return E_FAIL;
1181
1182 m_cidl = ListView_GetSelectedCount(m_hWndList);
1183
1184 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1185 if (FAILED( hResult))
1186 goto cleanup;
1187
1188 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1189 //if (FAILED( hResult))
1190 // goto cleanup;
1191
1192 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1193 if (FAILED( hResult))
1194 goto cleanup;
1195
1196 if (m_FolderSettings.fFlags & FWF_DESKTOP)
1197 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1198
1199 uCommand = TrackPopupMenu(hMenu,
1200 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1201 x, y, 0, m_hWnd, NULL);
1202 if (uCommand == 0)
1203 goto cleanup;
1204
1205 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1206 goto cleanup;
1207
1208 ZeroMemory(&cmi, sizeof(cmi));
1209 cmi.cbSize = sizeof(cmi);
1210 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1211 cmi.hwnd = m_hWnd;
1212 m_pCM->InvokeCommand(&cmi);
1213
1214 cleanup:
1215
1216 if (m_pCM)
1217 {
1218 IUnknown_SetSite(m_pCM, NULL);
1219 m_pCM.Release();
1220 }
1221
1222 if (hMenu)
1223 DestroyMenu(hMenu);
1224
1225 return 0;
1226 }
1227
1228 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1229 {
1230 HRESULT hResult;
1231 CMINVOKECOMMANDINFO cmi;
1232 HMENU hMenu;
1233
1234 hMenu = CreatePopupMenu();
1235 if (!hMenu)
1236 return 0;
1237
1238 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1239 if (FAILED( hResult))
1240 goto cleanup;
1241
1242 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1243 //if (FAILED( hResult))
1244 // goto cleanup;
1245
1246 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1247 if (FAILED( hResult))
1248 goto cleanup;
1249
1250 ZeroMemory(&cmi, sizeof(cmi));
1251 cmi.cbSize = sizeof(cmi);
1252 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1253 cmi.hwnd = m_hWnd;
1254 m_pCM->InvokeCommand(&cmi);
1255
1256 cleanup:
1257
1258 if (m_pCM)
1259 {
1260 IUnknown_SetSite(m_pCM, NULL);
1261 m_pCM.Release();
1262 }
1263
1264 if (hMenu)
1265 DestroyMenu(hMenu);
1266
1267 return 0;
1268 }
1269
1270 /**********************************************************
1271 * ##### message handling #####
1272 */
1273
1274 /**********************************************************
1275 * ShellView_OnSize()
1276 */
1277 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1278 {
1279 WORD wWidth;
1280 WORD wHeight;
1281
1282 wWidth = LOWORD(lParam);
1283 wHeight = HIWORD(lParam);
1284
1285 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1286
1287 /*resize the ListView to fit our window*/
1288 if (m_hWndList)
1289 {
1290 ::MoveWindow(m_hWndList, 0, 0, wWidth, wHeight, TRUE);
1291 }
1292
1293 return 0;
1294 }
1295
1296 /**********************************************************
1297 * ShellView_OnDeactivate()
1298 *
1299 * NOTES
1300 * internal
1301 */
1302 void CDefView::OnDeactivate()
1303 {
1304 TRACE("%p\n", this);
1305
1306 if (m_uState != SVUIA_DEACTIVATE)
1307 {
1308 if (m_hMenu)
1309 {
1310 m_pShellBrowser->SetMenuSB(0, 0, 0);
1311 m_pShellBrowser->RemoveMenusSB(m_hMenu);
1312 DestroyMenu(m_hMenu);
1313 m_hMenu = 0;
1314 }
1315
1316 m_uState = SVUIA_DEACTIVATE;
1317 }
1318 }
1319
1320 void CDefView::DoActivate(UINT uState)
1321 {
1322 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1323 MENUITEMINFOA mii;
1324 CHAR szText[MAX_PATH];
1325
1326 TRACE("%p uState=%x\n", this, uState);
1327
1328 /*don't do anything if the state isn't really changing */
1329 if (m_uState == uState)
1330 {
1331 return;
1332 }
1333
1334 OnDeactivate();
1335
1336 /*only do This if we are active */
1337 if(uState != SVUIA_DEACTIVATE)
1338 {
1339 /*merge the menus */
1340 m_hMenu = CreateMenu();
1341
1342 if(m_hMenu)
1343 {
1344 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
1345 TRACE("-- after fnInsertMenusSB\n");
1346
1347 /*build the top level menu get the menu item's text*/
1348 strcpy(szText, "dummy 31");
1349
1350 ZeroMemory(&mii, sizeof(mii));
1351 mii.cbSize = sizeof(mii);
1352 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1353 mii.fType = MFT_STRING;
1354 mii.fState = MFS_ENABLED;
1355 mii.dwTypeData = szText;
1356 mii.hSubMenu = BuildFileMenu();
1357
1358 /*insert our menu into the menu bar*/
1359 if (mii.hSubMenu)
1360 {
1361 InsertMenuItemA(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1362 }
1363
1364 /*get the view menu so we can merge with it*/
1365 ZeroMemory(&mii, sizeof(mii));
1366 mii.cbSize = sizeof(mii);
1367 mii.fMask = MIIM_SUBMENU;
1368
1369 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1370 {
1371 MergeViewMenu(mii.hSubMenu);
1372 }
1373
1374 /*add the items that should only be added if we have the focus*/
1375 if (SVUIA_ACTIVATE_FOCUS == uState)
1376 {
1377 /*get the file menu so we can merge with it */
1378 ZeroMemory(&mii, sizeof(mii));
1379 mii.cbSize = sizeof(mii);
1380 mii.fMask = MIIM_SUBMENU;
1381
1382 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1383 {
1384 MergeFileMenu(mii.hSubMenu);
1385 }
1386 }
1387
1388 TRACE("-- before fnSetMenuSB\n");
1389 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1390 }
1391 }
1392 m_uState = uState;
1393 TRACE("--\n");
1394 }
1395
1396 /**********************************************************
1397 * ShellView_OnActivate()
1398 */
1399 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1400 {
1401 DoActivate(SVUIA_ACTIVATE_FOCUS);
1402 return 0;
1403 }
1404
1405 /**********************************************************
1406 * ShellView_OnSetFocus()
1407 *
1408 */
1409 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1410 {
1411 TRACE("%p\n", this);
1412
1413 /* Tell the browser one of our windows has received the focus. This
1414 should always be done before merging menus (OnActivate merges the
1415 menus) if one of our windows has the focus.*/
1416
1417 m_pShellBrowser->OnViewWindowActive((IShellView *)this);
1418 DoActivate(SVUIA_ACTIVATE_FOCUS);
1419
1420 /* Set the focus to the listview */
1421 ::SetFocus(m_hWndList);
1422
1423 /* Notify the ICommDlgBrowser interface */
1424 OnStateChange(CDBOSC_SETFOCUS);
1425
1426 return 0;
1427 }
1428
1429 /**********************************************************
1430 * ShellView_OnKillFocus()
1431 */
1432 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1433 {
1434 TRACE("(%p) stub\n", this);
1435
1436 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1437 /* Notify the ICommDlgBrowser */
1438 OnStateChange(CDBOSC_KILLFOCUS);
1439
1440 return 0;
1441 }
1442
1443 /**********************************************************
1444 * ShellView_OnCommand()
1445 *
1446 * NOTES
1447 * the CmdID's are the ones from the context menu
1448 */
1449 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1450 {
1451 DWORD dwCmdID;
1452 DWORD dwCmd;
1453 HWND hwndCmd;
1454
1455 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1456 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1457 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1458
1459 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1460
1461 switch (dwCmdID)
1462 {
1463 case FCIDM_SHVIEW_SMALLICON:
1464 m_FolderSettings.ViewMode = FVM_SMALLICON;
1465 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1466 CheckToolbar();
1467 break;
1468
1469 case FCIDM_SHVIEW_BIGICON:
1470 m_FolderSettings.ViewMode = FVM_ICON;
1471 SetStyle (LVS_ICON, LVS_TYPEMASK);
1472 CheckToolbar();
1473 break;
1474
1475 case FCIDM_SHVIEW_LISTVIEW:
1476 m_FolderSettings.ViewMode = FVM_LIST;
1477 SetStyle (LVS_LIST, LVS_TYPEMASK);
1478 CheckToolbar();
1479 break;
1480
1481 case FCIDM_SHVIEW_REPORTVIEW:
1482 m_FolderSettings.ViewMode = FVM_DETAILS;
1483 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1484 CheckToolbar();
1485 break;
1486
1487 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1488 case 0x30:
1489 case 0x31:
1490 case 0x32:
1491 case 0x33:
1492 m_sortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1493 m_sortInfo.bIsAscending = TRUE;
1494 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1495 SendMessageA(m_hWndList, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1496 break;
1497
1498 case FCIDM_SHVIEW_REFRESH:
1499 Refresh();
1500 break;
1501
1502 case FCIDM_SHVIEW_DELETE:
1503 case FCIDM_SHVIEW_CUT:
1504 case FCIDM_SHVIEW_COPY:
1505 case FCIDM_SHVIEW_RENAME:
1506 return OnExplorerCommand(dwCmdID, TRUE);
1507
1508 case FCIDM_SHVIEW_INSERT:
1509 case FCIDM_SHVIEW_UNDO:
1510 case FCIDM_SHVIEW_INSERTLINK:
1511 case FCIDM_SHVIEW_NEWFOLDER:
1512 return OnExplorerCommand(dwCmdID, FALSE);
1513 default:
1514 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1515 }
1516
1517 return 0;
1518 }
1519
1520 /**********************************************************
1521 * ShellView_OnNotify()
1522 */
1523
1524 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1525 {
1526 UINT CtlID;
1527 LPNMHDR lpnmh;
1528 LPNMLISTVIEW lpnmlv;
1529 NMLVDISPINFOW *lpdi;
1530 LPITEMIDLIST pidl;
1531 BOOL unused;
1532
1533 CtlID = wParam;
1534 lpnmh = (LPNMHDR)lParam;
1535 lpnmlv = (LPNMLISTVIEW)lpnmh;
1536 lpdi = (NMLVDISPINFOW *)lpnmh;
1537
1538 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1539
1540 switch (lpnmh->code)
1541 {
1542 case NM_SETFOCUS:
1543 TRACE("-- NM_SETFOCUS %p\n", this);
1544 OnSetFocus(0, 0, 0, unused);
1545 break;
1546
1547 case NM_KILLFOCUS:
1548 TRACE("-- NM_KILLFOCUS %p\n", this);
1549 OnDeactivate();
1550 /* Notify the ICommDlgBrowser interface */
1551 OnStateChange(CDBOSC_KILLFOCUS);
1552 break;
1553
1554 case NM_CUSTOMDRAW:
1555 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1556 return CDRF_DODEFAULT;
1557
1558 case NM_RELEASEDCAPTURE:
1559 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1560 break;
1561
1562 case NM_CLICK:
1563 TRACE("-- NM_CLICK %p\n", this);
1564 break;
1565
1566 case NM_RCLICK:
1567 TRACE("-- NM_RCLICK %p\n", this);
1568 break;
1569
1570 case NM_DBLCLK:
1571 TRACE("-- NM_DBLCLK %p\n", this);
1572 OpenSelectedItems();
1573 break;
1574
1575 case NM_RETURN:
1576 TRACE("-- NM_RETURN %p\n", this);
1577 OpenSelectedItems();
1578 break;
1579
1580 case HDN_ENDTRACKW:
1581 TRACE("-- HDN_ENDTRACKW %p\n", this);
1582 /*nColumn1 = ListView_GetColumnWidth(m_hWndList, 0);
1583 nColumn2 = ListView_GetColumnWidth(m_hWndList, 1);*/
1584 break;
1585
1586 case LVN_DELETEITEM:
1587 TRACE("-- LVN_DELETEITEM %p\n", this);
1588 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1589 break;
1590
1591 case LVN_DELETEALLITEMS:
1592 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1593 return FALSE;
1594
1595 case LVN_INSERTITEM:
1596 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1597 break;
1598
1599 case LVN_ITEMACTIVATE:
1600 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1601 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1602 break;
1603
1604 case LVN_COLUMNCLICK:
1605 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1606 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1607 {
1608 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1609 }
1610 else
1611 {
1612 m_sortInfo.bIsAscending = TRUE;
1613 }
1614 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1615
1616 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1617 break;
1618
1619 case LVN_GETDISPINFOA:
1620 case LVN_GETDISPINFOW:
1621 TRACE("-- LVN_GETDISPINFO %p\n", this);
1622 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1623
1624 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1625 {
1626 if (m_pSF2Parent)
1627 {
1628 SHELLDETAILS sd;
1629 if (FAILED(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1630 {
1631 FIXME("failed to get details\n");
1632 break;
1633 }
1634
1635 if (lpnmh->code == LVN_GETDISPINFOA)
1636 {
1637 /* shouldn't happen */
1638 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1639 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1640 TRACE("-- text=%s\n", lpdiA->item.pszText);
1641 }
1642 else /* LVN_GETDISPINFOW */
1643 {
1644 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1645 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1646 }
1647 }
1648 else
1649 {
1650 FIXME("no SF2\n");
1651 }
1652 }
1653 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1654 {
1655 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1656 }
1657 lpdi->item.mask |= LVIF_DI_SETITEM;
1658 break;
1659
1660 case LVN_ITEMCHANGED:
1661 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1662 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1663 break;
1664
1665 case LVN_BEGINDRAG:
1666 case LVN_BEGINRDRAG:
1667 TRACE("-- LVN_BEGINDRAG\n");
1668
1669 if (GetSelections())
1670 {
1671 IDataObject * pda;
1672 DWORD dwAttributes = SFGAO_CANLINK;
1673 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1674
1675 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1676 {
1677 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1678
1679 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, (LPCITEMIDLIST*)m_apidl, &dwAttributes)))
1680 {
1681 if (dwAttributes & SFGAO_CANLINK)
1682 {
1683 dwEffect |= DROPEFFECT_LINK;
1684 }
1685 }
1686
1687 if (pds)
1688 {
1689 DWORD dwEffect2;
1690 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1691 }
1692 pda->Release();
1693 }
1694 }
1695 break;
1696
1697 case LVN_BEGINLABELEDITW:
1698 {
1699 DWORD dwAttr = SFGAO_CANRENAME;
1700 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1701
1702 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1703
1704 m_pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1705 if (SFGAO_CANRENAME & dwAttr)
1706 {
1707 return FALSE;
1708 }
1709 return TRUE;
1710 }
1711
1712 case LVN_ENDLABELEDITW:
1713 {
1714 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1715 if (lpdi->item.pszText)
1716 {
1717 HRESULT hr;
1718 LVITEMW lvItem;
1719
1720 lvItem.iItem = lpdi->item.iItem;
1721 lvItem.iSubItem = 0;
1722 lvItem.mask = LVIF_PARAM;
1723 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1724
1725 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1726 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1727
1728 if (SUCCEEDED(hr) && pidl)
1729 {
1730 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1731 lvItem.lParam = (LPARAM)pidl;
1732 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1733 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1734 SendMessageW(m_hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1735
1736 return TRUE;
1737 }
1738 }
1739
1740 return FALSE;
1741 }
1742
1743 case LVN_KEYDOWN:
1744 {
1745 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1746
1747 /* initiate a rename of the selected file or directory */
1748 if (plvKeyDown->wVKey == VK_BACK)
1749 {
1750 LPSHELLBROWSER lpSb;
1751 if ((lpSb = (LPSHELLBROWSER)SendMessageW(m_hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1752 {
1753 lpSb->BrowseObject(NULL, SBSP_PARENT);
1754 }
1755 }
1756
1757 else
1758 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
1759 }
1760 break;
1761
1762 default:
1763 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1764 break;
1765 }
1766
1767 return 0;
1768 }
1769
1770 /**********************************************************
1771 * ShellView_OnChange()
1772 */
1773 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1774 {
1775 LPITEMIDLIST *Pidls;
1776
1777 Pidls = (LPITEMIDLIST *)wParam;
1778
1779 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1780
1781 switch (lParam)
1782 {
1783 case SHCNE_MKDIR:
1784 case SHCNE_CREATE:
1785 LV_AddItem(Pidls[0]);
1786 break;
1787
1788 case SHCNE_RMDIR:
1789 case SHCNE_DELETE:
1790 LV_DeleteItem(Pidls[0]);
1791 break;
1792
1793 case SHCNE_RENAMEFOLDER:
1794 case SHCNE_RENAMEITEM:
1795 LV_RenameItem(Pidls[0], Pidls[1]);
1796 break;
1797
1798 case SHCNE_UPDATEITEM:
1799 break;
1800 }
1801
1802 return TRUE;
1803 }
1804
1805 /**********************************************************
1806 * CDefView::OnCustomItem
1807 */
1808 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1809 {
1810 if (!m_pCM.p)
1811 {
1812 /* no menu */
1813 ERR("no menu!!!\n");
1814 return FALSE;
1815 }
1816
1817 CComPtr<IContextMenu2> pCM2;
1818 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1819 if(FAILED(hres))
1820 return FALSE;
1821
1822 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1823 return TRUE;
1824 else
1825 return FALSE;
1826 }
1827
1828 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1829 {
1830 /* Wallpaper setting affects drop shadows effect */
1831 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1832 UpdateListColors();
1833
1834 return S_OK;
1835 }
1836
1837 /**********************************************************
1838 *
1839 *
1840 * The INTERFACE of the IShellView object
1841 *
1842 *
1843 **********************************************************
1844 */
1845
1846 /**********************************************************
1847 * ShellView_GetWindow
1848 */
1849 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1850 {
1851 TRACE("(%p)\n", this);
1852
1853 *phWnd = m_hWnd;
1854
1855 return S_OK;
1856 }
1857
1858 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1859 {
1860 FIXME("(%p) stub\n", this);
1861
1862 return E_NOTIMPL;
1863 }
1864
1865 /**********************************************************
1866 * IShellView_TranslateAccelerator
1867 *
1868 * FIXME:
1869 * use the accel functions
1870 */
1871 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1872 {
1873 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1874 {
1875 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1876 return S_OK;
1877
1878 /* FIXME: should call TranslateAcceleratorSB */
1879
1880 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1881 }
1882
1883 return S_FALSE; /* not handled */
1884 }
1885
1886 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1887 {
1888 FIXME("(%p) stub\n", this);
1889
1890 return E_NOTIMPL;
1891 }
1892
1893 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1894 {
1895 /*
1896 CHAR szName[MAX_PATH];
1897 */
1898 LRESULT lResult;
1899 int nPartArray[1] = { -1};
1900
1901 TRACE("(%p)->(state=%x) stub\n", this, uState);
1902
1903 /*don't do anything if the state isn't really changing*/
1904 if (m_uState == uState)
1905 {
1906 return S_OK;
1907 }
1908
1909 /*OnActivate handles the menu merging and internal state*/
1910 DoActivate(uState);
1911
1912 /*only do This if we are active*/
1913 if (uState != SVUIA_DEACTIVATE)
1914 {
1915
1916 /*
1917 GetFolderPath is not a method of IShellFolder
1918 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1919 */
1920 /* set the number of parts */
1921 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1922
1923 /* set the text for the parts */
1924 /*
1925 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1926 */
1927 }
1928
1929 return S_OK;
1930 }
1931
1932 HRESULT WINAPI CDefView::Refresh()
1933 {
1934 TRACE("(%p)\n", this);
1935
1936 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1937 FillList();
1938
1939 return S_OK;
1940 }
1941
1942 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1943 {
1944 *phWnd = 0;
1945
1946 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1947
1948 if (lpfs != NULL)
1949 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1950 if (prcView != NULL)
1951 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1952
1953 /* Validate the Shell Browser */
1954 if (psb == NULL)
1955 return E_UNEXPECTED;
1956
1957 /*set up the member variables*/
1958 m_pShellBrowser = psb;
1959 m_FolderSettings = *lpfs;
1960
1961 /*get our parent window*/
1962 m_pShellBrowser->GetWindow(&m_hWndParent);
1963
1964 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
1965 m_pCommDlgBrowser = NULL;
1966 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
1967 {
1968 TRACE("-- CommDlgBrowser\n");
1969 }
1970
1971 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
1972 if (m_hWnd == NULL)
1973 return E_FAIL;
1974
1975 *phWnd = m_hWnd;
1976
1977 CheckToolbar();
1978
1979 if (!*phWnd)
1980 return E_FAIL;
1981
1982 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1983 UpdateWindow();
1984
1985 return S_OK;
1986 }
1987
1988 HRESULT WINAPI CDefView::DestroyViewWindow()
1989 {
1990 TRACE("(%p)\n", this);
1991
1992 /*Make absolutely sure all our UI is cleaned up.*/
1993 UIActivate(SVUIA_DEACTIVATE);
1994
1995 if (m_hMenu)
1996 {
1997 DestroyMenu(m_hMenu);
1998 }
1999
2000 DestroyWindow();
2001 m_pShellBrowser.Release();
2002 m_pCommDlgBrowser.Release();
2003
2004 return S_OK;
2005 }
2006
2007 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2008 {
2009 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2010 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2011
2012 if (!lpfs)
2013 return E_INVALIDARG;
2014
2015 *lpfs = m_FolderSettings;
2016 return S_OK;
2017 }
2018
2019 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2020 {
2021 FIXME("(%p) stub\n", this);
2022
2023 return E_NOTIMPL;
2024 }
2025
2026 HRESULT WINAPI CDefView::SaveViewState()
2027 {
2028 FIXME("(%p) stub\n", this);
2029
2030 return S_OK;
2031 }
2032
2033 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2034 {
2035 int i;
2036
2037 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2038
2039 i = LV_FindItemByPidl(pidl);
2040
2041 if (i != -1)
2042 {
2043 LVITEMW lvItem;
2044
2045 if(uFlags & SVSI_ENSUREVISIBLE)
2046 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2047
2048 lvItem.mask = LVIF_STATE;
2049 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2050 lvItem.iItem = 0;
2051 lvItem.iSubItem = 0;
2052
2053 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2054 {
2055 if (lvItem.iItem == i)
2056 {
2057 if (uFlags & SVSI_SELECT)
2058 lvItem.state |= LVIS_SELECTED;
2059 else
2060 lvItem.state &= ~LVIS_SELECTED;
2061
2062 if (uFlags & SVSI_FOCUSED)
2063 lvItem.state &= ~LVIS_FOCUSED;
2064 }
2065 else
2066 {
2067 if (uFlags & SVSI_DESELECTOTHERS)
2068 lvItem.state &= ~LVIS_SELECTED;
2069 }
2070
2071 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2072 lvItem.iItem++;
2073 }
2074
2075
2076 if(uFlags & SVSI_EDIT)
2077 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2078 }
2079
2080 return S_OK;
2081 }
2082
2083 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2084 {
2085 HRESULT hr = E_NOINTERFACE;
2086
2087 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2088
2089 *ppvOut = NULL;
2090
2091 switch (uItem)
2092 {
2093 case SVGIO_BACKGROUND:
2094 if (IsEqualIID(riid, IID_IContextMenu))
2095 {
2096 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2097 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2098 if (!ppvOut)
2099 hr = E_OUTOFMEMORY;
2100 else
2101 hr = S_OK;
2102 }
2103 break;
2104
2105 case SVGIO_SELECTION:
2106 GetSelections();
2107 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2108 break;
2109 }
2110
2111 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2112
2113 return hr;
2114 }
2115
2116 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2117 {
2118 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2119
2120 if (!pViewMode)
2121 return E_INVALIDARG;
2122
2123 *pViewMode = m_FolderSettings.ViewMode;
2124 return S_OK;
2125 }
2126
2127 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2128 {
2129 DWORD dwStyle;
2130 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2131
2132 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2133 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2134 return E_INVALIDARG;
2135
2136 /* Windows before Vista uses LVM_SETVIEW and possibly
2137 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2138 while later versions seem to accomplish this through other
2139 means. */
2140 switch (ViewMode)
2141 {
2142 case FVM_ICON:
2143 dwStyle = LVS_ICON;
2144 break;
2145 case FVM_DETAILS:
2146 dwStyle = LVS_REPORT;
2147 break;
2148 case FVM_SMALLICON:
2149 dwStyle = LVS_SMALLICON;
2150 break;
2151 case FVM_LIST:
2152 dwStyle = LVS_LIST;
2153 break;
2154 default:
2155 {
2156 FIXME("ViewMode %d not implemented\n", ViewMode);
2157 dwStyle = LVS_LIST;
2158 break;
2159 }
2160 }
2161
2162 SetStyle(dwStyle, LVS_TYPEMASK);
2163
2164 /* This will not necessarily be the actual mode set above.
2165 This mimics the behavior of Windows XP. */
2166 m_FolderSettings.ViewMode = ViewMode;
2167
2168 return S_OK;
2169 }
2170
2171 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2172 {
2173 if (m_pSFParent == NULL)
2174 return E_FAIL;
2175
2176 return m_pSFParent->QueryInterface(riid, ppv);
2177 }
2178
2179 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2180 {
2181 LVITEMW item;
2182
2183 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2184
2185 item.mask = LVIF_PARAM;
2186 item.iItem = iItemIndex;
2187
2188 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2189 {
2190 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2191 return S_OK;
2192 }
2193
2194 *ppidl = 0;
2195
2196 return E_INVALIDARG;
2197 }
2198
2199 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2200 {
2201 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2202
2203 if (uFlags != SVGIO_ALLVIEW)
2204 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2205
2206 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2207
2208 return S_OK;
2209 }
2210
2211 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2212 {
2213 return E_NOTIMPL;
2214 }
2215
2216 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2217 {
2218 TRACE("(%p)->(%p)\n", this, piItem);
2219
2220 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2221
2222 return S_OK;
2223 }
2224
2225 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2226 {
2227 TRACE("(%p)->(%p)\n", this, piItem);
2228
2229 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2230
2231 return S_OK;
2232 }
2233
2234 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2235 {
2236 return E_NOTIMPL;
2237 }
2238
2239 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2240 {
2241 TRACE("(%p)->(%p)\n", this, ppt);
2242
2243 if (NULL == m_hWndList) return S_FALSE;
2244
2245 if (ppt)
2246 {
2247 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2248
2249 ppt->x = LOWORD(ret);
2250 ppt->y = HIWORD(ret);
2251 }
2252
2253 return S_OK;
2254 }
2255
2256 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2257 {
2258 return E_NOTIMPL;
2259 }
2260
2261 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2262 {
2263 return E_NOTIMPL;
2264 }
2265
2266 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2267 {
2268 LVITEMW lvItem;
2269
2270 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2271
2272 lvItem.state = 0;
2273 lvItem.stateMask = LVIS_SELECTED;
2274
2275 if (dwFlags & SVSI_ENSUREVISIBLE)
2276 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2277
2278 /* all items */
2279 if (dwFlags & SVSI_DESELECTOTHERS)
2280 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2281
2282 /* this item */
2283 if (dwFlags & SVSI_SELECT)
2284 lvItem.state |= LVIS_SELECTED;
2285
2286 if (dwFlags & SVSI_FOCUSED)
2287 lvItem.stateMask |= LVIS_FOCUSED;
2288
2289 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2290
2291 if (dwFlags & SVSI_EDIT)
2292 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2293
2294 return S_OK;
2295 }
2296
2297 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2298 {
2299 return E_NOTIMPL;
2300 }
2301
2302 /**********************************************************
2303 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2304 */
2305 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2306 {
2307 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2308 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2309
2310 if (!prgCmds)
2311 return E_INVALIDARG;
2312
2313 for (UINT i = 0; i < cCmds; i++)
2314 {
2315 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2316 prgCmds[i].cmdf = 0;
2317 }
2318
2319 return OLECMDERR_E_UNKNOWNGROUP;
2320 }
2321
2322 /**********************************************************
2323 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2324 *
2325 * nCmdID is the OLECMDID_* enumeration
2326 */
2327 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2328 {
2329 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2330 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2331
2332 if (!pguidCmdGroup)
2333 return OLECMDERR_E_UNKNOWNGROUP;
2334
2335 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2336 (nCmdID == 0x29) &&
2337 (nCmdexecopt == 4) && pvaOut)
2338 return S_OK;
2339
2340 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2341 (nCmdID == 9) &&
2342 (nCmdexecopt == 0))
2343 return 1;
2344
2345 return OLECMDERR_E_UNKNOWNGROUP;
2346 }
2347
2348 /**********************************************************
2349 * ISVDropTarget implementation
2350 */
2351
2352 /******************************************************************************
2353 * drag_notify_subitem [Internal]
2354 *
2355 * Figure out the shellfolder object, which is currently under the mouse cursor
2356 * and notify it via the IDropTarget interface.
2357 */
2358
2359 #define SCROLLAREAWIDTH 20
2360
2361 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2362 {
2363 LVHITTESTINFO htinfo;
2364 LVITEMW lvItem;
2365 LONG lResult;
2366 HRESULT hr;
2367 RECT clientRect;
2368
2369 /* Map from global to client coordinates and query the index of the listview-item, which is
2370 * currently under the mouse cursor. */
2371 htinfo.pt.x = pt.x;
2372 htinfo.pt.y = pt.y;
2373 htinfo.flags = LVHT_ONITEM;
2374 ::ScreenToClient(m_hWndList, &htinfo.pt);
2375 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2376
2377 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2378 ::GetClientRect(m_hWndList, &clientRect);
2379 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2380 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2381 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2382 {
2383 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2384 if (m_cScrollDelay == 0)
2385 {
2386 /* Mouse did hover another 250 ms over the scroll-area */
2387 if (htinfo.pt.x < SCROLLAREAWIDTH)
2388 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2389
2390 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2391 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2392
2393 if (htinfo.pt.y < SCROLLAREAWIDTH)
2394 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2395
2396 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2397 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2398 }
2399 }
2400 else
2401 {
2402 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2403 }
2404
2405 m_ptLastMousePos = htinfo.pt;
2406
2407 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2408 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2409 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2410
2411 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2412 if (m_pCurDropTarget)
2413 {
2414 m_pCurDropTarget->DragLeave();
2415 m_pCurDropTarget.Release();
2416 }
2417
2418 m_iDragOverItem = lResult;
2419 if (lResult == -1)
2420 {
2421 /* We are not above one of the listview's subitems. Bind to the parent folder's
2422 * DropTarget interface. */
2423 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2424 }
2425 else
2426 {
2427 /* Query the relative PIDL of the shellfolder object represented by the currently
2428 * dragged over listview-item ... */
2429 lvItem.mask = LVIF_PARAM;
2430 lvItem.iItem = lResult;
2431 lvItem.iSubItem = 0;
2432 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2433
2434 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2435 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1,
2436 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&m_pCurDropTarget);
2437 }
2438
2439 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2440 if (FAILED(hr))
2441 return hr;
2442
2443 /* Notify the item just entered via DragEnter. */
2444 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2445 }
2446
2447 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2448 {
2449 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2450 m_pCurDataObject = pDataObject;
2451 pDataObject->AddRef();
2452
2453 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2454 }
2455
2456 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2457 {
2458 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2459 }
2460
2461 HRESULT WINAPI CDefView::DragLeave()
2462 {
2463 if (m_pCurDropTarget)
2464 {
2465 m_pCurDropTarget->DragLeave();
2466 m_pCurDropTarget.Release();
2467 }
2468
2469 if (m_pCurDataObject != NULL)
2470 {
2471 m_pCurDataObject.Release();
2472 }
2473
2474 m_iDragOverItem = 0;
2475
2476 return S_OK;
2477 }
2478
2479 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2480 {
2481 if (m_pCurDropTarget)
2482 {
2483 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2484 m_pCurDropTarget.Release();
2485 }
2486
2487 m_pCurDataObject.Release();
2488 m_iDragOverItem = 0;
2489
2490 return S_OK;
2491 }
2492
2493 /**********************************************************
2494 * ISVDropSource implementation
2495 */
2496
2497 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2498 {
2499 TRACE("(%p)\n", this);
2500
2501 if (fEscapePressed)
2502 return DRAGDROP_S_CANCEL;
2503 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2504 return DRAGDROP_S_DROP;
2505 else
2506 return S_OK;
2507 }
2508
2509 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2510 {
2511 TRACE("(%p)\n", this);
2512
2513 return DRAGDROP_S_USEDEFAULTCURSORS;
2514 }
2515
2516 /**********************************************************
2517 * ISVViewObject implementation
2518 */
2519
2520 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)
2521 {
2522 FIXME("Stub: this=%p\n", this);
2523
2524 return E_NOTIMPL;
2525 }
2526
2527 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2528 {
2529 FIXME("Stub: this=%p\n", this);
2530
2531 return E_NOTIMPL;
2532 }
2533
2534 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2535 {
2536 FIXME("Stub: this=%p\n", this);
2537
2538 return E_NOTIMPL;
2539 }
2540
2541 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2542 {
2543 FIXME("Stub: this=%p\n", this);
2544
2545 return E_NOTIMPL;
2546 }
2547
2548 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2549 {
2550 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2551
2552 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2553 m_pAdvSink = pAdvSink;
2554 m_dwAspects = aspects;
2555 m_dwAdvf = advf;
2556
2557 return S_OK;
2558 }
2559
2560 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2561 {
2562 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2563
2564 if (ppAdvSink)
2565 {
2566 *ppAdvSink = m_pAdvSink;
2567 m_pAdvSink.p->AddRef();
2568 }
2569
2570 if (pAspects)
2571 *pAspects = m_dwAspects;
2572
2573 if (pAdvf)
2574 *pAdvf = m_dwAdvf;
2575
2576 return S_OK;
2577 }
2578
2579 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2580 {
2581 if (IsEqualIID(guidService, SID_IShellBrowser))
2582 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2583 else if(IsEqualIID(guidService, SID_IFolderView))
2584 return QueryInterface(riid, ppvObject);
2585
2586 return E_NOINTERFACE;
2587 }
2588
2589 /**********************************************************
2590 * IShellView_Constructor
2591 */
2592 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2593 {
2594 CComObject<CDefView> *theView;
2595 CComPtr<IShellView> result;
2596 HRESULT hResult;
2597
2598 if (newView == NULL)
2599 return E_POINTER;
2600
2601 *newView = NULL;
2602 ATLTRY (theView = new CComObject<CDefView>);
2603
2604 if (theView == NULL)
2605 return E_OUTOFMEMORY;
2606
2607 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2608 if (FAILED (hResult))
2609 {
2610 delete theView;
2611 return hResult;
2612 }
2613
2614 hResult = theView->Initialize (pFolder);
2615 if (FAILED (hResult))
2616 return hResult;
2617 *newView = result.Detach ();
2618
2619 return S_OK;
2620 }