[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 RevokeDragDrop(m_hWnd);
926 SHChangeNotifyDeregister(m_hNotify);
927 bHandled = FALSE;
928 return 0;
929 }
930
931 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
932 {
933 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
934 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
935
936 bHandled = FALSE;
937 return 0;
938 }
939
940 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
941 {
942 /* Update desktop labels color */
943 UpdateListColors();
944
945 /* Forward WM_SYSCOLORCHANGE to common controls */
946 return SendMessageW(m_hWndList, uMsg, 0, 0);
947 }
948
949 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
950 {
951 return (LRESULT)m_pShellBrowser.p;
952 }
953
954 /**********************************************************
955 * ShellView_OnCreate()
956 */
957 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
958 {
959 CComPtr<IDropTarget> pdt;
960 SHChangeNotifyEntry ntreg;
961 CComPtr<IPersistFolder2> ppf2;
962
963 TRACE("%p\n", this);
964
965 if(CreateList())
966 {
967 if(InitList())
968 {
969 FillList();
970 }
971 }
972
973 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
974 {
975 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
976 ERR("Registering Drag Drop Failed");
977 }
978
979 /* register for receiving notifications */
980 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
981 if (ppf2)
982 {
983 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
984 ntreg.fRecursive = TRUE;
985 m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
986 SHFree((LPITEMIDLIST)ntreg.pidl);
987 }
988
989 m_hAccel = LoadAcceleratorsA(shell32_hInstance, MAKEINTRESOURCEA( IDA_SHELLVIEW));
990
991 return S_OK;
992 }
993
994 /**********************************************************
995 * #### Handling of the menus ####
996 */
997
998 /**********************************************************
999 * ShellView_BuildFileMenu()
1000 */
1001 HMENU CDefView::BuildFileMenu()
1002 { WCHAR szText[MAX_PATH];
1003 MENUITEMINFOW mii;
1004 int nTools, i;
1005 HMENU hSubMenu;
1006
1007 TRACE("(%p)\n", this);
1008
1009 hSubMenu = CreatePopupMenu();
1010 if (hSubMenu)
1011 {
1012 /*get the number of items in our global array*/
1013 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++) {}
1014
1015 /*add the menu items*/
1016 for(i = 0; i < nTools; i++)
1017 {
1018 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
1019
1020 ZeroMemory(&mii, sizeof(mii));
1021 mii.cbSize = sizeof(mii);
1022 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
1023
1024 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
1025 {
1026 mii.fType = MFT_STRING;
1027 mii.fState = MFS_ENABLED;
1028 mii.dwTypeData = szText;
1029 mii.wID = Tools[i].idCommand;
1030 }
1031 else
1032 {
1033 mii.fType = MFT_SEPARATOR;
1034 }
1035 /* tack This item onto the end of the menu */
1036 InsertMenuItemW(hSubMenu, (UINT) - 1, TRUE, &mii);
1037 }
1038 }
1039
1040 TRACE("-- return (menu=%p)\n", hSubMenu);
1041 return hSubMenu;
1042 }
1043
1044 /**********************************************************
1045 * ShellView_MergeFileMenu()
1046 */
1047 void CDefView::MergeFileMenu(HMENU hSubMenu)
1048 {
1049 TRACE("(%p)->(submenu=%p) stub\n", this, hSubMenu);
1050
1051 if (hSubMenu)
1052 { /*insert This item at the beginning of the menu */
1053 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1054 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM+4, MFT_STRING, L"Properties", MFS_DISABLED);
1055 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM+3, MFT_STRING, L"Rename", MFS_DISABLED);
1056 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM+2, MFT_STRING, L"Delete", MFS_DISABLED);
1057 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM+1, MFT_STRING, L"Create Shortcut", MFS_DISABLED);
1058 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1059 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"New", MFS_ENABLED);
1060 }
1061
1062 TRACE("--\n");
1063 }
1064
1065 /**********************************************************
1066 * ShellView_MergeViewMenu()
1067 */
1068 void CDefView::MergeViewMenu(HMENU hSubMenu)
1069 {
1070 TRACE("(%p)->(submenu=%p)\n", this, hSubMenu);
1071
1072 if (hSubMenu)
1073 {
1074 /*add a separator at the correct position in the menu*/
1075 MENUITEMINFOW mii;
1076 static WCHAR view[] = L"View";
1077
1078 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1079
1080 ZeroMemory(&mii, sizeof(mii));
1081 mii.cbSize = sizeof(mii);
1082 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
1083 mii.fType = MFT_STRING;
1084 mii.dwTypeData = view;
1085 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
1086 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
1087 }
1088 }
1089
1090 /**********************************************************
1091 * ShellView_GetSelections()
1092 *
1093 * - fills the m_apidl list with the selected objects
1094 *
1095 * RETURNS
1096 * number of selected items
1097 */
1098 UINT CDefView::GetSelections()
1099 {
1100 LVITEMW lvItem;
1101 UINT i = 0;
1102
1103 SHFree(m_apidl);
1104
1105 m_cidl = ListView_GetSelectedCount(m_hWndList);
1106 m_apidl = (LPITEMIDLIST*)SHAlloc(m_cidl * sizeof(LPITEMIDLIST));
1107
1108 TRACE("selected=%i\n", m_cidl);
1109
1110 if (m_apidl)
1111 {
1112 TRACE("-- Items selected =%u\n", m_cidl);
1113
1114 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1115 lvItem.stateMask = LVIS_SELECTED;
1116 lvItem.iItem = 0;
1117 lvItem.iSubItem = 0;
1118 lvItem.state = 0;
1119
1120 while(SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < m_cidl))
1121 {
1122 if(lvItem.state & LVIS_SELECTED)
1123 {
1124 m_apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1125 i++;
1126 if (i == m_cidl)
1127 break;
1128 TRACE("-- selected Item found\n");
1129 }
1130 lvItem.iItem++;
1131 }
1132 }
1133
1134 return m_cidl;
1135 }
1136
1137 /**********************************************************
1138 * ShellView_OpenSelectedItems()
1139 */
1140 HRESULT CDefView::OpenSelectedItems()
1141 {
1142 HMENU hMenu;
1143 CMINVOKECOMMANDINFO cmi;
1144 UINT uCommand;
1145 HRESULT hResult;
1146
1147 m_cidl = ListView_GetSelectedCount(m_hWndList);
1148 if (m_cidl == 0)
1149 return S_OK;
1150
1151 hResult = OnDefaultCommand();
1152 if (hResult == S_OK)
1153 return hResult;
1154
1155 hMenu = CreatePopupMenu();
1156 if (!hMenu)
1157 return E_FAIL;
1158
1159 hResult = GetItemObject( SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1160 if (FAILED(hResult))
1161 goto cleanup;
1162
1163 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1164 //if (FAILED( hResult))
1165 // goto cleanup;
1166
1167 hResult = m_pCM->QueryContextMenu(hMenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1168 if (FAILED(hResult))
1169 goto cleanup;
1170
1171 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1172 if (uCommand == (UINT)-1)
1173 {
1174 hResult = E_FAIL;
1175 goto cleanup;
1176 }
1177
1178 ZeroMemory(&cmi, sizeof(cmi));
1179 cmi.cbSize = sizeof(cmi);
1180 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1181 cmi.hwnd = m_hWnd;
1182
1183 hResult = m_pCM->InvokeCommand(&cmi);
1184
1185 cleanup:
1186
1187 if (hMenu)
1188 DestroyMenu(hMenu);
1189
1190 if (m_pCM)
1191 {
1192 IUnknown_SetSite(m_pCM, NULL);
1193 m_pCM.Release();
1194 }
1195
1196 return hResult;
1197 }
1198
1199 /**********************************************************
1200 * ShellView_DoContextMenu()
1201 */
1202 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1203 {
1204 WORD x;
1205 WORD y;
1206 UINT uCommand;
1207 HMENU hMenu;
1208 CMINVOKECOMMANDINFO cmi;
1209 HRESULT hResult;
1210
1211 // for some reason I haven't figured out, we sometimes recurse into this method
1212 if (m_pCM != NULL)
1213 return 0;
1214
1215 x = LOWORD(lParam);
1216 y = HIWORD(lParam);
1217
1218 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1219
1220 hMenu = CreatePopupMenu();
1221 if (!hMenu)
1222 return E_FAIL;
1223
1224 m_cidl = ListView_GetSelectedCount(m_hWndList);
1225
1226 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1227 if (FAILED( hResult))
1228 goto cleanup;
1229
1230 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1231 //if (FAILED( hResult))
1232 // goto cleanup;
1233
1234 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1235 if (FAILED( hResult))
1236 goto cleanup;
1237
1238 if (m_FolderSettings.fFlags & FWF_DESKTOP)
1239 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1240
1241 uCommand = TrackPopupMenu(hMenu,
1242 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1243 x, y, 0, m_hWnd, NULL);
1244 if (uCommand == 0)
1245 goto cleanup;
1246
1247 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1248 goto cleanup;
1249
1250 ZeroMemory(&cmi, sizeof(cmi));
1251 cmi.cbSize = sizeof(cmi);
1252 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1253 cmi.hwnd = m_hWnd;
1254 m_pCM->InvokeCommand(&cmi);
1255
1256 cleanup:
1257
1258 if (m_pCM)
1259 {
1260 IUnknown_SetSite(m_pCM, NULL);
1261 m_pCM.Release();
1262 }
1263
1264 if (hMenu)
1265 DestroyMenu(hMenu);
1266
1267 return 0;
1268 }
1269
1270 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1271 {
1272 HRESULT hResult;
1273 CMINVOKECOMMANDINFO cmi;
1274 HMENU hMenu;
1275
1276 hMenu = CreatePopupMenu();
1277 if (!hMenu)
1278 return 0;
1279
1280 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1281 if (FAILED( hResult))
1282 goto cleanup;
1283
1284 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1285 //if (FAILED( hResult))
1286 // goto cleanup;
1287
1288 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1289 if (FAILED( hResult))
1290 goto cleanup;
1291
1292 ZeroMemory(&cmi, sizeof(cmi));
1293 cmi.cbSize = sizeof(cmi);
1294 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1295 cmi.hwnd = m_hWnd;
1296 m_pCM->InvokeCommand(&cmi);
1297
1298 cleanup:
1299
1300 if (m_pCM)
1301 {
1302 IUnknown_SetSite(m_pCM, NULL);
1303 m_pCM.Release();
1304 }
1305
1306 if (hMenu)
1307 DestroyMenu(hMenu);
1308
1309 return 0;
1310 }
1311
1312 /**********************************************************
1313 * ##### message handling #####
1314 */
1315
1316 /**********************************************************
1317 * ShellView_OnSize()
1318 */
1319 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1320 {
1321 WORD wWidth;
1322 WORD wHeight;
1323
1324 wWidth = LOWORD(lParam);
1325 wHeight = HIWORD(lParam);
1326
1327 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1328
1329 /*resize the ListView to fit our window*/
1330 if (m_hWndList)
1331 {
1332 ::MoveWindow(m_hWndList, 0, 0, wWidth, wHeight, TRUE);
1333 }
1334
1335 return 0;
1336 }
1337
1338 /**********************************************************
1339 * ShellView_OnDeactivate()
1340 *
1341 * NOTES
1342 * internal
1343 */
1344 void CDefView::OnDeactivate()
1345 {
1346 TRACE("%p\n", this);
1347
1348 if (m_uState != SVUIA_DEACTIVATE)
1349 {
1350 // TODO: cleanup menu after deactivation
1351
1352 m_uState = SVUIA_DEACTIVATE;
1353 }
1354 }
1355
1356 void CDefView::DoActivate(UINT uState)
1357 {
1358 MENUITEMINFOA mii;
1359 CHAR szText[MAX_PATH];
1360
1361 TRACE("%p uState=%x\n", this, uState);
1362
1363 /*don't do anything if the state isn't really changing */
1364 if (m_uState == uState)
1365 {
1366 return;
1367 }
1368
1369 OnDeactivate();
1370
1371 /*only do This if we are active */
1372 if(uState != SVUIA_DEACTIVATE)
1373 {
1374 // FIXME: windows does not do this.
1375
1376 // temporary solution (HACK): wipe the contents and refill
1377 {
1378 OLEMENUGROUPWIDTHS omw = { { 0 } };
1379
1380 INT mic = GetMenuItemCount(m_hMenu);
1381 for (int i = 0; i < mic; i++)
1382 {
1383 HMENU submenu = GetSubMenu(m_hMenu, 0);
1384 RemoveMenu(m_hMenu, 0, MF_BYPOSITION);
1385 if (submenu)
1386 DestroyMenu(submenu);
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 case LVN_KEYDOWN:
1795 {
1796 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1797
1798 /* initiate a rename of the selected file or directory */
1799 if (plvKeyDown->wVKey == VK_BACK)
1800 {
1801 LPSHELLBROWSER lpSb;
1802 if ((lpSb = (LPSHELLBROWSER)SendMessageW(m_hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1803 {
1804 lpSb->BrowseObject(NULL, SBSP_PARENT);
1805 }
1806 }
1807
1808 else
1809 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
1810 }
1811 break;
1812
1813 default:
1814 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1815 break;
1816 }
1817
1818 return 0;
1819 }
1820
1821 /**********************************************************
1822 * ShellView_OnChange()
1823 */
1824 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1825 {
1826 LPITEMIDLIST *Pidls;
1827
1828 Pidls = (LPITEMIDLIST *)wParam;
1829
1830 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1831
1832 switch (lParam)
1833 {
1834 case SHCNE_MKDIR:
1835 case SHCNE_CREATE:
1836 LV_AddItem(Pidls[0]);
1837 break;
1838
1839 case SHCNE_RMDIR:
1840 case SHCNE_DELETE:
1841 LV_DeleteItem(Pidls[0]);
1842 break;
1843
1844 case SHCNE_RENAMEFOLDER:
1845 case SHCNE_RENAMEITEM:
1846 LV_RenameItem(Pidls[0], Pidls[1]);
1847 break;
1848
1849 case SHCNE_UPDATEITEM:
1850 LV_RenameItem(Pidls[0], Pidls[0]);
1851 break;
1852
1853 case SHCNE_UPDATEDIR:
1854 Refresh();
1855 break;
1856 }
1857 return TRUE;
1858 }
1859
1860 /**********************************************************
1861 * CDefView::OnCustomItem
1862 */
1863 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1864 {
1865 if (!m_pCM.p)
1866 {
1867 /* no menu */
1868 ERR("no menu!!!\n");
1869 return FALSE;
1870 }
1871
1872 CComPtr<IContextMenu2> pCM2;
1873 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1874 if(FAILED(hres))
1875 return FALSE;
1876
1877 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1878 return TRUE;
1879 else
1880 return FALSE;
1881 }
1882
1883 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1884 {
1885 /* Wallpaper setting affects drop shadows effect */
1886 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1887 UpdateListColors();
1888
1889 return S_OK;
1890 }
1891
1892 /**********************************************************
1893 *
1894 *
1895 * The INTERFACE of the IShellView object
1896 *
1897 *
1898 **********************************************************
1899 */
1900
1901 /**********************************************************
1902 * ShellView_GetWindow
1903 */
1904 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1905 {
1906 TRACE("(%p)\n", this);
1907
1908 *phWnd = m_hWnd;
1909
1910 return S_OK;
1911 }
1912
1913 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1914 {
1915 FIXME("(%p) stub\n", this);
1916
1917 return E_NOTIMPL;
1918 }
1919
1920 /**********************************************************
1921 * IShellView_TranslateAccelerator
1922 *
1923 * FIXME:
1924 * use the accel functions
1925 */
1926 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1927 {
1928 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1929 {
1930 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1931 return S_OK;
1932
1933 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1934 }
1935
1936 return S_FALSE; /* not handled */
1937 }
1938
1939 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1940 {
1941 FIXME("(%p) stub\n", this);
1942
1943 return E_NOTIMPL;
1944 }
1945
1946 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1947 {
1948 /*
1949 CHAR szName[MAX_PATH];
1950 */
1951 LRESULT lResult;
1952 int nPartArray[1] = { -1};
1953
1954 TRACE("(%p)->(state=%x) stub\n", this, uState);
1955
1956 /*don't do anything if the state isn't really changing*/
1957 if (m_uState == uState)
1958 {
1959 return S_OK;
1960 }
1961
1962 /*OnActivate handles the menu merging and internal state*/
1963 DoActivate(uState);
1964
1965 /*only do This if we are active*/
1966 if (uState != SVUIA_DEACTIVATE)
1967 {
1968
1969 /*
1970 GetFolderPath is not a method of IShellFolder
1971 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1972 */
1973 /* set the number of parts */
1974 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1975
1976 /* set the text for the parts */
1977 /*
1978 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1979 */
1980 }
1981
1982 return S_OK;
1983 }
1984
1985 HRESULT WINAPI CDefView::Refresh()
1986 {
1987 TRACE("(%p)\n", this);
1988
1989 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1990 FillList();
1991
1992 return S_OK;
1993 }
1994
1995 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1996 {
1997 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
1998
1999 *phWnd = 0;
2000
2001 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
2002
2003 if (lpfs != NULL)
2004 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
2005 if (prcView != NULL)
2006 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2007
2008 /* Validate the Shell Browser */
2009 if (psb == NULL)
2010 return E_UNEXPECTED;
2011
2012 /*set up the member variables*/
2013 m_pShellBrowser = psb;
2014 m_FolderSettings = *lpfs;
2015
2016 /*get our parent window*/
2017 m_pShellBrowser->GetWindow(&m_hWndParent);
2018
2019 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2020 m_pCommDlgBrowser = NULL;
2021 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2022 {
2023 TRACE("-- CommDlgBrowser\n");
2024 }
2025
2026 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
2027 if (m_hWnd == NULL)
2028 return E_FAIL;
2029
2030 *phWnd = m_hWnd;
2031
2032 CheckToolbar();
2033
2034 if (!*phWnd)
2035 return E_FAIL;
2036
2037 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2038 UpdateWindow();
2039
2040 if (!m_hMenu)
2041 {
2042 m_hMenu = CreateMenu();
2043 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2044 TRACE("-- after fnInsertMenusSB\n");
2045 }
2046
2047 return S_OK;
2048 }
2049
2050 HRESULT WINAPI CDefView::DestroyViewWindow()
2051 {
2052 TRACE("(%p)\n", this);
2053
2054 /*Make absolutely sure all our UI is cleaned up.*/
2055 UIActivate(SVUIA_DEACTIVATE);
2056
2057 if (m_hMenu)
2058 {
2059 DestroyMenu(m_hMenu);
2060 }
2061
2062 DestroyWindow();
2063 m_pShellBrowser.Release();
2064 m_pCommDlgBrowser.Release();
2065
2066 return S_OK;
2067 }
2068
2069 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2070 {
2071 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2072 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2073
2074 if (!lpfs)
2075 return E_INVALIDARG;
2076
2077 *lpfs = m_FolderSettings;
2078 return S_OK;
2079 }
2080
2081 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2082 {
2083 FIXME("(%p) stub\n", this);
2084
2085 return E_NOTIMPL;
2086 }
2087
2088 HRESULT WINAPI CDefView::SaveViewState()
2089 {
2090 FIXME("(%p) stub\n", this);
2091
2092 return S_OK;
2093 }
2094
2095 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2096 {
2097 int i;
2098
2099 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2100
2101 i = LV_FindItemByPidl(pidl);
2102
2103 if (i != -1)
2104 {
2105 LVITEMW lvItem;
2106
2107 if(uFlags & SVSI_ENSUREVISIBLE)
2108 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2109
2110 lvItem.mask = LVIF_STATE;
2111 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2112 lvItem.iItem = 0;
2113 lvItem.iSubItem = 0;
2114
2115 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2116 {
2117 if (lvItem.iItem == i)
2118 {
2119 if (uFlags & SVSI_SELECT)
2120 lvItem.state |= LVIS_SELECTED;
2121 else
2122 lvItem.state &= ~LVIS_SELECTED;
2123
2124 if (uFlags & SVSI_FOCUSED)
2125 lvItem.state &= ~LVIS_FOCUSED;
2126 }
2127 else
2128 {
2129 if (uFlags & SVSI_DESELECTOTHERS)
2130 lvItem.state &= ~LVIS_SELECTED;
2131 }
2132
2133 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2134 lvItem.iItem++;
2135 }
2136
2137
2138 if(uFlags & SVSI_EDIT)
2139 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2140 }
2141
2142 return S_OK;
2143 }
2144
2145 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2146 {
2147 HRESULT hr = E_NOINTERFACE;
2148
2149 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2150
2151 *ppvOut = NULL;
2152
2153 switch (uItem)
2154 {
2155 case SVGIO_BACKGROUND:
2156 if (IsEqualIID(riid, IID_IContextMenu))
2157 {
2158 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2159 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2160 if (!ppvOut)
2161 hr = E_OUTOFMEMORY;
2162 else
2163 hr = S_OK;
2164 }
2165 break;
2166
2167 case SVGIO_SELECTION:
2168 GetSelections();
2169 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2170 break;
2171 }
2172
2173 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2174
2175 return hr;
2176 }
2177
2178 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2179 {
2180 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2181
2182 if (!pViewMode)
2183 return E_INVALIDARG;
2184
2185 *pViewMode = m_FolderSettings.ViewMode;
2186 return S_OK;
2187 }
2188
2189 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2190 {
2191 DWORD dwStyle;
2192 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2193
2194 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2195 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2196 return E_INVALIDARG;
2197
2198 /* Windows before Vista uses LVM_SETVIEW and possibly
2199 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2200 while later versions seem to accomplish this through other
2201 means. */
2202 switch (ViewMode)
2203 {
2204 case FVM_ICON:
2205 dwStyle = LVS_ICON;
2206 break;
2207 case FVM_DETAILS:
2208 dwStyle = LVS_REPORT;
2209 break;
2210 case FVM_SMALLICON:
2211 dwStyle = LVS_SMALLICON;
2212 break;
2213 case FVM_LIST:
2214 dwStyle = LVS_LIST;
2215 break;
2216 default:
2217 {
2218 FIXME("ViewMode %d not implemented\n", ViewMode);
2219 dwStyle = LVS_LIST;
2220 break;
2221 }
2222 }
2223
2224 SetStyle(dwStyle, LVS_TYPEMASK);
2225
2226 /* This will not necessarily be the actual mode set above.
2227 This mimics the behavior of Windows XP. */
2228 m_FolderSettings.ViewMode = ViewMode;
2229
2230 return S_OK;
2231 }
2232
2233 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2234 {
2235 if (m_pSFParent == NULL)
2236 return E_FAIL;
2237
2238 return m_pSFParent->QueryInterface(riid, ppv);
2239 }
2240
2241 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2242 {
2243 LVITEMW item;
2244
2245 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2246
2247 item.mask = LVIF_PARAM;
2248 item.iItem = iItemIndex;
2249
2250 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2251 {
2252 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2253 return S_OK;
2254 }
2255
2256 *ppidl = 0;
2257
2258 return E_INVALIDARG;
2259 }
2260
2261 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2262 {
2263 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2264
2265 if (uFlags != SVGIO_ALLVIEW)
2266 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2267
2268 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2269
2270 return S_OK;
2271 }
2272
2273 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2274 {
2275 return E_NOTIMPL;
2276 }
2277
2278 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2279 {
2280 TRACE("(%p)->(%p)\n", this, piItem);
2281
2282 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2283
2284 return S_OK;
2285 }
2286
2287 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2288 {
2289 TRACE("(%p)->(%p)\n", this, piItem);
2290
2291 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2292
2293 return S_OK;
2294 }
2295
2296 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2297 {
2298 return E_NOTIMPL;
2299 }
2300
2301 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2302 {
2303 TRACE("(%p)->(%p)\n", this, ppt);
2304
2305 if (NULL == m_hWndList) return S_FALSE;
2306
2307 if (ppt)
2308 {
2309 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2310
2311 ppt->x = LOWORD(ret);
2312 ppt->y = HIWORD(ret);
2313 }
2314
2315 return S_OK;
2316 }
2317
2318 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2319 {
2320 return E_NOTIMPL;
2321 }
2322
2323 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2324 {
2325 return E_NOTIMPL;
2326 }
2327
2328 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2329 {
2330 LVITEMW lvItem;
2331
2332 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2333
2334 lvItem.state = 0;
2335 lvItem.stateMask = LVIS_SELECTED;
2336
2337 if (dwFlags & SVSI_ENSUREVISIBLE)
2338 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2339
2340 /* all items */
2341 if (dwFlags & SVSI_DESELECTOTHERS)
2342 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2343
2344 /* this item */
2345 if (dwFlags & SVSI_SELECT)
2346 lvItem.state |= LVIS_SELECTED;
2347
2348 if (dwFlags & SVSI_FOCUSED)
2349 lvItem.stateMask |= LVIS_FOCUSED;
2350
2351 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2352
2353 if (dwFlags & SVSI_EDIT)
2354 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2355
2356 return S_OK;
2357 }
2358
2359 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2360 {
2361 return E_NOTIMPL;
2362 }
2363
2364 /**********************************************************
2365 * IShellFolderView implementation
2366 */
2367 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2368 {
2369 FIXME("(%p)->(%ld) stub\n", this, sort);
2370 return E_NOTIMPL;
2371 }
2372
2373 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2374 {
2375 FIXME("(%p)->(%p) stub\n", this, sort);
2376 return E_NOTIMPL;
2377 }
2378
2379 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2380 {
2381 FIXME("(%p) stub\n", this);
2382 return E_NOTIMPL;
2383 }
2384
2385 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2386 {
2387 FIXME("(%p) stub\n", this);
2388 return E_NOTIMPL;
2389 }
2390
2391 HRESULT STDMETHODCALLTYPE CDefView::IShellFolderView_GetAutoArrange()
2392 {
2393 TRACE("(%p)\n", this);
2394 return GetAutoArrange();
2395 }
2396
2397 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2398 {
2399 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2400 return E_NOTIMPL;
2401 }
2402
2403 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
2404 {
2405 TRACE("(%p)->(%p %d)\n", this, pidl, item);
2406 return Item(item, pidl);
2407 }
2408
2409 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
2410 {
2411
2412 TRACE("(%p)->(%p %p)\n", this, pidl, item);
2413
2414 if (pidl)
2415 {
2416 *item = LV_FindItemByPidl(ILFindLastID(pidl));
2417 SendMessageW(m_hWndList, LVM_DELETEITEM, *item, 0);
2418 }
2419 else
2420 {
2421 *item = 0;
2422 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
2423 }
2424
2425 return S_OK;
2426 }
2427
2428 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
2429 {
2430 TRACE("(%p)->(%p)\n", this, count);
2431 return ItemCount(SVGIO_ALLVIEW, reinterpret_cast<INT*>(count));
2432 }
2433
2434 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
2435 {
2436 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
2437 return E_NOTIMPL;
2438 }
2439
2440 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
2441 {
2442 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
2443 return E_NOTIMPL;
2444 }
2445
2446 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
2447 {
2448 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2449 return E_NOTIMPL;
2450 }
2451
2452 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
2453 {
2454 TRACE("(%p)->(%d)\n", this, redraw);
2455 SendMessageW(m_hWndList, WM_SETREDRAW, redraw, 0);
2456 return S_OK;
2457 }
2458
2459 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
2460 {
2461 FIXME("(%p)->(%p) stub\n", this, count);
2462 return E_NOTIMPL;
2463 }
2464
2465 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
2466 {
2467 TRACE("(%p)->(%p %p)\n", this, pidl, items);
2468
2469 *items = GetSelections();
2470
2471 if (*items)
2472 {
2473 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(LPITEMIDLIST)));
2474 if (!*pidl)
2475 {
2476 return E_OUTOFMEMORY;
2477 }
2478
2479 /* it's documented that caller shouldn't PIDLs, only array itself */
2480 memcpy(static_cast<PCUITEMID_CHILD *>(*pidl), m_apidl, *items * sizeof(LPITEMIDLIST));
2481 }
2482
2483 return S_OK;
2484 }
2485
2486 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
2487 {
2488 FIXME("(%p)->(%p) stub\n", this, drop_target);
2489 return E_NOTIMPL;
2490 }
2491
2492 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
2493 {
2494 FIXME("(%p)->(%p) stub\n", this, pt);
2495 return E_NOTIMPL;
2496 }
2497
2498 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
2499 {
2500 FIXME("(%p)->(%p) stub\n", this, pt);
2501 return E_NOTIMPL;
2502 }
2503
2504 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
2505 {
2506 TRACE("(%p)->(%p)\n", this, obj);
2507 return E_NOTIMPL;
2508 }
2509
2510 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
2511 {
2512 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
2513 return E_NOTIMPL;
2514 }
2515
2516 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
2517 {
2518 FIXME("(%p)->(%p) stub\n", this, drop_target);
2519 return E_NOTIMPL;
2520 }
2521
2522 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
2523 {
2524 FIXME("(%p)->(%d) stub\n", this, move);
2525 return E_NOTIMPL;
2526 }
2527
2528 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
2529 {
2530 FIXME("(%p)->(%p) stub\n", this, obj);
2531 return E_NOTIMPL;
2532 }
2533
2534 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
2535 {
2536 FIXME("(%p)->(%p) stub\n", this, spacing);
2537 return E_NOTIMPL;
2538 }
2539
2540 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
2541 {
2542 FIXME("(%p)->(%p %p) stub\n", this, new_cb, old_cb);
2543 return E_NOTIMPL;
2544 }
2545
2546 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
2547 {
2548 FIXME("(%p)->(%d) stub\n", this, flags);
2549 return E_NOTIMPL;
2550 }
2551
2552 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
2553 {
2554 TRACE("(%p)->(%p)\n", this, support);
2555 return S_OK;
2556 }
2557
2558 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
2559 {
2560 FIXME("(%p)->(%p) stub\n", this, disp);
2561 return E_NOTIMPL;
2562 }
2563
2564 /**********************************************************
2565 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2566 */
2567 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2568 {
2569 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2570 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2571
2572 if (!prgCmds)
2573 return E_INVALIDARG;
2574
2575 for (UINT i = 0; i < cCmds; i++)
2576 {
2577 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2578 prgCmds[i].cmdf = 0;
2579 }
2580
2581 return OLECMDERR_E_UNKNOWNGROUP;
2582 }
2583
2584 /**********************************************************
2585 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2586 *
2587 * nCmdID is the OLECMDID_* enumeration
2588 */
2589 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2590 {
2591 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2592 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2593
2594 if (!pguidCmdGroup)
2595 return OLECMDERR_E_UNKNOWNGROUP;
2596
2597 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2598 (nCmdID == 0x29) &&
2599 (nCmdexecopt == 4) && pvaOut)
2600 return S_OK;
2601
2602 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2603 (nCmdID == 9) &&
2604 (nCmdexecopt == 0))
2605 return 1;
2606
2607 return OLECMDERR_E_UNKNOWNGROUP;
2608 }
2609
2610 /**********************************************************
2611 * ISVDropTarget implementation
2612 */
2613
2614 /******************************************************************************
2615 * drag_notify_subitem [Internal]
2616 *
2617 * Figure out the shellfolder object, which is currently under the mouse cursor
2618 * and notify it via the IDropTarget interface.
2619 */
2620
2621 #define SCROLLAREAWIDTH 20
2622
2623 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2624 {
2625 LVHITTESTINFO htinfo;
2626 LVITEMW lvItem;
2627 LONG lResult;
2628 HRESULT hr;
2629 RECT clientRect;
2630
2631 /* Map from global to client coordinates and query the index of the listview-item, which is
2632 * currently under the mouse cursor. */
2633 htinfo.pt.x = pt.x;
2634 htinfo.pt.y = pt.y;
2635 htinfo.flags = LVHT_ONITEM;
2636 ::ScreenToClient(m_hWndList, &htinfo.pt);
2637 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2638
2639 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2640 ::GetClientRect(m_hWndList, &clientRect);
2641 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2642 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2643 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2644 {
2645 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2646 if (m_cScrollDelay == 0)
2647 {
2648 /* Mouse did hover another 250 ms over the scroll-area */
2649 if (htinfo.pt.x < SCROLLAREAWIDTH)
2650 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2651
2652 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2653 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2654
2655 if (htinfo.pt.y < SCROLLAREAWIDTH)
2656 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2657
2658 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2659 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2660 }
2661 }
2662 else
2663 {
2664 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2665 }
2666
2667 m_ptLastMousePos = htinfo.pt;
2668
2669 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2670 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2671 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2672
2673 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2674 if (m_pCurDropTarget)
2675 {
2676 m_pCurDropTarget->DragLeave();
2677 m_pCurDropTarget.Release();
2678 }
2679
2680 m_iDragOverItem = lResult;
2681 if (lResult == -1)
2682 {
2683 /* We are not above one of the listview's subitems. Bind to the parent folder's
2684 * DropTarget interface. */
2685 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2686 }
2687 else
2688 {
2689 /* Query the relative PIDL of the shellfolder object represented by the currently
2690 * dragged over listview-item ... */
2691 lvItem.mask = LVIF_PARAM;
2692 lvItem.iItem = lResult;
2693 lvItem.iSubItem = 0;
2694 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2695
2696 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2697 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1, (LPCITEMIDLIST*)&lvItem.lParam, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
2698 }
2699
2700 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2701 if (FAILED(hr))
2702 return hr;
2703
2704 /* Notify the item just entered via DragEnter. */
2705 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2706 }
2707
2708 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2709 {
2710 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2711 m_pCurDataObject = pDataObject;
2712 pDataObject->AddRef();
2713
2714 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2715 }
2716
2717 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2718 {
2719 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2720 }
2721
2722 HRESULT WINAPI CDefView::DragLeave()
2723 {
2724 if (m_pCurDropTarget)
2725 {
2726 m_pCurDropTarget->DragLeave();
2727 m_pCurDropTarget.Release();
2728 }
2729
2730 if (m_pCurDataObject != NULL)
2731 {
2732 m_pCurDataObject.Release();
2733 }
2734
2735 m_iDragOverItem = 0;
2736
2737 return S_OK;
2738 }
2739
2740 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2741 {
2742 if (m_pCurDropTarget)
2743 {
2744 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2745 m_pCurDropTarget.Release();
2746 }
2747
2748 m_pCurDataObject.Release();
2749 m_iDragOverItem = 0;
2750 return S_OK;
2751 }
2752
2753 /**********************************************************
2754 * ISVDropSource implementation
2755 */
2756
2757 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2758 {
2759 TRACE("(%p)\n", this);
2760
2761 if (fEscapePressed)
2762 return DRAGDROP_S_CANCEL;
2763 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2764 return DRAGDROP_S_DROP;
2765 else
2766 return S_OK;
2767 }
2768
2769 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2770 {
2771 TRACE("(%p)\n", this);
2772
2773 return DRAGDROP_S_USEDEFAULTCURSORS;
2774 }
2775
2776 /**********************************************************
2777 * ISVViewObject implementation
2778 */
2779
2780 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)
2781 {
2782 FIXME("Stub: this=%p\n", this);
2783
2784 return E_NOTIMPL;
2785 }
2786
2787 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2788 {
2789 FIXME("Stub: this=%p\n", this);
2790
2791 return E_NOTIMPL;
2792 }
2793
2794 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2795 {
2796 FIXME("Stub: this=%p\n", this);
2797
2798 return E_NOTIMPL;
2799 }
2800
2801 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2802 {
2803 FIXME("Stub: this=%p\n", this);
2804
2805 return E_NOTIMPL;
2806 }
2807
2808 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2809 {
2810 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2811
2812 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2813 m_pAdvSink = pAdvSink;
2814 m_dwAspects = aspects;
2815 m_dwAdvf = advf;
2816
2817 return S_OK;
2818 }
2819
2820 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2821 {
2822 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2823
2824 if (ppAdvSink)
2825 {
2826 *ppAdvSink = m_pAdvSink;
2827 m_pAdvSink.p->AddRef();
2828 }
2829
2830 if (pAspects)
2831 *pAspects = m_dwAspects;
2832
2833 if (pAdvf)
2834 *pAdvf = m_dwAdvf;
2835
2836 return S_OK;
2837 }
2838
2839 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2840 {
2841 if (IsEqualIID(guidService, SID_IShellBrowser))
2842 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2843 else if(IsEqualIID(guidService, SID_IFolderView))
2844 return QueryInterface(riid, ppvObject);
2845
2846 return E_NOINTERFACE;
2847 }
2848
2849 /**********************************************************
2850 * IShellView_Constructor
2851 */
2852 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2853 {
2854 CComObject<CDefView> *theView;
2855 CComPtr<IShellView> result;
2856 HRESULT hResult;
2857
2858 if (newView == NULL)
2859 return E_POINTER;
2860
2861 *newView = NULL;
2862 ATLTRY (theView = new CComObject<CDefView>);
2863
2864 if (theView == NULL)
2865 return E_OUTOFMEMORY;
2866
2867 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2868 if (FAILED (hResult))
2869 {
2870 delete theView;
2871 return hResult;
2872 }
2873
2874 hResult = theView->Initialize (pFolder);
2875 if (FAILED (hResult))
2876 return hResult;
2877 *newView = result.Detach ();
2878
2879 return S_OK;
2880 }