[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> pSFParent;
80 CComPtr<IShellFolder2> pSF2Parent;
81 CComPtr<IShellBrowser> pShellBrowser;
82 CComPtr<ICommDlgBrowser> pCommDlgBrowser;
83 HWND hWndList; /* ListView control */
84 HWND hWndParent;
85 FOLDERSETTINGS FolderSettings;
86 HMENU hMenu;
87 UINT uState;
88 UINT cidl;
89 LPITEMIDLIST *apidl;
90 LISTVIEW_SORT_INFO ListViewSortInfo;
91 ULONG hNotify; /* change notification handle */
92 HACCEL hAccel;
93 DWORD dwAspects;
94 DWORD dwAdvf;
95 CComPtr<IAdviseSink> pAdvSink;
96 // for drag and drop
97 CComPtr<IDropTarget> pCurDropTarget; /* The sub-item, which is currently dragged over */
98 CComPtr<IDataObject> pCurDataObject; /* The dragged data-object */
99 LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */
100 UINT cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
101 POINT ptLastMousePos; /* Mouse position at last DragOver call */
102 //
103 CComPtr<IContextMenu2> 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 hWndList = NULL;
323 hWndParent = NULL;
324 FolderSettings.fFlags = 0;
325 FolderSettings.ViewMode = 0;
326 hMenu = NULL;
327 uState = 0;
328 cidl = 0;
329 apidl = NULL;
330 ListViewSortInfo.bIsAscending = FALSE;
331 ListViewSortInfo.nHeaderID = 0;
332 ListViewSortInfo.nLastHeaderID = 0;
333 hNotify = 0;
334 hAccel = NULL;
335 dwAspects = 0;
336 dwAdvf = 0;
337 iDragOverItem = 0;
338 cScrollDelay = 0;
339 ptLastMousePos.x = 0;
340 ptLastMousePos.y = 0;
341 }
342
343 CDefView::~CDefView()
344 {
345 TRACE(" destroying IShellView(%p)\n", this);
346
347 SHFree(apidl);
348 }
349
350 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
351 {
352 pSFParent = shellFolder;
353 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &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 (pCommDlgBrowser.p != NULL)
367 {
368 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
369 ret = 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 (pCommDlgBrowser.p != NULL)
381 {
382 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
383 ret = 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 (pCommDlgBrowser.p != NULL)
395 {
396 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
397 ret = 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 (pCommDlgBrowser != NULL)
416 {
417 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
418 FCIDM_TB_SMALLICON, (FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result);
419 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
420 FCIDM_TB_REPORTVIEW, (FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result);
421 pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
422 FCIDM_TB_SMALLICON, TRUE, &result);
423 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(hWndList, GWL_STYLE);
442 ::SetWindowLongPtrW(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 (FolderSettings.fFlags & FWF_DESKTOP)
460 dwStyle |= LVS_ALIGNLEFT;
461 else
462 dwStyle |= LVS_ALIGNTOP;
463
464 switch (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 (FolderSettings.fFlags & FWF_AUTOARRANGE)
488 dwStyle |= LVS_AUTOARRANGE;
489
490 if (FolderSettings.fFlags & FWF_DESKTOP)
491 FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
492
493 if (FolderSettings.fFlags & FWF_SINGLESEL)
494 dwStyle |= LVS_SINGLESEL;
495
496 if (FolderSettings.fFlags & FWF_NOCLIENTEDGE)
497 dwExStyle &= ~WS_EX_CLIENTEDGE;
498
499 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 (!hWndList)
510 return FALSE;
511
512 ListViewSortInfo.bIsAscending = TRUE;
513 ListViewSortInfo.nHeaderID = -1;
514 ListViewSortInfo.nLastHeaderID = -1;
515
516 UpdateListColors();
517
518 /* UpdateShellSettings(); */
519 return TRUE;
520 }
521
522 void CDefView::UpdateListColors()
523 {
524 if (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(hWndList, LVM_SETTEXTBKCOLOR, 0, CLR_NONE);
536 SendMessageW(hWndList, LVM_SETBKCOLOR, 0, CLR_NONE);
537 SendMessageW(hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
538 SendMessageW(hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
539 }
540 else
541 {
542 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP);
543 SendMessageW(hWndList, LVM_SETTEXTBKCOLOR, 0, crDesktop);
544 SendMessageW(hWndList, LVM_SETBKCOLOR, 0, crDesktop);
545 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
546 SendMessageW(hWndList, LVM_SETTEXTCOLOR, 0, RGB(0, 0, 0));
547 else
548 SendMessageW(hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
549 SendMessageW(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(hWndList, LVM_DELETEALLITEMS, 0, 0);
568
569 lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
570 lvColumn.pszText = szTemp;
571
572 if (pSF2Parent)
573 {
574 for (int i = 0; 1; i++)
575 {
576 if (FAILED(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(hWndList, LVM_INSERTCOLUMNW, i, (LPARAM) &lvColumn);
583 }
584 }
585 else
586 {
587 FIXME("no SF2\n");
588 }
589
590 SendMessageW(hWndList, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)ShellSmallIconList);
591 SendMessageW(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(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
727 lvItem.iItem++)
728 {
729 LPITEMIDLIST currentpidl = (LPITEMIDLIST) lvItem.lParam;
730 HRESULT hr = 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(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(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(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(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(pSFParent, pidlNew, 0);
799 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
800 SendMessageW(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 = 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)pSFParent.p);
863
864 /*turn the listview's redrawing off*/
865 SendMessageA(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(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(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(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(hNotify);
893 bHandled = FALSE;
894 return 0;
895 }
896
897 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
898 {
899 if (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(hWndList, uMsg, 0, 0);
913 }
914
915 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
916 {
917 return (LRESULT)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 pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
944 if (ppf2)
945 {
946 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
947 ntreg.fRecursive = TRUE;
948 hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
949 SHFree((LPITEMIDLIST)ntreg.pidl);
950 }
951
952 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 this->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(apidl);
1062
1063 cidl = ListView_GetSelectedCount(hWndList);
1064 apidl = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1065
1066 TRACE("selected=%i\n", cidl);
1067
1068 if (apidl)
1069 {
1070 TRACE("-- Items selected =%u\n", 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(hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < cidl))
1079 {
1080 if(lvItem.state & LVIS_SELECTED)
1081 {
1082 apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1083 i++;
1084 if (i == cidl)
1085 break;
1086 TRACE("-- selected Item found\n");
1087 }
1088 lvItem.iItem++;
1089 }
1090 }
1091
1092 return 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 cidl = ListView_GetSelectedCount(hWndList);
1106 if (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(IContextMenu2, &pCM));
1118 if (FAILED(hResult))
1119 goto cleanup;
1120
1121 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1122 //if (FAILED( hResult))
1123 // goto cleanup;
1124
1125 hResult = 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 = pCM->InvokeCommand(&cmi);
1142
1143 cleanup:
1144
1145 if (hMenu)
1146 DestroyMenu(hMenu);
1147
1148 if (pCM)
1149 {
1150 IUnknown_SetSite(pCM, NULL);
1151 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 (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 cidl = ListView_GetSelectedCount(hWndList);
1183
1184 hResult = GetItemObject( cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu2, &pCM));
1185 if (FAILED( hResult))
1186 goto cleanup;
1187
1188 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1189 //if (FAILED( hResult))
1190 // goto cleanup;
1191
1192 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1193 if (FAILED( hResult))
1194 goto cleanup;
1195
1196 if (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 pCM->InvokeCommand(&cmi);
1213
1214 cleanup:
1215
1216 if (pCM)
1217 {
1218 IUnknown_SetSite(pCM, NULL);
1219 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(IContextMenu2, &pCM));
1239 if (FAILED( hResult))
1240 goto cleanup;
1241
1242 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1243 //if (FAILED( hResult))
1244 // goto cleanup;
1245
1246 hResult = 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 pCM->InvokeCommand(&cmi);
1255
1256 cleanup:
1257
1258 if (pCM)
1259 {
1260 IUnknown_SetSite(pCM, NULL);
1261 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 (hWndList)
1289 {
1290 ::MoveWindow(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 (uState != SVUIA_DEACTIVATE)
1307 {
1308 if (hMenu)
1309 {
1310 pShellBrowser->SetMenuSB(0, 0, 0);
1311 pShellBrowser->RemoveMenusSB(hMenu);
1312 DestroyMenu(hMenu);
1313 hMenu = 0;
1314 }
1315
1316 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 (this->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 hMenu = CreateMenu();
1341
1342 if(hMenu)
1343 {
1344 pShellBrowser->InsertMenusSB(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(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(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(hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1383 {
1384 MergeFileMenu(mii.hSubMenu);
1385 }
1386 }
1387
1388 TRACE("-- before fnSetMenuSB\n");
1389 pShellBrowser->SetMenuSB(hMenu, 0, m_hWnd);
1390 }
1391 }
1392 this->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 pShellBrowser->OnViewWindowActive((IShellView *)this);
1418 DoActivate(SVUIA_ACTIVATE_FOCUS);
1419
1420 /* Set the focus to the listview */
1421 ::SetFocus(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 FolderSettings.ViewMode = FVM_SMALLICON;
1465 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1466 CheckToolbar();
1467 break;
1468
1469 case FCIDM_SHVIEW_BIGICON:
1470 FolderSettings.ViewMode = FVM_ICON;
1471 SetStyle (LVS_ICON, LVS_TYPEMASK);
1472 CheckToolbar();
1473 break;
1474
1475 case FCIDM_SHVIEW_LISTVIEW:
1476 FolderSettings.ViewMode = FVM_LIST;
1477 SetStyle (LVS_LIST, LVS_TYPEMASK);
1478 CheckToolbar();
1479 break;
1480
1481 case FCIDM_SHVIEW_REPORTVIEW:
1482 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 ListViewSortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1493 ListViewSortInfo.bIsAscending = TRUE;
1494 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1495 SendMessageA(hWndList, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (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(hWndList, 0);
1583 nColumn2 = ListView_GetColumnWidth(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 ListViewSortInfo.nHeaderID = lpnmlv->iSubItem;
1606 if (ListViewSortInfo.nLastHeaderID == ListViewSortInfo.nHeaderID)
1607 {
1608 ListViewSortInfo.bIsAscending = !ListViewSortInfo.bIsAscending;
1609 }
1610 else
1611 {
1612 ListViewSortInfo.bIsAscending = TRUE;
1613 }
1614 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1615
1616 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (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 (pSF2Parent)
1627 {
1628 SHELLDETAILS sd;
1629 if (FAILED(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(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(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1676 {
1677 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1678
1679 if (SUCCEEDED(pSFParent->GetAttributesOf(cidl, (LPCITEMIDLIST*)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 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(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1724
1725 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1726 hr = 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(pSFParent, pidl, 0);
1733 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1734 SendMessageW(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(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 (!pCM.p)
1811 {
1812 /* no menu */
1813 ERR("no menu!!!\n");
1814 return FALSE;
1815 }
1816
1817 if (pCM.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1818 return TRUE;
1819 else
1820 return FALSE;
1821 }
1822
1823 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1824 {
1825 /* Wallpaper setting affects drop shadows effect */
1826 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1827 UpdateListColors();
1828
1829 return S_OK;
1830 }
1831
1832 /**********************************************************
1833 *
1834 *
1835 * The INTERFACE of the IShellView object
1836 *
1837 *
1838 **********************************************************
1839 */
1840
1841 /**********************************************************
1842 * ShellView_GetWindow
1843 */
1844 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1845 {
1846 TRACE("(%p)\n", this);
1847
1848 *phWnd = m_hWnd;
1849
1850 return S_OK;
1851 }
1852
1853 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1854 {
1855 FIXME("(%p) stub\n", this);
1856
1857 return E_NOTIMPL;
1858 }
1859
1860 /**********************************************************
1861 * IShellView_TranslateAccelerator
1862 *
1863 * FIXME:
1864 * use the accel functions
1865 */
1866 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1867 {
1868 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1869 {
1870 if (::TranslateAcceleratorW(m_hWnd, hAccel, lpmsg) != 0)
1871 return S_OK;
1872
1873 /* FIXME: should call TranslateAcceleratorSB */
1874
1875 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1876 }
1877
1878 return S_FALSE; /* not handled */
1879 }
1880
1881 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1882 {
1883 FIXME("(%p) stub\n", this);
1884
1885 return E_NOTIMPL;
1886 }
1887
1888 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1889 {
1890 /*
1891 CHAR szName[MAX_PATH];
1892 */
1893 LRESULT lResult;
1894 int nPartArray[1] = { -1};
1895
1896 TRACE("(%p)->(state=%x) stub\n", this, uState);
1897
1898 /*don't do anything if the state isn't really changing*/
1899 if (this->uState == uState)
1900 {
1901 return S_OK;
1902 }
1903
1904 /*OnActivate handles the menu merging and internal state*/
1905 DoActivate(uState);
1906
1907 /*only do This if we are active*/
1908 if (uState != SVUIA_DEACTIVATE)
1909 {
1910
1911 /*
1912 GetFolderPath is not a method of IShellFolder
1913 IShellFolder_GetFolderPath( pSFParent, szName, sizeof(szName) );
1914 */
1915 /* set the number of parts */
1916 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1917
1918 /* set the text for the parts */
1919 /*
1920 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1921 */
1922 }
1923
1924 return S_OK;
1925 }
1926
1927 HRESULT WINAPI CDefView::Refresh()
1928 {
1929 TRACE("(%p)\n", this);
1930
1931 SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
1932 FillList();
1933
1934 return S_OK;
1935 }
1936
1937 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1938 {
1939 *phWnd = 0;
1940
1941 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1942
1943 if (lpfs != NULL)
1944 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1945 if (prcView != NULL)
1946 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1947
1948 /* Validate the Shell Browser */
1949 if (psb == NULL)
1950 return E_UNEXPECTED;
1951
1952 /*set up the member variables*/
1953 pShellBrowser = psb;
1954 FolderSettings = *lpfs;
1955
1956 /*get our parent window*/
1957 pShellBrowser->GetWindow(&hWndParent);
1958
1959 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
1960 pCommDlgBrowser = NULL;
1961 if (SUCCEEDED(pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &pCommDlgBrowser))))
1962 {
1963 TRACE("-- CommDlgBrowser\n");
1964 }
1965
1966 Create(hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
1967 if (m_hWnd == NULL)
1968 return E_FAIL;
1969
1970 *phWnd = m_hWnd;
1971
1972 CheckToolbar();
1973
1974 if (!*phWnd)
1975 return E_FAIL;
1976
1977 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1978 UpdateWindow();
1979
1980 return S_OK;
1981 }
1982
1983 HRESULT WINAPI CDefView::DestroyViewWindow()
1984 {
1985 TRACE("(%p)\n", this);
1986
1987 /*Make absolutely sure all our UI is cleaned up.*/
1988 UIActivate(SVUIA_DEACTIVATE);
1989
1990 if (hMenu)
1991 {
1992 DestroyMenu(hMenu);
1993 }
1994
1995 DestroyWindow();
1996 pShellBrowser.Release();
1997 pCommDlgBrowser.Release();
1998
1999 return S_OK;
2000 }
2001
2002 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2003 {
2004 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2005 FolderSettings.ViewMode, FolderSettings.fFlags);
2006
2007 if (!lpfs)
2008 return E_INVALIDARG;
2009
2010 *lpfs = FolderSettings;
2011 return S_OK;
2012 }
2013
2014 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2015 {
2016 FIXME("(%p) stub\n", this);
2017
2018 return E_NOTIMPL;
2019 }
2020
2021 HRESULT WINAPI CDefView::SaveViewState()
2022 {
2023 FIXME("(%p) stub\n", this);
2024
2025 return S_OK;
2026 }
2027
2028 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2029 {
2030 int i;
2031
2032 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2033
2034 i = LV_FindItemByPidl(pidl);
2035
2036 if (i != -1)
2037 {
2038 LVITEMW lvItem;
2039
2040 if(uFlags & SVSI_ENSUREVISIBLE)
2041 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
2042
2043 lvItem.mask = LVIF_STATE;
2044 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2045 lvItem.iItem = 0;
2046 lvItem.iSubItem = 0;
2047
2048 while (SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2049 {
2050 if (lvItem.iItem == i)
2051 {
2052 if (uFlags & SVSI_SELECT)
2053 lvItem.state |= LVIS_SELECTED;
2054 else
2055 lvItem.state &= ~LVIS_SELECTED;
2056
2057 if (uFlags & SVSI_FOCUSED)
2058 lvItem.state &= ~LVIS_FOCUSED;
2059 }
2060 else
2061 {
2062 if (uFlags & SVSI_DESELECTOTHERS)
2063 lvItem.state &= ~LVIS_SELECTED;
2064 }
2065
2066 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2067 lvItem.iItem++;
2068 }
2069
2070
2071 if(uFlags & SVSI_EDIT)
2072 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
2073 }
2074
2075 return S_OK;
2076 }
2077
2078 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2079 {
2080 HRESULT hr = E_NOINTERFACE;
2081
2082 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2083
2084 *ppvOut = NULL;
2085
2086 switch (uItem)
2087 {
2088 case SVGIO_BACKGROUND:
2089 if (IsEqualIID(riid, IID_IContextMenu))
2090 {
2091 //*ppvOut = ISvBgCm_Constructor(pSFParent, FALSE);
2092 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2093 if (!ppvOut)
2094 hr = E_OUTOFMEMORY;
2095 else
2096 hr = S_OK;
2097 }
2098 break;
2099
2100 case SVGIO_SELECTION:
2101 GetSelections();
2102 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, riid, 0, ppvOut);
2103 break;
2104 }
2105
2106 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2107
2108 return hr;
2109 }
2110
2111 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2112 {
2113 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2114
2115 if (!pViewMode)
2116 return E_INVALIDARG;
2117
2118 *pViewMode = this->FolderSettings.ViewMode;
2119 return S_OK;
2120 }
2121
2122 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2123 {
2124 DWORD dwStyle;
2125 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2126
2127 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2128 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2129 return E_INVALIDARG;
2130
2131 /* Windows before Vista uses LVM_SETVIEW and possibly
2132 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2133 while later versions seem to accomplish this through other
2134 means. */
2135 switch (ViewMode)
2136 {
2137 case FVM_ICON:
2138 dwStyle = LVS_ICON;
2139 break;
2140 case FVM_DETAILS:
2141 dwStyle = LVS_REPORT;
2142 break;
2143 case FVM_SMALLICON:
2144 dwStyle = LVS_SMALLICON;
2145 break;
2146 case FVM_LIST:
2147 dwStyle = LVS_LIST;
2148 break;
2149 default:
2150 {
2151 FIXME("ViewMode %d not implemented\n", ViewMode);
2152 dwStyle = LVS_LIST;
2153 break;
2154 }
2155 }
2156
2157 SetStyle(dwStyle, LVS_TYPEMASK);
2158
2159 /* This will not necessarily be the actual mode set above.
2160 This mimics the behavior of Windows XP. */
2161 this->FolderSettings.ViewMode = ViewMode;
2162
2163 return S_OK;
2164 }
2165
2166 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2167 {
2168 if (pSFParent == NULL)
2169 return E_FAIL;
2170
2171 return pSFParent->QueryInterface(riid, ppv);
2172 }
2173
2174 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2175 {
2176 LVITEMW item;
2177
2178 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2179
2180 item.mask = LVIF_PARAM;
2181 item.iItem = iItemIndex;
2182
2183 if (SendMessageW(this->hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2184 {
2185 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2186 return S_OK;
2187 }
2188
2189 *ppidl = 0;
2190
2191 return E_INVALIDARG;
2192 }
2193
2194 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2195 {
2196 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2197
2198 if (uFlags != SVGIO_ALLVIEW)
2199 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2200
2201 *pcItems = SendMessageW(this->hWndList, LVM_GETITEMCOUNT, 0, 0);
2202
2203 return S_OK;
2204 }
2205
2206 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2207 {
2208 return E_NOTIMPL;
2209 }
2210
2211 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2212 {
2213 TRACE("(%p)->(%p)\n", this, piItem);
2214
2215 *piItem = SendMessageW(this->hWndList, LVM_GETSELECTIONMARK, 0, 0);
2216
2217 return S_OK;
2218 }
2219
2220 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2221 {
2222 TRACE("(%p)->(%p)\n", this, piItem);
2223
2224 *piItem = SendMessageW(this->hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2225
2226 return S_OK;
2227 }
2228
2229 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2230 {
2231 return E_NOTIMPL;
2232 }
2233
2234 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2235 {
2236 TRACE("(%p)->(%p)\n", this, ppt);
2237
2238 if (NULL == this->hWndList) return S_FALSE;
2239
2240 if (ppt)
2241 {
2242 const DWORD ret = SendMessageW(this->hWndList, LVM_GETITEMSPACING, 0, 0);
2243
2244 ppt->x = LOWORD(ret);
2245 ppt->y = HIWORD(ret);
2246 }
2247
2248 return S_OK;
2249 }
2250
2251 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2252 {
2253 return E_NOTIMPL;
2254 }
2255
2256 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2257 {
2258 return E_NOTIMPL;
2259 }
2260
2261 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2262 {
2263 LVITEMW lvItem;
2264
2265 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2266
2267 lvItem.state = 0;
2268 lvItem.stateMask = LVIS_SELECTED;
2269
2270 if (dwFlags & SVSI_ENSUREVISIBLE)
2271 SendMessageW(this->hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2272
2273 /* all items */
2274 if (dwFlags & SVSI_DESELECTOTHERS)
2275 SendMessageW(this->hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2276
2277 /* this item */
2278 if (dwFlags & SVSI_SELECT)
2279 lvItem.state |= LVIS_SELECTED;
2280
2281 if (dwFlags & SVSI_FOCUSED)
2282 lvItem.stateMask |= LVIS_FOCUSED;
2283
2284 SendMessageW(this->hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2285
2286 if (dwFlags & SVSI_EDIT)
2287 SendMessageW(this->hWndList, LVM_EDITLABELW, iItem, 0);
2288
2289 return S_OK;
2290 }
2291
2292 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2293 {
2294 return E_NOTIMPL;
2295 }
2296
2297 /**********************************************************
2298 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2299 */
2300 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2301 {
2302 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2303 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2304
2305 if (!prgCmds)
2306 return E_INVALIDARG;
2307
2308 for (UINT i = 0; i < cCmds; i++)
2309 {
2310 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2311 prgCmds[i].cmdf = 0;
2312 }
2313
2314 return OLECMDERR_E_UNKNOWNGROUP;
2315 }
2316
2317 /**********************************************************
2318 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2319 *
2320 * nCmdID is the OLECMDID_* enumeration
2321 */
2322 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2323 {
2324 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2325 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2326
2327 if (!pguidCmdGroup)
2328 return OLECMDERR_E_UNKNOWNGROUP;
2329
2330 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2331 (nCmdID == 0x29) &&
2332 (nCmdexecopt == 4) && pvaOut)
2333 return S_OK;
2334
2335 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2336 (nCmdID == 9) &&
2337 (nCmdexecopt == 0))
2338 return 1;
2339
2340 return OLECMDERR_E_UNKNOWNGROUP;
2341 }
2342
2343 /**********************************************************
2344 * ISVDropTarget implementation
2345 */
2346
2347 /******************************************************************************
2348 * drag_notify_subitem [Internal]
2349 *
2350 * Figure out the shellfolder object, which is currently under the mouse cursor
2351 * and notify it via the IDropTarget interface.
2352 */
2353
2354 #define SCROLLAREAWIDTH 20
2355
2356 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2357 {
2358 LVHITTESTINFO htinfo;
2359 LVITEMW lvItem;
2360 LONG lResult;
2361 HRESULT hr;
2362 RECT clientRect;
2363
2364 /* Map from global to client coordinates and query the index of the listview-item, which is
2365 * currently under the mouse cursor. */
2366 htinfo.pt.x = pt.x;
2367 htinfo.pt.y = pt.y;
2368 htinfo.flags = LVHT_ONITEM;
2369 ::ScreenToClient(hWndList, &htinfo.pt);
2370 lResult = SendMessageW(hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2371
2372 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2373 ::GetClientRect(hWndList, &clientRect);
2374 if (htinfo.pt.x == ptLastMousePos.x && htinfo.pt.y == ptLastMousePos.y &&
2375 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2376 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2377 {
2378 cScrollDelay = (cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2379 if (cScrollDelay == 0)
2380 {
2381 /* Mouse did hover another 250 ms over the scroll-area */
2382 if (htinfo.pt.x < SCROLLAREAWIDTH)
2383 SendMessageW(hWndList, WM_HSCROLL, SB_LINEUP, 0);
2384
2385 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2386 SendMessageW(hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2387
2388 if (htinfo.pt.y < SCROLLAREAWIDTH)
2389 SendMessageW(hWndList, WM_VSCROLL, SB_LINEUP, 0);
2390
2391 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2392 SendMessageW(hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2393 }
2394 }
2395 else
2396 {
2397 cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2398 }
2399
2400 ptLastMousePos = htinfo.pt;
2401
2402 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2403 if (pCurDropTarget && lResult == iDragOverItem)
2404 return pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2405
2406 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2407 if (pCurDropTarget)
2408 {
2409 pCurDropTarget->DragLeave();
2410 pCurDropTarget.Release();
2411 }
2412
2413 iDragOverItem = lResult;
2414 if (lResult == -1)
2415 {
2416 /* We are not above one of the listview's subitems. Bind to the parent folder's
2417 * DropTarget interface. */
2418 hr = pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&pCurDropTarget));
2419 }
2420 else
2421 {
2422 /* Query the relative PIDL of the shellfolder object represented by the currently
2423 * dragged over listview-item ... */
2424 lvItem.mask = LVIF_PARAM;
2425 lvItem.iItem = lResult;
2426 lvItem.iSubItem = 0;
2427 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2428
2429 /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2430 hr = pSFParent->GetUIObjectOf(hWndList, 1,
2431 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&pCurDropTarget);
2432 }
2433
2434 /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2435 if (FAILED(hr))
2436 return hr;
2437
2438 /* Notify the item just entered via DragEnter. */
2439 return pCurDropTarget->DragEnter(pCurDataObject, grfKeyState, pt, pdwEffect);
2440 }
2441
2442 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2443 {
2444 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2445 pCurDataObject = pDataObject;
2446 pDataObject->AddRef();
2447
2448 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2449 }
2450
2451 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2452 {
2453 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2454 }
2455
2456 HRESULT WINAPI CDefView::DragLeave()
2457 {
2458 if (pCurDropTarget)
2459 {
2460 pCurDropTarget->DragLeave();
2461 pCurDropTarget.Release();
2462 }
2463
2464 if (pCurDataObject != NULL)
2465 {
2466 pCurDataObject.Release();
2467 }
2468
2469 iDragOverItem = 0;
2470
2471 return S_OK;
2472 }
2473
2474 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2475 {
2476 if (pCurDropTarget)
2477 {
2478 pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2479 pCurDropTarget.Release();
2480 }
2481
2482 pCurDataObject.Release();
2483 iDragOverItem = 0;
2484
2485 return S_OK;
2486 }
2487
2488 /**********************************************************
2489 * ISVDropSource implementation
2490 */
2491
2492 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2493 {
2494 TRACE("(%p)\n", this);
2495
2496 if (fEscapePressed)
2497 return DRAGDROP_S_CANCEL;
2498 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2499 return DRAGDROP_S_DROP;
2500 else
2501 return S_OK;
2502 }
2503
2504 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2505 {
2506 TRACE("(%p)\n", this);
2507
2508 return DRAGDROP_S_USEDEFAULTCURSORS;
2509 }
2510
2511 /**********************************************************
2512 * ISVViewObject implementation
2513 */
2514
2515 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)
2516 {
2517 FIXME("Stub: this=%p\n", this);
2518
2519 return E_NOTIMPL;
2520 }
2521
2522 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2523 {
2524 FIXME("Stub: this=%p\n", this);
2525
2526 return E_NOTIMPL;
2527 }
2528
2529 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2530 {
2531 FIXME("Stub: this=%p\n", this);
2532
2533 return E_NOTIMPL;
2534 }
2535
2536 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2537 {
2538 FIXME("Stub: this=%p\n", this);
2539
2540 return E_NOTIMPL;
2541 }
2542
2543 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2544 {
2545 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2546
2547 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2548 this->pAdvSink = pAdvSink;
2549 dwAspects = aspects;
2550 dwAdvf = advf;
2551
2552 return S_OK;
2553 }
2554
2555 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2556 {
2557 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2558
2559 if (ppAdvSink)
2560 {
2561 *ppAdvSink = pAdvSink;
2562 pAdvSink.p->AddRef();
2563 }
2564
2565 if (pAspects)
2566 *pAspects = dwAspects;
2567
2568 if (pAdvf)
2569 *pAdvf = dwAdvf;
2570
2571 return S_OK;
2572 }
2573
2574 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2575 {
2576 if (IsEqualIID(guidService, SID_IShellBrowser))
2577 return pShellBrowser->QueryInterface(riid, ppvObject);
2578 else if(IsEqualIID(guidService, SID_IFolderView))
2579 return QueryInterface(riid, ppvObject);
2580
2581 return E_NOINTERFACE;
2582 }
2583
2584 /**********************************************************
2585 * IShellView_Constructor
2586 */
2587 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2588 {
2589 CComObject<CDefView> *theView;
2590 CComPtr<IShellView> result;
2591 HRESULT hResult;
2592
2593 if (newView == NULL)
2594 return E_POINTER;
2595
2596 *newView = NULL;
2597 ATLTRY (theView = new CComObject<CDefView>);
2598
2599 if (theView == NULL)
2600 return E_OUTOFMEMORY;
2601
2602 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2603 if (FAILED (hResult))
2604 {
2605 delete theView;
2606 return hResult;
2607 }
2608
2609 hResult = theView->Initialize (pFolder);
2610 if (FAILED (hResult))
2611 return hResult;
2612 *newView = result.Detach ();
2613
2614 return S_OK;
2615 }