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