1caa3f91f87db9440ad1b135e2fccecc06a42b8f
[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 DeleteMenu(m_hMenu, 0, MF_BYPOSITION);
1387 }
1388
1389 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
1390 }
1391
1392 /*merge the menus */
1393
1394 if(m_hMenu)
1395 {
1396 /*build the top level menu get the menu item's text*/
1397 strcpy(szText, "dummy 31");
1398
1399 ZeroMemory(&mii, sizeof(mii));
1400 mii.cbSize = sizeof(mii);
1401 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1402 mii.fType = MFT_STRING;
1403 mii.fState = MFS_ENABLED;
1404 mii.dwTypeData = szText;
1405 mii.hSubMenu = BuildFileMenu();
1406
1407 /*get the view menu so we can merge with it*/
1408 ZeroMemory(&mii, sizeof(mii));
1409 mii.cbSize = sizeof(mii);
1410 mii.fMask = MIIM_SUBMENU;
1411
1412 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1413 {
1414 MergeViewMenu(mii.hSubMenu);
1415 }
1416
1417 /*add the items that should only be added if we have the focus*/
1418 if (SVUIA_ACTIVATE_FOCUS == uState)
1419 {
1420 /*get the file menu so we can merge with it */
1421 ZeroMemory(&mii, sizeof(mii));
1422 mii.cbSize = sizeof(mii);
1423 mii.fMask = MIIM_SUBMENU;
1424
1425 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1426 {
1427 MergeFileMenu(mii.hSubMenu);
1428 }
1429
1430 ::SetFocus(m_hWndList);
1431 }
1432
1433 TRACE("-- before fnSetMenuSB\n");
1434 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1435 }
1436 }
1437 m_uState = uState;
1438 TRACE("--\n");
1439 }
1440
1441 /**********************************************************
1442 * ShellView_OnActivate()
1443 */
1444 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1445 {
1446 DoActivate(SVUIA_ACTIVATE_FOCUS);
1447 return 0;
1448 }
1449
1450 /**********************************************************
1451 * ShellView_OnSetFocus()
1452 *
1453 */
1454 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1455 {
1456 TRACE("%p\n", this);
1457
1458 /* Tell the browser one of our windows has received the focus. This
1459 should always be done before merging menus (OnActivate merges the
1460 menus) if one of our windows has the focus.*/
1461
1462 m_pShellBrowser->OnViewWindowActive((IShellView *)this);
1463 DoActivate(SVUIA_ACTIVATE_FOCUS);
1464
1465 /* Set the focus to the listview */
1466 ::SetFocus(m_hWndList);
1467
1468 /* Notify the ICommDlgBrowser interface */
1469 OnStateChange(CDBOSC_SETFOCUS);
1470
1471 return 0;
1472 }
1473
1474 /**********************************************************
1475 * ShellView_OnKillFocus()
1476 */
1477 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1478 {
1479 TRACE("(%p) stub\n", this);
1480
1481 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1482 /* Notify the ICommDlgBrowser */
1483 OnStateChange(CDBOSC_KILLFOCUS);
1484
1485 return 0;
1486 }
1487
1488 /**********************************************************
1489 * ShellView_OnCommand()
1490 *
1491 * NOTES
1492 * the CmdID's are the ones from the context menu
1493 */
1494 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1495 {
1496 DWORD dwCmdID;
1497 DWORD dwCmd;
1498 HWND hwndCmd;
1499
1500 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1501 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1502 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1503
1504 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1505
1506 switch (dwCmdID)
1507 {
1508 case FCIDM_SHVIEW_SMALLICON:
1509 m_FolderSettings.ViewMode = FVM_SMALLICON;
1510 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1511 CheckToolbar();
1512 break;
1513
1514 case FCIDM_SHVIEW_BIGICON:
1515 m_FolderSettings.ViewMode = FVM_ICON;
1516 SetStyle (LVS_ICON, LVS_TYPEMASK);
1517 CheckToolbar();
1518 break;
1519
1520 case FCIDM_SHVIEW_LISTVIEW:
1521 m_FolderSettings.ViewMode = FVM_LIST;
1522 SetStyle (LVS_LIST, LVS_TYPEMASK);
1523 CheckToolbar();
1524 break;
1525
1526 case FCIDM_SHVIEW_REPORTVIEW:
1527 m_FolderSettings.ViewMode = FVM_DETAILS;
1528 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1529 CheckToolbar();
1530 break;
1531
1532 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1533 case 0x30:
1534 case 0x31:
1535 case 0x32:
1536 case 0x33:
1537 m_sortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1538 m_sortInfo.bIsAscending = TRUE;
1539 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1540 SendMessageA(m_hWndList, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1541 break;
1542
1543 case FCIDM_SHVIEW_REFRESH:
1544 Refresh();
1545 break;
1546
1547 case FCIDM_SHVIEW_DELETE:
1548 case FCIDM_SHVIEW_CUT:
1549 case FCIDM_SHVIEW_COPY:
1550 case FCIDM_SHVIEW_RENAME:
1551 return OnExplorerCommand(dwCmdID, TRUE);
1552
1553 case FCIDM_SHVIEW_INSERT:
1554 case FCIDM_SHVIEW_UNDO:
1555 case FCIDM_SHVIEW_INSERTLINK:
1556 case FCIDM_SHVIEW_NEWFOLDER:
1557 return OnExplorerCommand(dwCmdID, FALSE);
1558 default:
1559 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1560 }
1561
1562 return 0;
1563 }
1564
1565 /**********************************************************
1566 * ShellView_OnNotify()
1567 */
1568
1569 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1570 {
1571 UINT CtlID;
1572 LPNMHDR lpnmh;
1573 LPNMLISTVIEW lpnmlv;
1574 NMLVDISPINFOW *lpdi;
1575 LPITEMIDLIST pidl;
1576 BOOL unused;
1577
1578 CtlID = wParam;
1579 lpnmh = (LPNMHDR)lParam;
1580 lpnmlv = (LPNMLISTVIEW)lpnmh;
1581 lpdi = (NMLVDISPINFOW *)lpnmh;
1582
1583 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1584
1585 switch (lpnmh->code)
1586 {
1587 case NM_SETFOCUS:
1588 TRACE("-- NM_SETFOCUS %p\n", this);
1589 OnSetFocus(0, 0, 0, unused);
1590 break;
1591
1592 case NM_KILLFOCUS:
1593 TRACE("-- NM_KILLFOCUS %p\n", this);
1594 OnDeactivate();
1595 /* Notify the ICommDlgBrowser interface */
1596 OnStateChange(CDBOSC_KILLFOCUS);
1597 break;
1598
1599 case NM_CUSTOMDRAW:
1600 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1601 return CDRF_DODEFAULT;
1602
1603 case NM_RELEASEDCAPTURE:
1604 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1605 break;
1606
1607 case NM_CLICK:
1608 TRACE("-- NM_CLICK %p\n", this);
1609 break;
1610
1611 case NM_RCLICK:
1612 TRACE("-- NM_RCLICK %p\n", this);
1613 break;
1614
1615 case NM_DBLCLK:
1616 TRACE("-- NM_DBLCLK %p\n", this);
1617 OpenSelectedItems();
1618 break;
1619
1620 case NM_RETURN:
1621 TRACE("-- NM_RETURN %p\n", this);
1622 OpenSelectedItems();
1623 break;
1624
1625 case HDN_ENDTRACKW:
1626 TRACE("-- HDN_ENDTRACKW %p\n", this);
1627 /*nColumn1 = ListView_GetColumnWidth(m_hWndList, 0);
1628 nColumn2 = ListView_GetColumnWidth(m_hWndList, 1);*/
1629 break;
1630
1631 case LVN_DELETEITEM:
1632 TRACE("-- LVN_DELETEITEM %p\n", this);
1633 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1634 break;
1635
1636 case LVN_DELETEALLITEMS:
1637 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1638 return FALSE;
1639
1640 case LVN_INSERTITEM:
1641 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1642 break;
1643
1644 case LVN_ITEMACTIVATE:
1645 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1646 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1647 break;
1648
1649 case LVN_COLUMNCLICK:
1650 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1651 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1652 {
1653 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1654 }
1655 else
1656 {
1657 m_sortInfo.bIsAscending = TRUE;
1658 }
1659 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1660
1661 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1662 break;
1663
1664 case LVN_GETDISPINFOA:
1665 case LVN_GETDISPINFOW:
1666 TRACE("-- LVN_GETDISPINFO %p\n", this);
1667 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1668
1669 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1670 {
1671 if (m_pSF2Parent)
1672 {
1673 SHELLDETAILS sd;
1674 if (FAILED(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1675 {
1676 FIXME("failed to get details\n");
1677 break;
1678 }
1679
1680 if (lpnmh->code == LVN_GETDISPINFOA)
1681 {
1682 /* shouldn't happen */
1683 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1684 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1685 TRACE("-- text=%s\n", lpdiA->item.pszText);
1686 }
1687 else /* LVN_GETDISPINFOW */
1688 {
1689 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1690 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1691 }
1692 }
1693 else
1694 {
1695 FIXME("no SF2\n");
1696 }
1697 }
1698 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1699 {
1700 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1701 }
1702 lpdi->item.mask |= LVIF_DI_SETITEM;
1703 break;
1704
1705 case LVN_ITEMCHANGED:
1706 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1707 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1708 break;
1709
1710 case LVN_BEGINDRAG:
1711 case LVN_BEGINRDRAG:
1712 TRACE("-- LVN_BEGINDRAG\n");
1713
1714 if (GetSelections())
1715 {
1716 IDataObject * pda;
1717 DWORD dwAttributes = SFGAO_CANLINK;
1718 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1719
1720 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
1721 {
1722 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1723
1724 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, (LPCITEMIDLIST*)m_apidl, &dwAttributes)))
1725 {
1726 if (dwAttributes & SFGAO_CANLINK)
1727 {
1728 dwEffect |= DROPEFFECT_LINK;
1729 }
1730 }
1731
1732 CComPtr<IAsyncOperation> piaso;
1733 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
1734 {
1735 piaso->SetAsyncMode(TRUE);
1736 piaso->Release();
1737 }
1738
1739 if (pds)
1740 { DWORD dwEffect2;
1741 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1742 }
1743 pda->Release();
1744 }
1745 }
1746 break;
1747
1748 case LVN_BEGINLABELEDITW:
1749 {
1750 DWORD dwAttr = SFGAO_CANRENAME;
1751 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1752
1753 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1754
1755 m_pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1756 if (SFGAO_CANRENAME & dwAttr)
1757 {
1758 return FALSE;
1759 }
1760 return TRUE;
1761 }
1762
1763 case LVN_ENDLABELEDITW:
1764 {
1765 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1766 if (lpdi->item.pszText)
1767 {
1768 HRESULT hr;
1769 LVITEMW lvItem;
1770
1771 lvItem.iItem = lpdi->item.iItem;
1772 lvItem.iSubItem = 0;
1773 lvItem.mask = LVIF_PARAM;
1774 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1775
1776 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1777 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1778
1779 if (SUCCEEDED(hr) && pidl)
1780 {
1781 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1782 lvItem.lParam = (LPARAM)pidl;
1783 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1784 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1785 SendMessageW(m_hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1786
1787 return TRUE;
1788 }
1789 }
1790
1791 return FALSE;
1792 }
1793
1794 default:
1795 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1796 break;
1797 }
1798
1799 return 0;
1800 }
1801
1802 /**********************************************************
1803 * ShellView_OnChange()
1804 */
1805 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1806 {
1807 LPITEMIDLIST *Pidls;
1808
1809 Pidls = (LPITEMIDLIST *)wParam;
1810
1811 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1812
1813 switch (lParam)
1814 {
1815 case SHCNE_MKDIR:
1816 case SHCNE_CREATE:
1817 LV_AddItem(Pidls[0]);
1818 break;
1819
1820 case SHCNE_RMDIR:
1821 case SHCNE_DELETE:
1822 LV_DeleteItem(Pidls[0]);
1823 break;
1824
1825 case SHCNE_RENAMEFOLDER:
1826 case SHCNE_RENAMEITEM:
1827 LV_RenameItem(Pidls[0], Pidls[1]);
1828 break;
1829
1830 case SHCNE_UPDATEITEM:
1831 LV_RenameItem(Pidls[0], Pidls[0]);
1832 break;
1833
1834 case SHCNE_UPDATEDIR:
1835 Refresh();
1836 break;
1837 }
1838 return TRUE;
1839 }
1840
1841 /**********************************************************
1842 * CDefView::OnCustomItem
1843 */
1844 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1845 {
1846 if (!m_pCM.p)
1847 {
1848 /* no menu */
1849 ERR("no menu!!!\n");
1850 return FALSE;
1851 }
1852
1853 CComPtr<IContextMenu2> pCM2;
1854 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1855 if(FAILED(hres))
1856 return FALSE;
1857
1858 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1859 return TRUE;
1860 else
1861 return FALSE;
1862 }
1863
1864 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1865 {
1866 /* Wallpaper setting affects drop shadows effect */
1867 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1868 UpdateListColors();
1869
1870 return S_OK;
1871 }
1872
1873 /**********************************************************
1874 *
1875 *
1876 * The INTERFACE of the IShellView object
1877 *
1878 *
1879 **********************************************************
1880 */
1881
1882 /**********************************************************
1883 * ShellView_GetWindow
1884 */
1885 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1886 {
1887 TRACE("(%p)\n", this);
1888
1889 *phWnd = m_hWnd;
1890
1891 return S_OK;
1892 }
1893
1894 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1895 {
1896 FIXME("(%p) stub\n", this);
1897
1898 return E_NOTIMPL;
1899 }
1900
1901 /**********************************************************
1902 * IShellView_TranslateAccelerator
1903 *
1904 * FIXME:
1905 * use the accel functions
1906 */
1907 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1908 {
1909 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1910 {
1911 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1912 return S_OK;
1913
1914 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1915 }
1916
1917 return S_FALSE; /* not handled */
1918 }
1919
1920 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1921 {
1922 FIXME("(%p) stub\n", this);
1923
1924 return E_NOTIMPL;
1925 }
1926
1927 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1928 {
1929 /*
1930 CHAR szName[MAX_PATH];
1931 */
1932 LRESULT lResult;
1933 int nPartArray[1] = { -1};
1934
1935 TRACE("(%p)->(state=%x) stub\n", this, uState);
1936
1937 /*don't do anything if the state isn't really changing*/
1938 if (m_uState == uState)
1939 {
1940 return S_OK;
1941 }
1942
1943 /*OnActivate handles the menu merging and internal state*/
1944 DoActivate(uState);
1945
1946 /*only do This if we are active*/
1947 if (uState != SVUIA_DEACTIVATE)
1948 {
1949
1950 /*
1951 GetFolderPath is not a method of IShellFolder
1952 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1953 */
1954 /* set the number of parts */
1955 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1956
1957 /* set the text for the parts */
1958 /*
1959 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1960 */
1961 }
1962
1963 return S_OK;
1964 }
1965
1966 HRESULT WINAPI CDefView::Refresh()
1967 {
1968 TRACE("(%p)\n", this);
1969
1970 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1971 FillList();
1972
1973 return S_OK;
1974 }
1975
1976 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1977 {
1978 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
1979
1980 *phWnd = 0;
1981
1982 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1983
1984 if (lpfs != NULL)
1985 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1986 if (prcView != NULL)
1987 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1988
1989 /* Validate the Shell Browser */
1990 if (psb == NULL)
1991 return E_UNEXPECTED;
1992
1993 /*set up the member variables*/
1994 m_pShellBrowser = psb;
1995 m_FolderSettings = *lpfs;
1996
1997 /*get our parent window*/
1998 m_pShellBrowser->GetWindow(&m_hWndParent);
1999
2000 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2001 m_pCommDlgBrowser = NULL;
2002 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2003 {
2004 TRACE("-- CommDlgBrowser\n");
2005 }
2006
2007 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
2008 if (m_hWnd == NULL)
2009 return E_FAIL;
2010
2011 *phWnd = m_hWnd;
2012
2013 CheckToolbar();
2014
2015 if (!*phWnd)
2016 return E_FAIL;
2017
2018 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2019 UpdateWindow();
2020
2021 if (!m_hMenu)
2022 {
2023 m_hMenu = CreateMenu();
2024 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2025 TRACE("-- after fnInsertMenusSB\n");
2026 }
2027
2028 return S_OK;
2029 }
2030
2031 HRESULT WINAPI CDefView::DestroyViewWindow()
2032 {
2033 TRACE("(%p)\n", this);
2034
2035 /*Make absolutely sure all our UI is cleaned up.*/
2036 UIActivate(SVUIA_DEACTIVATE);
2037
2038 if (m_hMenu)
2039 {
2040 DestroyMenu(m_hMenu);
2041 }
2042
2043 DestroyWindow();
2044 m_pShellBrowser.Release();
2045 m_pCommDlgBrowser.Release();
2046
2047 return S_OK;
2048 }
2049
2050 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2051 {
2052 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2053 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2054
2055 if (!lpfs)
2056 return E_INVALIDARG;
2057
2058 *lpfs = m_FolderSettings;
2059 return S_OK;
2060 }
2061
2062 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2063 {
2064 FIXME("(%p) stub\n", this);
2065
2066 return E_NOTIMPL;
2067 }
2068
2069 HRESULT WINAPI CDefView::SaveViewState()
2070 {
2071 FIXME("(%p) stub\n", this);
2072
2073 return S_OK;
2074 }
2075
2076 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2077 {
2078 int i;
2079
2080 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2081
2082 i = LV_FindItemByPidl(pidl);
2083
2084 if (i != -1)
2085 {
2086 LVITEMW lvItem;
2087
2088 if(uFlags & SVSI_ENSUREVISIBLE)
2089 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2090
2091 lvItem.mask = LVIF_STATE;
2092 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2093 lvItem.iItem = 0;
2094 lvItem.iSubItem = 0;
2095
2096 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2097 {
2098 if (lvItem.iItem == i)
2099 {
2100 if (uFlags & SVSI_SELECT)
2101 lvItem.state |= LVIS_SELECTED;
2102 else
2103 lvItem.state &= ~LVIS_SELECTED;
2104
2105 if (uFlags & SVSI_FOCUSED)
2106 lvItem.state &= ~LVIS_FOCUSED;
2107 }
2108 else
2109 {
2110 if (uFlags & SVSI_DESELECTOTHERS)
2111 lvItem.state &= ~LVIS_SELECTED;
2112 }
2113
2114 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2115 lvItem.iItem++;
2116 }
2117
2118
2119 if(uFlags & SVSI_EDIT)
2120 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2121 }
2122
2123 return S_OK;
2124 }
2125
2126 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2127 {
2128 HRESULT hr = E_NOINTERFACE;
2129
2130 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2131
2132 *ppvOut = NULL;
2133
2134 switch (uItem)
2135 {
2136 case SVGIO_BACKGROUND:
2137 if (IsEqualIID(riid, IID_IContextMenu))
2138 {
2139 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2140 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2141 if (!ppvOut)
2142 hr = E_OUTOFMEMORY;
2143 else
2144 hr = S_OK;
2145 }
2146 break;
2147
2148 case SVGIO_SELECTION:
2149 GetSelections();
2150 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2151 break;
2152 }
2153
2154 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2155
2156 return hr;
2157 }
2158
2159 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2160 {
2161 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2162
2163 if (!pViewMode)
2164 return E_INVALIDARG;
2165
2166 *pViewMode = m_FolderSettings.ViewMode;
2167 return S_OK;
2168 }
2169
2170 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2171 {
2172 DWORD dwStyle;
2173 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2174
2175 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2176 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2177 return E_INVALIDARG;
2178
2179 /* Windows before Vista uses LVM_SETVIEW and possibly
2180 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2181 while later versions seem to accomplish this through other
2182 means. */
2183 switch (ViewMode)
2184 {
2185 case FVM_ICON:
2186 dwStyle = LVS_ICON;
2187 break;
2188 case FVM_DETAILS:
2189 dwStyle = LVS_REPORT;
2190 break;
2191 case FVM_SMALLICON:
2192 dwStyle = LVS_SMALLICON;
2193 break;
2194 case FVM_LIST:
2195 dwStyle = LVS_LIST;
2196 break;
2197 default:
2198 {
2199 FIXME("ViewMode %d not implemented\n", ViewMode);
2200 dwStyle = LVS_LIST;
2201 break;
2202 }
2203 }
2204
2205 SetStyle(dwStyle, LVS_TYPEMASK);
2206
2207 /* This will not necessarily be the actual mode set above.
2208 This mimics the behavior of Windows XP. */
2209 m_FolderSettings.ViewMode = ViewMode;
2210
2211 return S_OK;
2212 }
2213
2214 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2215 {
2216 if (m_pSFParent == NULL)
2217 return E_FAIL;
2218
2219 return m_pSFParent->QueryInterface(riid, ppv);
2220 }
2221
2222 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2223 {
2224 LVITEMW item;
2225
2226 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2227
2228 item.mask = LVIF_PARAM;
2229 item.iItem = iItemIndex;
2230
2231 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2232 {
2233 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2234 return S_OK;
2235 }
2236
2237 *ppidl = 0;
2238
2239 return E_INVALIDARG;
2240 }
2241
2242 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2243 {
2244 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2245
2246 if (uFlags != SVGIO_ALLVIEW)
2247 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2248
2249 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2250
2251 return S_OK;
2252 }
2253
2254 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2255 {
2256 return E_NOTIMPL;
2257 }
2258
2259 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2260 {
2261 TRACE("(%p)->(%p)\n", this, piItem);
2262
2263 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2264
2265 return S_OK;
2266 }
2267
2268 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2269 {
2270 TRACE("(%p)->(%p)\n", this, piItem);
2271
2272 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2273
2274 return S_OK;
2275 }
2276
2277 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2278 {
2279 return E_NOTIMPL;
2280 }
2281
2282 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2283 {
2284 TRACE("(%p)->(%p)\n", this, ppt);
2285
2286 if (NULL == m_hWndList) return S_FALSE;
2287
2288 if (ppt)
2289 {
2290 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2291
2292 ppt->x = LOWORD(ret);
2293 ppt->y = HIWORD(ret);
2294 }
2295
2296 return S_OK;
2297 }
2298
2299 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2300 {
2301 return E_NOTIMPL;
2302 }
2303
2304 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2305 {
2306 return E_NOTIMPL;
2307 }
2308
2309 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2310 {
2311 LVITEMW lvItem;
2312
2313 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2314
2315 lvItem.state = 0;
2316 lvItem.stateMask = LVIS_SELECTED;
2317
2318 if (dwFlags & SVSI_ENSUREVISIBLE)
2319 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2320
2321 /* all items */
2322 if (dwFlags & SVSI_DESELECTOTHERS)
2323 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2324
2325 /* this item */
2326 if (dwFlags & SVSI_SELECT)
2327 lvItem.state |= LVIS_SELECTED;
2328
2329 if (dwFlags & SVSI_FOCUSED)
2330 lvItem.stateMask |= LVIS_FOCUSED;
2331
2332 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2333
2334 if (dwFlags & SVSI_EDIT)
2335 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2336
2337 return S_OK;
2338 }
2339
2340 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2341 {
2342 return E_NOTIMPL;
2343 }
2344
2345 /**********************************************************
2346 * IShellFolderView implementation
2347 */
2348 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2349 {
2350 FIXME("(%p)->(%ld) stub\n", this, sort);
2351 return E_NOTIMPL;
2352 }
2353
2354 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2355 {
2356 FIXME("(%p)->(%p) stub\n", this, sort);
2357 return E_NOTIMPL;
2358 }
2359
2360 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2361 {
2362 FIXME("(%p) stub\n", this);
2363 return E_NOTIMPL;
2364 }
2365
2366 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2367 {
2368 FIXME("(%p) stub\n", this);
2369 return E_NOTIMPL;
2370 }
2371
2372 HRESULT STDMETHODCALLTYPE CDefView::IShellFolderView_GetAutoArrange()
2373 {
2374 TRACE("(%p)\n", this);
2375 return GetAutoArrange();
2376 }
2377
2378 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2379 {
2380 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2381 return E_NOTIMPL;
2382 }
2383
2384 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
2385 {
2386 TRACE("(%p)->(%p %d)\n", this, pidl, item);
2387 return Item(item, pidl);
2388 }
2389
2390 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
2391 {
2392
2393 TRACE("(%p)->(%p %p)\n", this, pidl, item);
2394
2395 if (pidl)
2396 {
2397 *item = LV_FindItemByPidl(ILFindLastID(pidl));
2398 SendMessageW(m_hWndList, LVM_DELETEITEM, *item, 0);
2399 }
2400 else
2401 {
2402 *item = 0;
2403 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
2404 }
2405
2406 return S_OK;
2407 }
2408
2409 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
2410 {
2411 TRACE("(%p)->(%p)\n", this, count);
2412 return ItemCount(SVGIO_ALLVIEW, reinterpret_cast<INT*>(count));
2413 }
2414
2415 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
2416 {
2417 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
2418 return E_NOTIMPL;
2419 }
2420
2421 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
2422 {
2423 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
2424 return E_NOTIMPL;
2425 }
2426
2427 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
2428 {
2429 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2430 return E_NOTIMPL;
2431 }
2432
2433 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
2434 {
2435 TRACE("(%p)->(%d)\n", this, redraw);
2436 SendMessageW(m_hWndList, WM_SETREDRAW, redraw, 0);
2437 return S_OK;
2438 }
2439
2440 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
2441 {
2442 FIXME("(%p)->(%p) stub\n", this, count);
2443 return E_NOTIMPL;
2444 }
2445
2446 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
2447 {
2448 TRACE("(%p)->(%p %p)\n", this, pidl, items);
2449
2450 *items = GetSelections();
2451
2452 if (*items)
2453 {
2454 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(LPITEMIDLIST)));
2455 if (!*pidl)
2456 {
2457 return E_OUTOFMEMORY;
2458 }
2459
2460 /* it's documented that caller shouldn't PIDLs, only array itself */
2461 memcpy(static_cast<PCUITEMID_CHILD *>(*pidl), m_apidl, *items * sizeof(LPITEMIDLIST));
2462 }
2463
2464 return S_OK;
2465 }
2466
2467 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
2468 {
2469 FIXME("(%p)->(%p) stub\n", this, drop_target);
2470 return E_NOTIMPL;
2471 }
2472
2473 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
2474 {
2475 FIXME("(%p)->(%p) stub\n", this, pt);
2476 return E_NOTIMPL;
2477 }
2478
2479 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
2480 {
2481 FIXME("(%p)->(%p) stub\n", this, pt);
2482 return E_NOTIMPL;
2483 }
2484
2485 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
2486 {
2487 TRACE("(%p)->(%p)\n", this, obj);
2488 return E_NOTIMPL;
2489 }
2490
2491 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
2492 {
2493 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
2494 return E_NOTIMPL;
2495 }
2496
2497 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
2498 {
2499 FIXME("(%p)->(%p) stub\n", this, drop_target);
2500 return E_NOTIMPL;
2501 }
2502
2503 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
2504 {
2505 FIXME("(%p)->(%d) stub\n", this, move);
2506 return E_NOTIMPL;
2507 }
2508
2509 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
2510 {
2511 FIXME("(%p)->(%p) stub\n", this, obj);
2512 return E_NOTIMPL;
2513 }
2514
2515 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
2516 {
2517 FIXME("(%p)->(%p) stub\n", this, spacing);
2518 return E_NOTIMPL;
2519 }
2520
2521 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
2522 {
2523 FIXME("(%p)->(%p %p) stub\n", this, new_cb, old_cb);
2524 return E_NOTIMPL;
2525 }
2526
2527 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
2528 {
2529 FIXME("(%p)->(%d) stub\n", this, flags);
2530 return E_NOTIMPL;
2531 }
2532
2533 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
2534 {
2535 TRACE("(%p)->(%p)\n", this, support);
2536 return S_OK;
2537 }
2538
2539 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
2540 {
2541 FIXME("(%p)->(%p) stub\n", this, disp);
2542 return E_NOTIMPL;
2543 }
2544
2545 /**********************************************************
2546 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2547 */
2548 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2549 {
2550 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2551 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2552
2553 if (!prgCmds)
2554 return E_INVALIDARG;
2555
2556 for (UINT i = 0; i < cCmds; i++)
2557 {
2558 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2559 prgCmds[i].cmdf = 0;
2560 }
2561
2562 return OLECMDERR_E_UNKNOWNGROUP;
2563 }
2564
2565 /**********************************************************
2566 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2567 *
2568 * nCmdID is the OLECMDID_* enumeration
2569 */
2570 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2571 {
2572 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2573 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2574
2575 if (!pguidCmdGroup)
2576 return OLECMDERR_E_UNKNOWNGROUP;
2577
2578 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2579 (nCmdID == 0x29) &&
2580 (nCmdexecopt == 4) && pvaOut)
2581 return S_OK;
2582
2583 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2584 (nCmdID == 9) &&
2585 (nCmdexecopt == 0))
2586 return 1;
2587
2588 return OLECMDERR_E_UNKNOWNGROUP;
2589 }
2590
2591 /**********************************************************
2592 * ISVDropTarget implementation
2593 */
2594
2595 /******************************************************************************
2596 * drag_notify_subitem [Internal]
2597 *
2598 * Figure out the shellfolder object, which is currently under the mouse cursor
2599 * and notify it via the IDropTarget interface.
2600 */
2601
2602 #define SCROLLAREAWIDTH 20
2603
2604 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2605 {
2606 LVHITTESTINFO htinfo;
2607 LVITEMW lvItem;
2608 LONG lResult;
2609 HRESULT hr;
2610 RECT clientRect;
2611
2612 /* Map from global to client coordinates and query the index of the listview-item, which is
2613 * currently under the mouse cursor. */
2614 htinfo.pt.x = pt.x;
2615 htinfo.pt.y = pt.y;
2616 htinfo.flags = LVHT_ONITEM;
2617 ::ScreenToClient(m_hWndList, &htinfo.pt);
2618 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2619
2620 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2621 ::GetClientRect(m_hWndList, &clientRect);
2622 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2623 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2624 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2625 {
2626 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2627 if (m_cScrollDelay == 0)
2628 {
2629 /* Mouse did hover another 250 ms over the scroll-area */
2630 if (htinfo.pt.x < SCROLLAREAWIDTH)
2631 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2632
2633 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2634 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2635
2636 if (htinfo.pt.y < SCROLLAREAWIDTH)
2637 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2638
2639 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2640 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2641 }
2642 }
2643 else
2644 {
2645 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2646 }
2647
2648 m_ptLastMousePos = htinfo.pt;
2649
2650 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2651 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2652 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2653
2654 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2655 if (m_pCurDropTarget)
2656 {
2657 m_pCurDropTarget->DragLeave();
2658 m_pCurDropTarget.Release();
2659 }
2660
2661 m_iDragOverItem = lResult;
2662 if (lResult == -1)
2663 {
2664 /* We are not above one of the listview's subitems. Bind to the parent folder's
2665 * DropTarget interface. */
2666 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2667 }
2668 else
2669 {
2670 /* Query the relative PIDL of the shellfolder object represented by the currently
2671 * dragged over listview-item ... */
2672 lvItem.mask = LVIF_PARAM;
2673 lvItem.iItem = lResult;
2674 lvItem.iSubItem = 0;
2675 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2676
2677 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2678 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1, (LPCITEMIDLIST*)&lvItem.lParam, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
2679 }
2680
2681 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2682 if (FAILED(hr))
2683 return hr;
2684
2685 /* Notify the item just entered via DragEnter. */
2686 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2687 }
2688
2689 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2690 {
2691 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2692 m_pCurDataObject = pDataObject;
2693 pDataObject->AddRef();
2694
2695 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2696 }
2697
2698 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2699 {
2700 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2701 }
2702
2703 HRESULT WINAPI CDefView::DragLeave()
2704 {
2705 if (m_pCurDropTarget)
2706 {
2707 m_pCurDropTarget->DragLeave();
2708 m_pCurDropTarget.Release();
2709 }
2710
2711 if (m_pCurDataObject != NULL)
2712 {
2713 m_pCurDataObject.Release();
2714 }
2715
2716 m_iDragOverItem = 0;
2717
2718 return S_OK;
2719 }
2720
2721 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2722 {
2723 if (m_pCurDropTarget)
2724 {
2725 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2726 m_pCurDropTarget.Release();
2727 }
2728
2729 m_pCurDataObject.Release();
2730 m_iDragOverItem = 0;
2731 return S_OK;
2732 }
2733
2734 /**********************************************************
2735 * ISVDropSource implementation
2736 */
2737
2738 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2739 {
2740 TRACE("(%p)\n", this);
2741
2742 if (fEscapePressed)
2743 return DRAGDROP_S_CANCEL;
2744 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2745 return DRAGDROP_S_DROP;
2746 else
2747 return S_OK;
2748 }
2749
2750 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2751 {
2752 TRACE("(%p)\n", this);
2753
2754 return DRAGDROP_S_USEDEFAULTCURSORS;
2755 }
2756
2757 /**********************************************************
2758 * ISVViewObject implementation
2759 */
2760
2761 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)
2762 {
2763 FIXME("Stub: this=%p\n", this);
2764
2765 return E_NOTIMPL;
2766 }
2767
2768 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2769 {
2770 FIXME("Stub: this=%p\n", this);
2771
2772 return E_NOTIMPL;
2773 }
2774
2775 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2776 {
2777 FIXME("Stub: this=%p\n", this);
2778
2779 return E_NOTIMPL;
2780 }
2781
2782 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2783 {
2784 FIXME("Stub: this=%p\n", this);
2785
2786 return E_NOTIMPL;
2787 }
2788
2789 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2790 {
2791 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2792
2793 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2794 m_pAdvSink = pAdvSink;
2795 m_dwAspects = aspects;
2796 m_dwAdvf = advf;
2797
2798 return S_OK;
2799 }
2800
2801 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2802 {
2803 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2804
2805 if (ppAdvSink)
2806 {
2807 *ppAdvSink = m_pAdvSink;
2808 m_pAdvSink.p->AddRef();
2809 }
2810
2811 if (pAspects)
2812 *pAspects = m_dwAspects;
2813
2814 if (pAdvf)
2815 *pAdvf = m_dwAdvf;
2816
2817 return S_OK;
2818 }
2819
2820 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2821 {
2822 if (IsEqualIID(guidService, SID_IShellBrowser))
2823 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2824 else if(IsEqualIID(guidService, SID_IFolderView))
2825 return QueryInterface(riid, ppvObject);
2826
2827 return E_NOINTERFACE;
2828 }
2829
2830 /**********************************************************
2831 * IShellView_Constructor
2832 */
2833 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2834 {
2835 CComObject<CDefView> *theView;
2836 CComPtr<IShellView> result;
2837 HRESULT hResult;
2838
2839 if (newView == NULL)
2840 return E_POINTER;
2841
2842 *newView = NULL;
2843 ATLTRY (theView = new CComObject<CDefView>);
2844
2845 if (theView == NULL)
2846 return E_OUTOFMEMORY;
2847
2848 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2849 if (FAILED (hResult))
2850 {
2851 delete theView;
2852 return hResult;
2853 }
2854
2855 hResult = theView->Initialize (pFolder);
2856 if (FAILED (hResult))
2857 return hResult;
2858 *newView = result.Detach ();
2859
2860 return S_OK;
2861 }