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