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