[USB-BRINGUP-TRUNK]
[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 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|LVIF_IMAGE;
779 lvItem.iItem = nItem;
780 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidlNew)); /* set the item's data */
781 lvItem.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidlNew, 0);
782 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
783 SendMessageW(hWndList, LVM_UPDATE, nItem, 0);
784 return TRUE; /* FIXME: better handling */
785 }
786
787 return FALSE;
788 }
789
790 /**********************************************************
791 * ShellView_FillList()
792 *
793 * - gets the objectlist from the shellfolder
794 * - sorts the list
795 * - fills the list into the view
796 */
797 INT CALLBACK CDefView::fill_list( LPVOID ptr, LPVOID arg )
798 {
799 LPITEMIDLIST pidl = (LPITEMIDLIST)ptr;
800 CDefView *pThis = (CDefView *)arg;
801 /* in a commdlg This works as a filemask*/
802 if (pThis->IncludeObject(pidl) == S_OK)
803 pThis->LV_AddItem(pidl);
804
805 SHFree(pidl);
806 return TRUE;
807 }
808
809 HRESULT CDefView::FillList()
810 {
811 LPENUMIDLIST pEnumIDList;
812 LPITEMIDLIST pidl;
813 DWORD dwFetched;
814 HRESULT hRes;
815 HDPA hdpa;
816
817 TRACE("%p\n", this);
818
819 /* get the itemlist from the shfolder*/
820 hRes = pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
821 if (hRes != S_OK)
822 {
823 if (hRes == S_FALSE)
824 return(NOERROR);
825 return(hRes);
826 }
827
828 /* create a pointer array */
829 hdpa = DPA_Create(16);
830 if (!hdpa)
831 {
832 return(E_OUTOFMEMORY);
833 }
834
835 /* copy the items into the array*/
836 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
837 {
838 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
839 {
840 SHFree(pidl);
841 }
842 }
843
844 /* sort the array */
845 DPA_Sort(hdpa, CompareItems, (LPARAM)pSFParent.p);
846
847 /*turn the listview's redrawing off*/
848 SendMessageA(hWndList, WM_SETREDRAW, FALSE, 0);
849
850 DPA_DestroyCallback( hdpa, fill_list, (void *)this);
851
852 /*turn the listview's redrawing back on and force it to draw*/
853 SendMessageA(hWndList, WM_SETREDRAW, TRUE, 0);
854
855 pEnumIDList->Release(); /* destroy the list*/
856
857 return S_OK;
858 }
859
860 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
861 {
862 ::UpdateWindow(hWndList);
863 bHandled = FALSE;
864 return 0;
865 }
866
867 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
868 {
869 return SendMessageW(hWndList, uMsg, 0, 0);
870 }
871
872 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
873 {
874 RevokeDragDrop(m_hWnd);
875 SHChangeNotifyDeregister(hNotify);
876 bHandled = FALSE;
877 return 0;
878 }
879
880 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
881 {
882 if (FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
883 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
884
885 bHandled = FALSE;
886 return 0;
887 }
888
889 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
890 {
891 /* Forward WM_SYSCOLORCHANGE to common controls */
892 return SendMessageW(hWndList, uMsg, 0, 0);
893 }
894
895 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
896 {
897 return (LRESULT)pShellBrowser.p;
898 }
899
900 /**********************************************************
901 * ShellView_OnCreate()
902 */
903 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
904 {
905 CComPtr<IDropTarget> pdt;
906 SHChangeNotifyEntry ntreg;
907 CComPtr<IPersistFolder2> ppf2;
908
909 TRACE("%p\n", this);
910
911 if(CreateList())
912 {
913 if(InitList())
914 {
915 FillList();
916 }
917 }
918
919 if (SUCCEEDED(this->QueryInterface(IID_IDropTarget, (LPVOID*)&pdt)))
920 RegisterDragDrop(m_hWnd, pdt);
921
922 /* register for receiving notifications */
923 pSFParent->QueryInterface(IID_IPersistFolder2, (LPVOID*)&ppf2);
924 if (ppf2)
925 {
926 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
927 ntreg.fRecursive = TRUE;
928 hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
929 SHFree((LPITEMIDLIST)ntreg.pidl);
930 }
931
932 hAccel = LoadAcceleratorsA(shell32_hInstance, "shv_accel");
933
934 return S_OK;
935 }
936
937 /**********************************************************
938 * #### Handling of the menus ####
939 */
940
941 /**********************************************************
942 * ShellView_BuildFileMenu()
943 */
944 HMENU CDefView::BuildFileMenu()
945 { WCHAR szText[MAX_PATH];
946 MENUITEMINFOW mii;
947 int nTools, i;
948 HMENU hSubMenu;
949
950 TRACE("(%p)\n", this);
951
952 hSubMenu = CreatePopupMenu();
953 if (hSubMenu)
954 {
955 /*get the number of items in our global array*/
956 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++) {}
957
958 /*add the menu items*/
959 for(i = 0; i < nTools; i++)
960 {
961 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
962
963 ZeroMemory(&mii, sizeof(mii));
964 mii.cbSize = sizeof(mii);
965 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
966
967 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
968 {
969 mii.fType = MFT_STRING;
970 mii.fState = MFS_ENABLED;
971 mii.dwTypeData = szText;
972 mii.wID = Tools[i].idCommand;
973 }
974 else
975 {
976 mii.fType = MFT_SEPARATOR;
977 }
978 /* tack This item onto the end of the menu */
979 InsertMenuItemW(hSubMenu, (UINT) - 1, TRUE, &mii);
980 }
981 }
982
983 TRACE("-- return (menu=%p)\n", hSubMenu);
984 return hSubMenu;
985 }
986
987 /**********************************************************
988 * ShellView_MergeFileMenu()
989 */
990 void CDefView::MergeFileMenu(HMENU hSubMenu)
991 {
992 TRACE("(%p)->(submenu=%p) stub\n", this, hSubMenu);
993
994 if (hSubMenu)
995 { /*insert This item at the beginning of the menu */
996 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
997 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
998 }
999
1000 TRACE("--\n");
1001 }
1002
1003 /**********************************************************
1004 * ShellView_MergeViewMenu()
1005 */
1006 void CDefView::MergeViewMenu(HMENU hSubMenu)
1007 {
1008 TRACE("(%p)->(submenu=%p)\n", this, hSubMenu);
1009
1010 if (hSubMenu)
1011 {
1012 /*add a separator at the correct position in the menu*/
1013 MENUITEMINFOW mii;
1014 static WCHAR view[] = L"View";
1015
1016 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1017
1018 ZeroMemory(&mii, sizeof(mii));
1019 mii.cbSize = sizeof(mii);
1020 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
1021 mii.fType = MFT_STRING;
1022 mii.dwTypeData = view;
1023 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
1024 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
1025 }
1026 }
1027
1028 /**********************************************************
1029 * ShellView_GetSelections()
1030 *
1031 * - fills the this->apidl list with the selected objects
1032 *
1033 * RETURNS
1034 * number of selected items
1035 */
1036 UINT CDefView::GetSelections()
1037 {
1038 LVITEMW lvItem;
1039 UINT i = 0;
1040
1041 SHFree(apidl);
1042
1043 cidl = ListView_GetSelectedCount(hWndList);
1044 apidl = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
1045
1046 TRACE("selected=%i\n", cidl);
1047
1048 if (apidl)
1049 {
1050 TRACE("-- Items selected =%u\n", cidl);
1051
1052 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1053 lvItem.stateMask = LVIS_SELECTED;
1054 lvItem.iItem = 0;
1055 lvItem.iSubItem = 0;
1056 lvItem.state = 0;
1057
1058 while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < cidl))
1059 {
1060 if(lvItem.state & LVIS_SELECTED)
1061 {
1062 apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1063 i++;
1064 if (i == cidl)
1065 break;
1066 TRACE("-- selected Item found\n");
1067 }
1068 lvItem.iItem++;
1069 }
1070 }
1071
1072 return cidl;
1073 }
1074
1075 /**********************************************************
1076 * ShellView_OpenSelectedItems()
1077 */
1078 HRESULT CDefView::OpenSelectedItems()
1079 {
1080 static UINT CF_IDLIST = 0;
1081 HRESULT hr;
1082 CComPtr<IDataObject> selection;
1083 CComPtr<IContextMenu> cm;
1084 HMENU hmenu;
1085 FORMATETC fetc;
1086 STGMEDIUM stgm;
1087 LPIDA pIDList;
1088 LPCITEMIDLIST parent_pidl;
1089 WCHAR parent_path[MAX_PATH];
1090 LPCWSTR parent_dir = NULL;
1091 SFGAOF attribs;
1092 int i;
1093 CMINVOKECOMMANDINFOEX ici;
1094 MENUITEMINFOW info;
1095
1096 if (0 == GetSelections())
1097 {
1098 return S_OK;
1099 }
1100
1101 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1102 (LPCITEMIDLIST*)apidl, IID_IContextMenu,
1103 0, (LPVOID *)&cm);
1104
1105 if (SUCCEEDED(hr))
1106 {
1107 hmenu = CreatePopupMenu();
1108 if (hmenu)
1109 {
1110 hr = IUnknown_SetSite(cm, (IShellView *)this);
1111 if (SUCCEEDED(cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY)))
1112 {
1113 INT def = -1, n = GetMenuItemCount(hmenu);
1114
1115 for ( i = 0; i < n; i++ )
1116 {
1117 memset( &info, 0, sizeof info );
1118 info.cbSize = sizeof info;
1119 info.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID;
1120 if (GetMenuItemInfoW( hmenu, i, TRUE, &info))
1121 {
1122 if (info.fState & MFS_DEFAULT)
1123 {
1124 def = info.wID;
1125 break;
1126 }
1127 }
1128 }
1129 if (def != -1)
1130 {
1131 memset( &ici, 0, sizeof ici );
1132 ici.cbSize = sizeof ici;
1133 ici.lpVerb = MAKEINTRESOURCEA( def );
1134 ici.hwnd = m_hWnd;
1135
1136 hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1137 if (hr == S_OK)
1138 {
1139 DestroyMenu(hmenu);
1140 hr = IUnknown_SetSite(cm, NULL);
1141 return S_OK;
1142 }
1143 else
1144 ERR("InvokeCommand failed: %x\n", hr);
1145 }
1146 else
1147 ERR("No default context menu item\n");
1148
1149 }
1150 DestroyMenu( hmenu );
1151 hr = IUnknown_SetSite(cm, NULL);
1152 }
1153 }
1154
1155
1156
1157 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
1158 (LPCITEMIDLIST*)apidl, IID_IDataObject,
1159 0, (LPVOID *)&selection);
1160
1161
1162
1163 if (FAILED(hr))
1164 return hr;
1165
1166 if (0 == CF_IDLIST)
1167 {
1168 CF_IDLIST = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
1169 }
1170
1171 fetc.cfFormat = CF_IDLIST;
1172 fetc.ptd = NULL;
1173 fetc.dwAspect = DVASPECT_CONTENT;
1174 fetc.lindex = -1;
1175 fetc.tymed = TYMED_HGLOBAL;
1176
1177 hr = selection->QueryGetData(&fetc);
1178 if (FAILED(hr))
1179 return hr;
1180
1181 hr = selection->GetData(&fetc, &stgm);
1182 if (FAILED(hr))
1183 return hr;
1184
1185 pIDList = (LPIDA)GlobalLock(stgm.hGlobal);
1186
1187 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pIDList + pIDList->aoffset[0]);
1188 hr = pSFParent->GetAttributesOf(1, &parent_pidl, &attribs);
1189 if (SUCCEEDED(hr) && (attribs & SFGAO_FILESYSTEM) &&
1190 SHGetPathFromIDListW(parent_pidl, parent_path))
1191 {
1192 parent_dir = parent_path;
1193 }
1194
1195 for (i = pIDList->cidl; i > 0; --i)
1196 {
1197 LPCITEMIDLIST pidl;
1198
1199 pidl = (LPCITEMIDLIST)((LPBYTE)pIDList + pIDList->aoffset[i]);
1200
1201 attribs = SFGAO_FOLDER;
1202 hr = pSFParent->GetAttributesOf(1, &pidl, &attribs);
1203
1204 if (SUCCEEDED(hr) && ! (attribs & SFGAO_FOLDER))
1205 {
1206 SHELLEXECUTEINFOW shexinfo;
1207
1208 shexinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
1209 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; /* SEE_MASK_IDLIST is also possible. */
1210 shexinfo.hwnd = NULL;
1211 shexinfo.lpVerb = NULL;
1212 shexinfo.lpFile = NULL;
1213 shexinfo.lpParameters = NULL;
1214 shexinfo.lpDirectory = parent_dir;
1215 shexinfo.nShow = SW_NORMAL;
1216 shexinfo.lpIDList = ILCombine(parent_pidl, pidl);
1217
1218 ShellExecuteExW(&shexinfo); /* Discard error/success info */
1219
1220 ILFree((LPITEMIDLIST)shexinfo.lpIDList);
1221 }
1222 }
1223
1224 GlobalUnlock(stgm.hGlobal);
1225 ReleaseStgMedium(&stgm);
1226
1227 return S_OK;
1228 }
1229
1230 /**********************************************************
1231 * ShellView_DoContextMenu()
1232 */
1233 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1234 {
1235 WORD x;
1236 WORD y;
1237 UINT uCommand;
1238 DWORD wFlags;
1239 HMENU hMenu;
1240 BOOL fExplore;
1241 HWND hwndTree;
1242 CMINVOKECOMMANDINFO cmi;
1243 HRESULT hResult;
1244
1245 // for some reason I haven't figured out, we sometimes recurse into this method
1246 if (pCM != NULL)
1247 return 0;
1248
1249 x = LOWORD(lParam);
1250 y = HIWORD(lParam);
1251
1252 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1253
1254 fExplore = FALSE;
1255 hwndTree = NULL;
1256
1257 /* look, what's selected and create a context menu object of it*/
1258 if (GetSelections())
1259 {
1260 pSFParent->GetUIObjectOf(hWndParent, cidl, (LPCITEMIDLIST*)apidl, IID_IContextMenu, NULL, (LPVOID *)&pCM);
1261
1262 if (pCM)
1263 {
1264 TRACE("-- pContextMenu\n");
1265 hMenu = CreatePopupMenu();
1266
1267 if (hMenu)
1268 {
1269 hResult = IUnknown_SetSite(pCM, (IShellView *)this);
1270
1271 /* See if we are in Explore or Open mode. If the browser's tree is present, we are in Explore mode.*/
1272 if (SUCCEEDED(pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
1273 {
1274 TRACE("-- explore mode\n");
1275 fExplore = TRUE;
1276 }
1277
1278 /* build the flags depending on what we can do with the selected item */
1279 wFlags = CMF_NORMAL | (cidl != 1 ? 0 : CMF_CANRENAME) | (fExplore ? CMF_EXPLORE : 0);
1280
1281 /* let the ContextMenu merge its items in */
1282 if (SUCCEEDED(pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags )))
1283 {
1284 if (FolderSettings.fFlags & FWF_DESKTOP)
1285 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1286
1287 TRACE("-- track popup\n");
1288 uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD, x, y, 0, m_hWnd, NULL);
1289
1290 if (uCommand > 0)
1291 {
1292 TRACE("-- uCommand=%u\n", uCommand);
1293
1294 if (uCommand == FCIDM_SHVIEW_OPEN && pCommDlgBrowser.p != NULL)
1295 {
1296 TRACE("-- dlg: OnDefaultCommand\n");
1297 if (OnDefaultCommand() != S_OK)
1298 OpenSelectedItems();
1299 }
1300 else
1301 {
1302 TRACE("-- explore -- invoke command\n");
1303 ZeroMemory(&cmi, sizeof(cmi));
1304 cmi.cbSize = sizeof(cmi);
1305 cmi.hwnd = hWndParent; /* this window has to answer CWM_GETISHELLBROWSER */
1306 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1307 pCM->InvokeCommand(&cmi);
1308 }
1309 }
1310
1311 hResult = IUnknown_SetSite(pCM, NULL);
1312 DestroyMenu(hMenu);
1313 }
1314 }
1315 pCM.Release();
1316 }
1317 }
1318 else /* background context menu */
1319 {
1320 hMenu = CreatePopupMenu();
1321
1322 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)&pCM);
1323 pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1324
1325 uCommand = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RETURNCMD, x, y, 0, m_hWnd, NULL);
1326 DestroyMenu(hMenu);
1327
1328 TRACE("-- (%p)->(uCommand=0x%08x )\n", this, uCommand);
1329
1330 ZeroMemory(&cmi, sizeof(cmi));
1331 cmi.cbSize = sizeof(cmi);
1332 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1333 cmi.hwnd = hWndParent;
1334 pCM->InvokeCommand(&cmi);
1335
1336 pCM.Release();
1337 }
1338
1339 return 0;
1340 }
1341
1342 /**********************************************************
1343 * ##### message handling #####
1344 */
1345
1346 /**********************************************************
1347 * ShellView_OnSize()
1348 */
1349 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1350 {
1351 WORD wWidth;
1352 WORD wHeight;
1353
1354 wWidth = LOWORD(lParam);
1355 wHeight = HIWORD(lParam);
1356
1357 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1358
1359 /*resize the ListView to fit our window*/
1360 if (hWndList)
1361 {
1362 ::MoveWindow(hWndList, 0, 0, wWidth, wHeight, TRUE);
1363 }
1364
1365 return 0;
1366 }
1367
1368 /**********************************************************
1369 * ShellView_OnDeactivate()
1370 *
1371 * NOTES
1372 * internal
1373 */
1374 void CDefView::OnDeactivate()
1375 {
1376 TRACE("%p\n", this);
1377
1378 if (uState != SVUIA_DEACTIVATE)
1379 {
1380 if (hMenu)
1381 {
1382 pShellBrowser->SetMenuSB(0, 0, 0);
1383 pShellBrowser->RemoveMenusSB(hMenu);
1384 DestroyMenu(hMenu);
1385 hMenu = 0;
1386 }
1387
1388 uState = SVUIA_DEACTIVATE;
1389 }
1390 }
1391
1392 void CDefView::DoActivate(UINT uState)
1393 {
1394 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1395 MENUITEMINFOA mii;
1396 CHAR szText[MAX_PATH];
1397
1398 TRACE("%p uState=%x\n", this, uState);
1399
1400 /*don't do anything if the state isn't really changing */
1401 if (uState == uState)
1402 {
1403 return;
1404 }
1405
1406 OnDeactivate();
1407
1408 /*only do This if we are active */
1409 if(uState != SVUIA_DEACTIVATE)
1410 {
1411 /*merge the menus */
1412 hMenu = CreateMenu();
1413
1414 if(hMenu)
1415 {
1416 pShellBrowser->InsertMenusSB(hMenu, &omw);
1417 TRACE("-- after fnInsertMenusSB\n");
1418
1419 /*build the top level menu get the menu item's text*/
1420 strcpy(szText, "dummy 31");
1421
1422 ZeroMemory(&mii, sizeof(mii));
1423 mii.cbSize = sizeof(mii);
1424 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1425 mii.fType = MFT_STRING;
1426 mii.fState = MFS_ENABLED;
1427 mii.dwTypeData = szText;
1428 mii.hSubMenu = BuildFileMenu();
1429
1430 /*insert our menu into the menu bar*/
1431 if (mii.hSubMenu)
1432 {
1433 InsertMenuItemA(hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1434 }
1435
1436 /*get the view menu so we can merge with it*/
1437 ZeroMemory(&mii, sizeof(mii));
1438 mii.cbSize = sizeof(mii);
1439 mii.fMask = MIIM_SUBMENU;
1440
1441 if (GetMenuItemInfoA(hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1442 {
1443 MergeViewMenu(mii.hSubMenu);
1444 }
1445
1446 /*add the items that should only be added if we have the focus*/
1447 if (SVUIA_ACTIVATE_FOCUS == uState)
1448 {
1449 /*get the file menu so we can merge with it */
1450 ZeroMemory(&mii, sizeof(mii));
1451 mii.cbSize = sizeof(mii);
1452 mii.fMask = MIIM_SUBMENU;
1453
1454 if (GetMenuItemInfoA(hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1455 {
1456 MergeFileMenu(mii.hSubMenu);
1457 }
1458 }
1459
1460 TRACE("-- before fnSetMenuSB\n");
1461 pShellBrowser->SetMenuSB(hMenu, 0, m_hWnd);
1462 }
1463 }
1464 uState = uState;
1465 TRACE("--\n");
1466 }
1467
1468 /**********************************************************
1469 * ShellView_OnActivate()
1470 */
1471 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1472 {
1473 DoActivate(SVUIA_ACTIVATE_FOCUS);
1474 return 0;
1475 }
1476
1477 /**********************************************************
1478 * ShellView_OnSetFocus()
1479 *
1480 */
1481 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1482 {
1483 TRACE("%p\n", this);
1484
1485 /* Tell the browser one of our windows has received the focus. This
1486 should always be done before merging menus (OnActivate merges the
1487 menus) if one of our windows has the focus.*/
1488
1489 pShellBrowser->OnViewWindowActive((IShellView *)this);
1490 DoActivate(SVUIA_ACTIVATE_FOCUS);
1491
1492 /* Set the focus to the listview */
1493 ::SetFocus(hWndList);
1494
1495 /* Notify the ICommDlgBrowser interface */
1496 OnStateChange(CDBOSC_SETFOCUS);
1497
1498 return 0;
1499 }
1500
1501 /**********************************************************
1502 * ShellView_OnKillFocus()
1503 */
1504 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1505 {
1506 TRACE("(%p) stub\n", this);
1507
1508 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1509 /* Notify the ICommDlgBrowser */
1510 OnStateChange(CDBOSC_KILLFOCUS);
1511
1512 return 0;
1513 }
1514
1515 /**********************************************************
1516 * ShellView_OnCommand()
1517 *
1518 * NOTES
1519 * the CmdID's are the ones from the context menu
1520 */
1521 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1522 {
1523 DWORD dwCmdID;
1524 DWORD dwCmd;
1525 HWND hwndCmd;
1526
1527 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1528 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1529 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1530
1531 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1532
1533 switch (dwCmdID)
1534 {
1535 case FCIDM_SHVIEW_SMALLICON:
1536 FolderSettings.ViewMode = FVM_SMALLICON;
1537 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1538 CheckToolbar();
1539 break;
1540
1541 case FCIDM_SHVIEW_BIGICON:
1542 FolderSettings.ViewMode = FVM_ICON;
1543 SetStyle (LVS_ICON, LVS_TYPEMASK);
1544 CheckToolbar();
1545 break;
1546
1547 case FCIDM_SHVIEW_LISTVIEW:
1548 FolderSettings.ViewMode = FVM_LIST;
1549 SetStyle (LVS_LIST, LVS_TYPEMASK);
1550 CheckToolbar();
1551 break;
1552
1553 case FCIDM_SHVIEW_REPORTVIEW:
1554 FolderSettings.ViewMode = FVM_DETAILS;
1555 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1556 CheckToolbar();
1557 break;
1558
1559 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1560 case 0x30:
1561 case 0x31:
1562 case 0x32:
1563 case 0x33:
1564 ListViewSortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1565 ListViewSortInfo.bIsAscending = TRUE;
1566 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1567 SendMessageA(hWndList, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1568 break;
1569
1570 default:
1571 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1572 }
1573
1574 return 0;
1575 }
1576
1577 /**********************************************************
1578 * ShellView_OnNotify()
1579 */
1580
1581 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1582 {
1583 UINT CtlID;
1584 LPNMHDR lpnmh;
1585 LPNMLISTVIEW lpnmlv;
1586 NMLVDISPINFOW *lpdi;
1587 LPITEMIDLIST pidl;
1588 BOOL unused;
1589
1590 CtlID = wParam;
1591 lpnmh = (LPNMHDR)lParam;
1592 lpnmlv = (LPNMLISTVIEW)lpnmh;
1593 lpdi = (NMLVDISPINFOW *)lpnmh;
1594
1595 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1596
1597 switch (lpnmh->code)
1598 {
1599 case NM_SETFOCUS:
1600 TRACE("-- NM_SETFOCUS %p\n", this);
1601 OnSetFocus(0, 0, 0, unused);
1602 break;
1603
1604 case NM_KILLFOCUS:
1605 TRACE("-- NM_KILLFOCUS %p\n", this);
1606 OnDeactivate();
1607 /* Notify the ICommDlgBrowser interface */
1608 OnStateChange(CDBOSC_KILLFOCUS);
1609 break;
1610
1611 case NM_CUSTOMDRAW:
1612 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1613 return CDRF_DODEFAULT;
1614
1615 case NM_RELEASEDCAPTURE:
1616 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1617 break;
1618
1619 case NM_CLICK:
1620 TRACE("-- NM_CLICK %p\n", this);
1621 break;
1622
1623 case NM_RCLICK:
1624 TRACE("-- NM_RCLICK %p\n", this);
1625 break;
1626
1627 case NM_DBLCLK:
1628 TRACE("-- NM_DBLCLK %p\n", this);
1629 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1630 break;
1631
1632 case NM_RETURN:
1633 TRACE("-- NM_RETURN %p\n", this);
1634 if (OnDefaultCommand() != S_OK) OpenSelectedItems();
1635 break;
1636
1637 case HDN_ENDTRACKW:
1638 TRACE("-- HDN_ENDTRACKW %p\n", this);
1639 /*nColumn1 = ListView_GetColumnWidth(hWndList, 0);
1640 nColumn2 = ListView_GetColumnWidth(hWndList, 1);*/
1641 break;
1642
1643 case LVN_DELETEITEM:
1644 TRACE("-- LVN_DELETEITEM %p\n", this);
1645 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1646 break;
1647
1648 case LVN_DELETEALLITEMS:
1649 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1650 return FALSE;
1651
1652 case LVN_INSERTITEM:
1653 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1654 break;
1655
1656 case LVN_ITEMACTIVATE:
1657 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1658 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1659 break;
1660
1661 case LVN_COLUMNCLICK:
1662 ListViewSortInfo.nHeaderID = lpnmlv->iSubItem;
1663 if (ListViewSortInfo.nLastHeaderID == ListViewSortInfo.nHeaderID)
1664 {
1665 ListViewSortInfo.bIsAscending = !ListViewSortInfo.bIsAscending;
1666 }
1667 else
1668 {
1669 ListViewSortInfo.bIsAscending = TRUE;
1670 }
1671 ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
1672
1673 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
1674 break;
1675
1676 case LVN_GETDISPINFOA:
1677 case LVN_GETDISPINFOW:
1678 TRACE("-- LVN_GETDISPINFO %p\n", this);
1679 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1680
1681 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1682 {
1683 if (pSF2Parent)
1684 {
1685 SHELLDETAILS sd;
1686 if (FAILED(pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1687 {
1688 FIXME("failed to get details\n");
1689 break;
1690 }
1691
1692 if (lpnmh->code == LVN_GETDISPINFOA)
1693 {
1694 /* shouldn't happen */
1695 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1696 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1697 TRACE("-- text=%s\n", lpdiA->item.pszText);
1698 }
1699 else /* LVN_GETDISPINFOW */
1700 {
1701 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1702 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1703 }
1704 }
1705 else
1706 {
1707 FIXME("no SF2\n");
1708 }
1709 }
1710 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1711 {
1712 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidl, 0);
1713 }
1714 lpdi->item.mask |= LVIF_DI_SETITEM;
1715 break;
1716
1717 case LVN_ITEMCHANGED:
1718 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1719 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1720 break;
1721
1722 case LVN_BEGINDRAG:
1723 case LVN_BEGINRDRAG:
1724 TRACE("-- LVN_BEGINDRAG\n");
1725
1726 if (GetSelections())
1727 {
1728 IDataObject * pda;
1729 DWORD dwAttributes = SFGAO_CANLINK;
1730 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1731
1732 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1733 {
1734 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1735
1736 if (SUCCEEDED(pSFParent->GetAttributesOf(cidl, (LPCITEMIDLIST*)apidl, &dwAttributes)))
1737 {
1738 if (dwAttributes & SFGAO_CANLINK)
1739 {
1740 dwEffect |= DROPEFFECT_LINK;
1741 }
1742 }
1743
1744 if (pds)
1745 {
1746 DWORD dwEffect2;
1747 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1748 }
1749 pda->Release();
1750 }
1751 }
1752 break;
1753
1754 case LVN_BEGINLABELEDITW:
1755 {
1756 DWORD dwAttr = SFGAO_CANRENAME;
1757 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1758
1759 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1760
1761 pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1762 if (SFGAO_CANRENAME & dwAttr)
1763 {
1764 return FALSE;
1765 }
1766 return TRUE;
1767 }
1768
1769 case LVN_ENDLABELEDITW:
1770 {
1771 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1772 if (lpdi->item.pszText)
1773 {
1774 HRESULT hr;
1775 LVITEMW lvItem;
1776
1777 lvItem.iItem = lpdi->item.iItem;
1778 lvItem.iSubItem = 0;
1779 lvItem.mask = LVIF_PARAM;
1780 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1781
1782 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1783 hr = pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1784
1785 if (SUCCEEDED(hr) && pidl)
1786 {
1787 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1788 lvItem.lParam = (LPARAM)pidl;
1789 lvItem.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidl, 0);
1790 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1791 SendMessageW(hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1792
1793 return TRUE;
1794 }
1795 }
1796
1797 return FALSE;
1798 }
1799
1800 case LVN_KEYDOWN:
1801 {
1802 /* MSG msg;
1803 msg.hwnd = m_hWnd;
1804 msg.message = WM_KEYDOWN;
1805 msg.wParam = plvKeyDown->wVKey;
1806 msg.lParam = 0;
1807 msg.time = 0;
1808 msg.pt = 0;*/
1809
1810 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1811 SHORT ctrl = GetKeyState(VK_CONTROL) & 0x8000;
1812
1813 /* initiate a rename of the selected file or directory */
1814 if (plvKeyDown->wVKey == VK_F2)
1815 {
1816 /* see how many files are selected */
1817 int i = ListView_GetSelectedCount(hWndList);
1818
1819 /* get selected item */
1820 if (i == 1)
1821 {
1822 /* get selected item */
1823 i = ListView_GetNextItem(hWndList, -1, LVNI_SELECTED);
1824
1825 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
1826 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
1827 }
1828 }
1829 #if 0
1830 TranslateAccelerator(m_hWnd, hAccel, &msg)
1831 #endif
1832 else if(plvKeyDown->wVKey == VK_DELETE)
1833 {
1834 UINT i;
1835 int item_index;
1836 LVITEMA item;
1837 LPITEMIDLIST* pItems;
1838 ISFHelper *psfhlp;
1839
1840 pSFParent->QueryInterface(IID_ISFHelper,
1841 (LPVOID*)&psfhlp);
1842
1843 if (psfhlp == NULL)
1844 break;
1845
1846 if (!(i = ListView_GetSelectedCount(hWndList)))
1847 break;
1848
1849 /* allocate memory for the pidl array */
1850 pItems = (LPITEMIDLIST *)HeapAlloc(GetProcessHeap(), 0,
1851 sizeof(LPITEMIDLIST) * i);
1852
1853 /* retrieve all selected items */
1854 i = 0;
1855 item_index = -1;
1856 while (ListView_GetSelectedCount(hWndList) > i)
1857 {
1858 /* get selected item */
1859 item_index = ListView_GetNextItem(hWndList,
1860 item_index, LVNI_SELECTED);
1861 item.iItem = item_index;
1862 item.mask = LVIF_PARAM;
1863 SendMessageA(hWndList, LVM_GETITEMA, 0, (LPARAM) &item);
1864
1865 /* get item pidl */
1866 pItems[i] = (LPITEMIDLIST)item.lParam;
1867
1868 i++;
1869 }
1870
1871 /* perform the item deletion */
1872 psfhlp->DeleteItems(i, (LPCITEMIDLIST*)pItems);
1873
1874 /* free pidl array memory */
1875 HeapFree(GetProcessHeap(), 0, pItems);
1876 }
1877 /* Initiate a refresh */
1878 else if (plvKeyDown->wVKey == VK_F5)
1879 {
1880 Refresh();
1881 }
1882 else if (plvKeyDown->wVKey == VK_BACK)
1883 {
1884 LPSHELLBROWSER lpSb;
1885 if ((lpSb = (LPSHELLBROWSER)SendMessageW(hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1886 {
1887 lpSb->BrowseObject(NULL, SBSP_PARENT);
1888 }
1889 }
1890 else if (plvKeyDown->wVKey == 'C' && ctrl)
1891 {
1892 if (GetSelections())
1893 {
1894 CComPtr<IDataObject> pda;
1895
1896 if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1897 {
1898 HRESULT hr = OleSetClipboard(pda);
1899 if (FAILED(hr))
1900 {
1901 WARN("OleSetClipboard failed");
1902 }
1903 }
1904 }
1905 break;
1906 }
1907 else if(plvKeyDown->wVKey == 'V' && ctrl)
1908 {
1909 CComPtr<IDataObject> pda;
1910 STGMEDIUM medium;
1911 FORMATETC formatetc;
1912 LPITEMIDLIST * apidl;
1913 LPITEMIDLIST pidl;
1914 CComPtr<IShellFolder> psfFrom;
1915 CComPtr<IShellFolder> psfDesktop;
1916 CComPtr<IShellFolder> psfTarget;
1917 LPIDA lpcida;
1918 CComPtr<ISFHelper> psfhlpdst;
1919 CComPtr<ISFHelper> psfhlpsrc;
1920 HRESULT hr;
1921
1922 hr = OleGetClipboard(&pda);
1923 if (hr != S_OK)
1924 {
1925 ERR("Failed to get clipboard with %lx\n", hr);
1926 return E_FAIL;
1927 }
1928
1929 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
1930 hr = pda->GetData(&formatetc, &medium);
1931
1932 if (FAILED(hr))
1933 {
1934 ERR("Failed to get clipboard data with %lx\n", hr);
1935 return E_FAIL;
1936 }
1937
1938 /* lock the handle */
1939 lpcida = (LPIDA)GlobalLock(medium.hGlobal);
1940 if (!lpcida)
1941 {
1942 ERR("failed to lock pidl\n");
1943 ReleaseStgMedium(&medium);
1944 return E_FAIL;
1945 }
1946
1947 /* convert the data into pidl */
1948 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1949
1950 if (!apidl)
1951 {
1952 ERR("failed to copy pidl\n");
1953 return E_FAIL;
1954 }
1955
1956 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
1957 {
1958 ERR("failed to get desktop folder\n");
1959 SHFree(pidl);
1960 _ILFreeaPidl(apidl, lpcida->cidl);
1961 ReleaseStgMedium(&medium);
1962 return E_FAIL;
1963 }
1964
1965 if (_ILIsDesktop(pidl))
1966 {
1967 /* use desktop shellfolder */
1968 psfFrom = psfDesktop;
1969 }
1970 else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
1971 {
1972 ERR("no IShellFolder\n");
1973
1974 SHFree(pidl);
1975 _ILFreeaPidl(apidl, lpcida->cidl);
1976 ReleaseStgMedium(&medium);
1977
1978 return E_FAIL;
1979 }
1980
1981 psfTarget = pSFParent;
1982
1983
1984 /* get source and destination shellfolder */
1985 if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
1986 {
1987 ERR("no IID_ISFHelper for destination\n");
1988
1989 SHFree(pidl);
1990 _ILFreeaPidl(apidl, lpcida->cidl);
1991 ReleaseStgMedium(&medium);
1992
1993 return E_FAIL;
1994 }
1995
1996 if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
1997 {
1998 ERR("no IID_ISFHelper for source\n");
1999
2000 SHFree(pidl);
2001 _ILFreeaPidl(apidl, lpcida->cidl);
2002 ReleaseStgMedium(&medium);
2003 return E_FAIL;
2004 }
2005
2006 /* FIXXME
2007 * do we want to perform a copy or move ???
2008 */
2009 hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
2010
2011 SHFree(pidl);
2012 _ILFreeaPidl(apidl, lpcida->cidl);
2013 ReleaseStgMedium(&medium);
2014
2015 TRACE("paste end hr %x\n", hr);
2016 break;
2017 }
2018 else
2019 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
2020 }
2021 break;
2022
2023 default:
2024 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2025 break;
2026 }
2027
2028 return 0;
2029 }
2030
2031 /**********************************************************
2032 * ShellView_OnChange()
2033 */
2034 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2035 {
2036 LPITEMIDLIST *Pidls;
2037
2038 Pidls = (LPITEMIDLIST *)wParam;
2039
2040 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2041
2042 switch (lParam)
2043 {
2044 case SHCNE_MKDIR:
2045 case SHCNE_CREATE:
2046 LV_AddItem(Pidls[0]);
2047 break;
2048
2049 case SHCNE_RMDIR:
2050 case SHCNE_DELETE:
2051 LV_DeleteItem(Pidls[0]);
2052 break;
2053
2054 case SHCNE_RENAMEFOLDER:
2055 case SHCNE_RENAMEITEM:
2056 LV_RenameItem(Pidls[0], Pidls[1]);
2057 break;
2058
2059 case SHCNE_UPDATEITEM:
2060 break;
2061 }
2062
2063 return TRUE;
2064 }
2065
2066 /**********************************************************
2067 * ShellView_DoMeasureItem
2068 */
2069 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2070 {
2071 if (!pCM.p)
2072 {
2073 /* no menu */
2074 ERR("no menu!!!\n");
2075 return FALSE;
2076 }
2077
2078 if (pCM.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
2079 return TRUE;
2080 else
2081 return FALSE;
2082 }
2083
2084 /**********************************************************
2085 *
2086 *
2087 * The INTERFACE of the IShellView object
2088 *
2089 *
2090 **********************************************************
2091 */
2092
2093 /**********************************************************
2094 * ShellView_GetWindow
2095 */
2096 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2097 {
2098 TRACE("(%p)\n", this);
2099
2100 *phWnd = m_hWnd;
2101
2102 return S_OK;
2103 }
2104
2105 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2106 {
2107 FIXME("(%p) stub\n", this);
2108
2109 return E_NOTIMPL;
2110 }
2111
2112 /**********************************************************
2113 * IShellView_TranslateAccelerator
2114 *
2115 * FIXME:
2116 * use the accel functions
2117 */
2118 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2119 {
2120 #if 0
2121 FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n", this, lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
2122 #endif
2123
2124 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message >= WM_KEYLAST)
2125 {
2126 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
2127 }
2128
2129 return S_FALSE; /* not handled */
2130 }
2131
2132 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2133 {
2134 FIXME("(%p) stub\n", this);
2135
2136 return E_NOTIMPL;
2137 }
2138
2139 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2140 {
2141 /*
2142 CHAR szName[MAX_PATH];
2143 */
2144 LRESULT lResult;
2145 int nPartArray[1] = { -1};
2146
2147 TRACE("(%p)->(state=%x) stub\n", this, uState);
2148
2149 /*don't do anything if the state isn't really changing*/
2150 if (uState == uState)
2151 {
2152 return S_OK;
2153 }
2154
2155 /*OnActivate handles the menu merging and internal state*/
2156 DoActivate(uState);
2157
2158 /*only do This if we are active*/
2159 if (uState != SVUIA_DEACTIVATE)
2160 {
2161
2162 /*
2163 GetFolderPath is not a method of IShellFolder
2164 IShellFolder_GetFolderPath( pSFParent, szName, sizeof(szName) );
2165 */
2166 /* set the number of parts */
2167 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2168
2169 /* set the text for the parts */
2170 /*
2171 pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2172 */
2173 }
2174
2175 return S_OK;
2176 }
2177
2178 HRESULT WINAPI CDefView::Refresh()
2179 {
2180 TRACE("(%p)\n", this);
2181
2182 SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
2183 FillList();
2184
2185 return S_OK;
2186 }
2187
2188 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2189 {
2190 *phWnd = 0;
2191
2192 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
2193
2194 if (lpfs != NULL)
2195 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
2196 if (prcView != NULL)
2197 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2198
2199 /* Validate the Shell Browser */
2200 if (psb == NULL)
2201 return E_UNEXPECTED;
2202
2203 /*set up the member variables*/
2204 pShellBrowser = psb;
2205 FolderSettings = *lpfs;
2206
2207 /*get our parent window*/
2208 pShellBrowser->GetWindow(&hWndParent);
2209
2210 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2211 pCommDlgBrowser = NULL;
2212 if (SUCCEEDED(pShellBrowser->QueryInterface(IID_ICommDlgBrowser, (LPVOID *)&pCommDlgBrowser)))
2213 {
2214 TRACE("-- CommDlgBrowser\n");
2215 }
2216
2217 Create(hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
2218 if (m_hWnd == NULL)
2219 return E_FAIL;
2220
2221 *phWnd = m_hWnd;
2222
2223 CheckToolbar();
2224
2225 if (!*phWnd)
2226 return E_FAIL;
2227
2228 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2229 UpdateWindow();
2230
2231 return S_OK;
2232 }
2233
2234 HRESULT WINAPI CDefView::DestroyViewWindow()
2235 {
2236 TRACE("(%p)\n", this);
2237
2238 /*Make absolutely sure all our UI is cleaned up.*/
2239 UIActivate(SVUIA_DEACTIVATE);
2240
2241 if (hMenu)
2242 {
2243 DestroyMenu(hMenu);
2244 }
2245
2246 DestroyWindow();
2247 pShellBrowser.Release();
2248 pCommDlgBrowser.Release();
2249
2250 return S_OK;
2251 }
2252
2253 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2254 {
2255 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2256 FolderSettings.ViewMode, FolderSettings.fFlags);
2257
2258 if (!lpfs)
2259 return E_INVALIDARG;
2260
2261 *lpfs = FolderSettings;
2262 return NOERROR;
2263 }
2264
2265 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2266 {
2267 FIXME("(%p) stub\n", this);
2268
2269 return E_NOTIMPL;
2270 }
2271
2272 HRESULT WINAPI CDefView::SaveViewState()
2273 {
2274 FIXME("(%p) stub\n", this);
2275
2276 return S_OK;
2277 }
2278
2279 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2280 {
2281 int i;
2282
2283 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2284
2285 i = LV_FindItemByPidl(pidl);
2286
2287 if (i != -1)
2288 {
2289 LVITEMW lvItem;
2290
2291 if(uFlags & SVSI_ENSUREVISIBLE)
2292 SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
2293
2294 lvItem.mask = LVIF_STATE;
2295 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2296 lvItem.iItem = 0;
2297 lvItem.iSubItem = 0;
2298
2299 while (SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2300 {
2301 if (lvItem.iItem == i)
2302 {
2303 if (uFlags & SVSI_SELECT)
2304 lvItem.state |= LVIS_SELECTED;
2305 else
2306 lvItem.state &= ~LVIS_SELECTED;
2307
2308 if (uFlags & SVSI_FOCUSED)
2309 lvItem.state &= ~LVIS_FOCUSED;
2310 }
2311 else
2312 {
2313 if (uFlags & SVSI_DESELECTOTHERS)
2314 lvItem.state &= ~LVIS_SELECTED;
2315 }
2316
2317 SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2318 lvItem.iItem++;
2319 }
2320
2321
2322 if(uFlags & SVSI_EDIT)
2323 SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
2324 }
2325
2326 return S_OK;
2327 }
2328
2329 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2330 {
2331 HRESULT hr = E_NOINTERFACE;
2332
2333 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2334
2335 *ppvOut = NULL;
2336
2337 switch (uItem)
2338 {
2339 case SVGIO_BACKGROUND:
2340 if (IsEqualIID(riid, IID_IContextMenu))
2341 {
2342 //*ppvOut = ISvBgCm_Constructor(pSFParent, FALSE);
2343 CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2344 if (!ppvOut)
2345 hr = E_OUTOFMEMORY;
2346 else
2347 hr = S_OK;
2348 }
2349 break;
2350
2351 case SVGIO_SELECTION:
2352 GetSelections();
2353 hr = pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, riid, 0, ppvOut);
2354 break;
2355 }
2356
2357 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2358
2359 return hr;
2360 }
2361
2362 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2363 {
2364 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2365
2366 if (!pViewMode)
2367 return E_INVALIDARG;
2368
2369 *pViewMode = this->FolderSettings.ViewMode;
2370 return S_OK;
2371 }
2372
2373 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2374 {
2375 DWORD dwStyle;
2376 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2377
2378 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) /* && (ViewMode != FVM_AUTO) */ )
2379 return E_INVALIDARG;
2380
2381 /* Windows before Vista uses LVM_SETVIEW and possibly
2382 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2383 while later versions seem to accomplish this through other
2384 means. */
2385 switch (ViewMode)
2386 {
2387 case FVM_ICON:
2388 dwStyle = LVS_ICON;
2389 break;
2390 case FVM_DETAILS:
2391 dwStyle = LVS_REPORT;
2392 break;
2393 case FVM_SMALLICON:
2394 dwStyle = LVS_SMALLICON;
2395 break;
2396 case FVM_LIST:
2397 dwStyle = LVS_LIST;
2398 break;
2399 default:
2400 {
2401 FIXME("ViewMode %d not implemented\n", ViewMode);
2402 dwStyle = LVS_LIST;
2403 break;
2404 }
2405 }
2406
2407 SetStyle(dwStyle, LVS_TYPEMASK);
2408
2409 /* This will not necessarily be the actual mode set above.
2410 This mimics the behavior of Windows XP. */
2411 this->FolderSettings.ViewMode = ViewMode;
2412
2413 return S_OK;
2414 }
2415
2416 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2417 {
2418 if (pSFParent == NULL)
2419 return E_FAIL;
2420
2421 return pSFParent->QueryInterface(riid, ppv);
2422 }
2423
2424 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2425 {
2426 LVITEMW item;
2427
2428 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2429
2430 item.mask = LVIF_PARAM;
2431 item.iItem = iItemIndex;
2432
2433 if (SendMessageW(this->hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2434 {
2435 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2436 return S_OK;
2437 }
2438
2439 *ppidl = 0;
2440
2441 return E_INVALIDARG;
2442 }
2443
2444 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2445 {
2446 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2447
2448 if (uFlags != SVGIO_ALLVIEW)
2449 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2450
2451 *pcItems = SendMessageW(this->hWndList, LVM_GETITEMCOUNT, 0, 0);
2452
2453 return S_OK;
2454 }
2455
2456 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2457 {
2458 return E_NOTIMPL;
2459 }
2460
2461 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2462 {
2463 TRACE("(%p)->(%p)\n", this, piItem);
2464
2465 *piItem = SendMessageW(this->hWndList, LVM_GETSELECTIONMARK, 0, 0);
2466
2467 return S_OK;
2468 }
2469
2470 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2471 {
2472 TRACE("(%p)->(%p)\n", this, piItem);
2473
2474 *piItem = SendMessageW(this->hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2475
2476 return S_OK;
2477 }
2478
2479 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2480 {
2481 return E_NOTIMPL;
2482 }
2483
2484 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2485 {
2486 TRACE("(%p)->(%p)\n", this, ppt);
2487
2488 if (NULL == this->hWndList) return S_FALSE;
2489
2490 if (ppt)
2491 {
2492 const DWORD ret = SendMessageW(this->hWndList, LVM_GETITEMSPACING, 0, 0);
2493
2494 ppt->x = LOWORD(ret);
2495 ppt->y = HIWORD(ret);
2496 }
2497
2498 return S_OK;
2499 }
2500
2501 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2502 {
2503 return E_NOTIMPL;
2504 }
2505
2506 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2507 {
2508 return E_NOTIMPL;
2509 }
2510
2511 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2512 {
2513 LVITEMW lvItem;
2514
2515 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2516
2517 lvItem.state = 0;
2518 lvItem.stateMask = LVIS_SELECTED;
2519
2520 if (dwFlags & SVSI_ENSUREVISIBLE)
2521 SendMessageW(this->hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2522
2523 /* all items */
2524 if (dwFlags & SVSI_DESELECTOTHERS)
2525 SendMessageW(this->hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2526
2527 /* this item */
2528 if (dwFlags & SVSI_SELECT)
2529 lvItem.state |= LVIS_SELECTED;
2530
2531 if (dwFlags & SVSI_FOCUSED)
2532 lvItem.stateMask |= LVIS_FOCUSED;
2533
2534 SendMessageW(this->hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2535
2536 if (dwFlags & SVSI_EDIT)
2537 SendMessageW(this->hWndList, LVM_EDITLABELW, iItem, 0);
2538
2539 return S_OK;
2540 }
2541
2542 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2543 {
2544 return E_NOTIMPL;
2545 }
2546
2547 /**********************************************************
2548 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2549 */
2550 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2551 {
2552 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2553 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2554
2555 if (!prgCmds)
2556 return E_INVALIDARG;
2557
2558 for (UINT i = 0; i < cCmds; i++)
2559 {
2560 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2561 prgCmds[i].cmdf = 0;
2562 }
2563
2564 return OLECMDERR_E_UNKNOWNGROUP;
2565 }
2566
2567 /**********************************************************
2568 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2569 *
2570 * nCmdID is the OLECMDID_* enumeration
2571 */
2572 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2573 {
2574 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2575 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2576
2577 if (!pguidCmdGroup)
2578 return OLECMDERR_E_UNKNOWNGROUP;
2579
2580 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2581 (nCmdID == 0x29) &&
2582 (nCmdexecopt == 4) && pvaOut)
2583 return S_OK;
2584
2585 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2586 (nCmdID == 9) &&
2587 (nCmdexecopt == 0))
2588 return 1;
2589
2590 return OLECMDERR_E_UNKNOWNGROUP;
2591 }
2592
2593 /**********************************************************
2594 * ISVDropTarget implementation
2595 */
2596
2597 /******************************************************************************
2598 * drag_notify_subitem [Internal]
2599 *
2600 * Figure out the shellfolder object, which is currently under the mouse cursor
2601 * and notify it via the IDropTarget interface.
2602 */
2603
2604 #define SCROLLAREAWIDTH 20
2605
2606 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2607 {
2608 LVHITTESTINFO htinfo;
2609 LVITEMW lvItem;
2610 LONG lResult;
2611 HRESULT hr;
2612 RECT clientRect;
2613
2614 /* Map from global to client coordinates and query the index of the listview-item, which is
2615 * currently under the mouse cursor. */
2616 htinfo.pt.x = pt.x;
2617 htinfo.pt.y = pt.y;
2618 htinfo.flags = LVHT_ONITEM;
2619 ::ScreenToClient(hWndList, &htinfo.pt);
2620 lResult = SendMessageW(hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2621
2622 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2623 ::GetClientRect(hWndList, &clientRect);
2624 if (htinfo.pt.x == ptLastMousePos.x && htinfo.pt.y == ptLastMousePos.y &&
2625 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2626 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2627 {
2628 cScrollDelay = (cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2629 if (cScrollDelay == 0)
2630 {
2631 /* Mouse did hover another 250 ms over the scroll-area */
2632 if (htinfo.pt.x < SCROLLAREAWIDTH)
2633 SendMessageW(hWndList, WM_HSCROLL, SB_LINEUP, 0);
2634
2635 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2636 SendMessageW(hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2637
2638 if (htinfo.pt.y < SCROLLAREAWIDTH)
2639 SendMessageW(hWndList, WM_VSCROLL, SB_LINEUP, 0);
2640
2641 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2642 SendMessageW(hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2643 }
2644 }
2645 else
2646 {
2647 cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2648 }
2649
2650 ptLastMousePos = htinfo.pt;
2651
2652 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2653 if (pCurDropTarget && lResult == iDragOverItem)
2654 return pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2655
2656 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2657 if (pCurDropTarget)
2658 {
2659 pCurDropTarget->DragLeave();
2660 pCurDropTarget.Release();
2661 }
2662
2663 iDragOverItem = lResult;
2664 if (lResult == -1)
2665 {
2666 /* We are not above one of the listview's subitems. Bind to the parent folder's
2667 * DropTarget interface. */
2668 hr = pSFParent->QueryInterface(IID_IDropTarget,
2669 (LPVOID*)&pCurDropTarget);
2670 }
2671 else
2672 {
2673 /* Query the relative PIDL of the shellfolder object represented by the currently
2674 * dragged over listview-item ... */
2675 lvItem.mask = LVIF_PARAM;
2676 lvItem.iItem = lResult;
2677 lvItem.iSubItem = 0;
2678 SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2679
2680 /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2681 hr = pSFParent->GetUIObjectOf(hWndList, 1,
2682 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&pCurDropTarget);
2683 }
2684
2685 /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2686 if (FAILED(hr))
2687 return hr;
2688
2689 /* Notify the item just entered via DragEnter. */
2690 return pCurDropTarget->DragEnter(pCurDataObject, grfKeyState, pt, pdwEffect);
2691 }
2692
2693 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2694 {
2695 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2696 pCurDataObject = pDataObject;
2697 pDataObject->AddRef();
2698
2699 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2700 }
2701
2702 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2703 {
2704 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2705 }
2706
2707 HRESULT WINAPI CDefView::DragLeave()
2708 {
2709 if (pCurDropTarget)
2710 {
2711 pCurDropTarget->DragLeave();
2712 pCurDropTarget.Release();
2713 }
2714
2715 if (pCurDataObject != NULL)
2716 {
2717 pCurDataObject.Release();
2718 }
2719
2720 iDragOverItem = 0;
2721
2722 return S_OK;
2723 }
2724
2725 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2726 {
2727 if (pCurDropTarget)
2728 {
2729 pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2730 pCurDropTarget.Release();
2731 }
2732
2733 pCurDataObject.Release();
2734 iDragOverItem = 0;
2735
2736 return S_OK;
2737 }
2738
2739 /**********************************************************
2740 * ISVDropSource implementation
2741 */
2742
2743 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2744 {
2745 TRACE("(%p)\n", this);
2746
2747 if (fEscapePressed)
2748 return DRAGDROP_S_CANCEL;
2749 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2750 return DRAGDROP_S_DROP;
2751 else
2752 return NOERROR;
2753 }
2754
2755 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2756 {
2757 TRACE("(%p)\n", this);
2758
2759 return DRAGDROP_S_USEDEFAULTCURSORS;
2760 }
2761
2762 /**********************************************************
2763 * ISVViewObject implementation
2764 */
2765
2766 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)
2767 {
2768 FIXME("Stub: this=%p\n", this);
2769
2770 return E_NOTIMPL;
2771 }
2772
2773 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2774 {
2775 FIXME("Stub: this=%p\n", this);
2776
2777 return E_NOTIMPL;
2778 }
2779
2780 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2781 {
2782 FIXME("Stub: this=%p\n", this);
2783
2784 return E_NOTIMPL;
2785 }
2786
2787 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2788 {
2789 FIXME("Stub: this=%p\n", this);
2790
2791 return E_NOTIMPL;
2792 }
2793
2794 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2795 {
2796 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2797
2798 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2799 pAdvSink = pAdvSink;
2800 dwAspects = aspects;
2801 dwAdvf = advf;
2802
2803 return S_OK;
2804 }
2805
2806 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2807 {
2808 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2809
2810 if (ppAdvSink)
2811 {
2812 *ppAdvSink = pAdvSink;
2813 pAdvSink.p->AddRef();
2814 }
2815
2816 if (pAspects)
2817 *pAspects = dwAspects;
2818
2819 if (pAdvf)
2820 *pAdvf = dwAdvf;
2821
2822 return S_OK;
2823 }
2824
2825 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2826 {
2827 if (IsEqualIID(guidService, SID_IShellBrowser))
2828 return pShellBrowser->QueryInterface(riid, ppvObject);
2829 else if(IsEqualIID(guidService, SID_IFolderView))
2830 return QueryInterface(riid, ppvObject);
2831
2832 return E_NOINTERFACE;
2833 }
2834
2835 /**********************************************************
2836 * IShellView_Constructor
2837 */
2838 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2839 {
2840 CComObject<CDefView> *theView;
2841 CComPtr<IShellView> result;
2842 HRESULT hResult;
2843
2844 if (newView == NULL)
2845 return E_POINTER;
2846
2847 *newView = NULL;
2848 ATLTRY (theView = new CComObject<CDefView>);
2849
2850 if (theView == NULL)
2851 return E_OUTOFMEMORY;
2852
2853 hResult = theView->QueryInterface (IID_IShellView, (void **)&result);
2854 if (FAILED (hResult))
2855 {
2856 delete theView;
2857 return hResult;
2858 }
2859
2860 hResult = theView->Initialize (pFolder);
2861 if (FAILED (hResult))
2862 return hResult;
2863 *newView = result.Detach ();
2864
2865 return S_OK;
2866 }