6a30462e0b4e6bc21f4e526c41fe60fa5842b0fd
[reactos.git] / reactos / dll / win32 / browseui / basebar.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 This class knows how to contain base bar site in a cabinet window.
23 */
24
25 #include "precomp.h"
26
27 /*
28 Base bar that contains a vertical or horizontal explorer band. It also
29 provides resizing abilities.
30 */
31 /*
32 TODO:
33 **Make base bar support resizing -- almost done (need to support integral ?)
34 Add context menu for base bar
35 Fix base bar to correctly initialize fVertical field
36 Fix base bar to correctly reposition its base bar site when resized -- done ?
37 */
38
39 class CBaseBar :
40 public CWindowImpl<CBaseBar, CWindow, CControlWinTraits>,
41 public CComObjectRootEx<CComMultiThreadModelNoCS>,
42 public IInputObjectSite,
43 public IOleCommandTarget,
44 public IServiceProvider,
45 public IInputObject,
46 public IDeskBar,
47 public IDockingWindow,
48 public IPersistStream,
49 public IPersistStreamInit,
50 public IPersistPropertyBag,
51 public IObjectWithSite
52 {
53 private:
54 CComPtr<IUnknown> fSite;
55 CComPtr<IUnknown> fClient;
56 HWND fClientWindow;
57 bool fVertical;
58 bool fVisible;
59 int fNeededSize; // width or height
60
61 // used by resize tracking loop
62 bool fTracking;
63 POINT fLastLocation;
64 public:
65 CBaseBar();
66 ~CBaseBar();
67 HRESULT Initialize(BOOL);
68
69 public:
70 HRESULT ReserveBorderSpace();
71
72 // *** IOleWindow methods ***
73 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
74 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
75
76 // *** IInputObjectSite specific methods ***
77 virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus);
78
79 // *** IOleCommandTarget specific methods ***
80 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
81 OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
82 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
83 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
84
85 // *** IServiceProvider methods ***
86 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
87
88 // *** IInputObject methods ***
89 // forward the methods to the contained active bar
90 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg);
91 virtual HRESULT STDMETHODCALLTYPE HasFocusIO();
92 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
93
94 // *** IDeskBar methods ***
95 virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient);
96 virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient);
97 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(LPRECT prc);
98
99 // *** IDockingWindow methods ***
100 virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow);
101 virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved);
102 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved);
103
104 // *** IObjectWithSite methods ***
105 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
106 virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite);
107
108 // *** IPersist methods ***
109 virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
110
111 // *** IPersistStream methods ***
112 virtual HRESULT STDMETHODCALLTYPE IsDirty();
113 virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
114 virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
115 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
116
117 // *** IPersistStreamInit methods ***
118 virtual HRESULT STDMETHODCALLTYPE InitNew();
119
120 // *** IPersistPropertyBag methods ***
121 virtual HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
122 virtual HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
123
124 // message handlers
125 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
126 LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
127 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
128 LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
129 LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
130 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
131 LRESULT OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
132 LRESULT OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
133
134 DECLARE_WND_CLASS_EX(_T("BaseBar"), 0, COLOR_3DFACE)
135
136 BEGIN_MSG_MAP(CBaseBar)
137 MESSAGE_HANDLER(WM_SIZE, OnSize)
138 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
139 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
140 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
141 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
142 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
143 MESSAGE_HANDLER(WM_CANCELMODE, OnCancelMode)
144 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
145 END_MSG_MAP()
146
147 BEGIN_COM_MAP(CBaseBar)
148 COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDockingWindow)
149 COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
150 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
151 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
152 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
153 COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IDeskBar)
154 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)
155 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
156 COM_INTERFACE_ENTRY2_IID(IID_IPersist, IPersist, IPersistStream)
157 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
158 COM_INTERFACE_ENTRY_IID(IID_IPersistStreamInit, IPersistStreamInit)
159 COM_INTERFACE_ENTRY_IID(IID_IPersistPropertyBag, IPersistPropertyBag)
160 END_COM_MAP()
161 };
162
163 CBaseBar::CBaseBar()
164 {
165 fClientWindow = NULL;
166 fVertical = true;
167 fVisible = false;
168 fNeededSize = 200;
169 fTracking = false;
170 }
171
172 CBaseBar::~CBaseBar()
173 {
174 }
175
176 HRESULT CBaseBar::Initialize(BOOL vert)
177 {
178 fVertical = (vert == TRUE);
179 return S_OK;
180 }
181
182 HRESULT CBaseBar::ReserveBorderSpace()
183 {
184 CComPtr<IDockingWindowSite> dockingWindowSite;
185 RECT availableBorderSpace;
186 RECT neededBorderSpace;
187 HRESULT hResult;
188
189 hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
190 if (FAILED_UNEXPECTEDLY(hResult))
191 return hResult;
192 hResult = dockingWindowSite->GetBorderDW(static_cast<IDeskBar *>(this), &availableBorderSpace);
193 if (FAILED_UNEXPECTEDLY(hResult))
194 return hResult;
195 memset(&neededBorderSpace, 0, sizeof(neededBorderSpace));
196 if (fVisible)
197 {
198 if (fVertical)
199 neededBorderSpace.left = fNeededSize + GetSystemMetrics(SM_CXFRAME);
200 else
201 neededBorderSpace.bottom = fNeededSize + GetSystemMetrics(SM_CXFRAME);
202 }
203 hResult = dockingWindowSite->SetBorderSpaceDW(static_cast<IDeskBar *>(this), &neededBorderSpace);
204 if (FAILED_UNEXPECTEDLY(hResult))
205 return hResult;
206 return S_OK;
207 }
208
209 // current bar size is stored in the registry under
210 // key=HKCU\Software\Microsoft\Internet Explorer\Explorer Bars
211 // value=current bar GUID
212 // result is 8 bytes of binary data, 2 longs. First is the size, second is reserved and will always be 0
213 /*HRESULT CBaseBar::StopCurrentBar()
214 {
215 CComPtr<IOleCommandTarget> commandTarget;
216 HRESULT hResult;
217
218 if (fCurrentBar.p != NULL)
219 {
220 hResult = fCurrentBar->QueryInterface(IID_IOleCommandTarget, (void **)&commandTarget);
221 hResult = commandTarget->Exec(NULL, 0x17, 0, NULL, NULL);
222 }
223 // hide the current bar
224 memcpy(&fCurrentActiveClass, &GUID_NULL, sizeof(fCurrentActiveClass));
225 return S_OK;
226 }*/
227
228 HRESULT STDMETHODCALLTYPE CBaseBar::GetWindow(HWND *lphwnd)
229 {
230 if (lphwnd == NULL)
231 return E_POINTER;
232 *lphwnd = m_hWnd;
233 return S_OK;
234 }
235
236 HRESULT STDMETHODCALLTYPE CBaseBar::ContextSensitiveHelp(BOOL fEnterMode)
237 {
238 return E_NOTIMPL;
239 }
240
241 HRESULT STDMETHODCALLTYPE CBaseBar::OnFocusChangeIS (IUnknown *punkObj, BOOL fSetFocus)
242 {
243 return IUnknown_OnFocusChangeIS(fSite, punkObj, fSetFocus);
244 }
245
246 HRESULT STDMETHODCALLTYPE CBaseBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
247 OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
248 {
249 return E_NOTIMPL;
250 }
251
252 HRESULT STDMETHODCALLTYPE CBaseBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
253 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
254 {
255 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
256 {
257 // pass through to the explorer ?
258 }
259 else if (IsEqualIID(*pguidCmdGroup, IID_IDeskBarClient))
260 {
261 switch (nCmdID)
262 {
263 case 0:
264 // hide current band
265 break;
266 case 2:
267 // switch bands
268 break;
269 case 3:
270 break;
271 }
272 }
273 return E_NOTIMPL;
274 }
275
276 HRESULT STDMETHODCALLTYPE CBaseBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
277 {
278 CComPtr<IServiceProvider> serviceProvider;
279 HRESULT hResult;
280
281 if (fSite == NULL)
282 return E_FAIL;
283 hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
284 if (FAILED_UNEXPECTEDLY(hResult))
285 return hResult;
286 // called for SID_STopLevelBrowser, IID_IBrowserService to find top level browser
287 // called for SID_IWebBrowserApp, IID_IConnectionPointContainer
288 // connection point called for DIID_DWebBrowserEvents2 to establish connection
289 return serviceProvider->QueryService(guidService, riid, ppvObject);
290 }
291
292 HRESULT STDMETHODCALLTYPE CBaseBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
293 {
294 return IUnknown_UIActivateIO(fClient, fActivate, lpMsg);
295 }
296
297 HRESULT STDMETHODCALLTYPE CBaseBar::HasFocusIO()
298 {
299 return IUnknown_HasFocusIO(fClient);
300 }
301
302 HRESULT STDMETHODCALLTYPE CBaseBar::TranslateAcceleratorIO(LPMSG lpMsg)
303 {
304 return IUnknown_TranslateAcceleratorIO(fClient, lpMsg);
305 }
306
307 HRESULT STDMETHODCALLTYPE CBaseBar::SetClient(IUnknown *punkClient)
308 {
309 CComPtr<IOleWindow> oleWindow;
310 HWND ownerWindow;
311 HRESULT hResult;
312
313 /* Clean up old client */
314 fClient = NULL;
315
316 if (punkClient)
317 {
318 hResult = punkClient->QueryInterface(IID_PPV_ARG(IUnknown, &fClient));
319 if (FAILED_UNEXPECTEDLY(hResult))
320 return hResult;
321 hResult = fSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
322 if (FAILED_UNEXPECTEDLY(hResult))
323 return hResult;
324 hResult = oleWindow->GetWindow(&ownerWindow);
325 if (FAILED_UNEXPECTEDLY(hResult))
326 return hResult;
327 Create(ownerWindow, 0, NULL,
328 WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_TOOLWINDOW);
329 ReserveBorderSpace();
330 }
331 return S_OK;
332 }
333
334 HRESULT STDMETHODCALLTYPE CBaseBar::GetClient(IUnknown **ppunkClient)
335 {
336 if (ppunkClient == NULL)
337 return E_POINTER;
338 *ppunkClient = fClient;
339 if (fClient.p != NULL)
340 fClient.p->AddRef();
341 return S_OK;
342 }
343
344 HRESULT STDMETHODCALLTYPE CBaseBar::OnPosRectChangeDB(LPRECT prc)
345 {
346 if (prc == NULL)
347 return E_POINTER;
348 if (fVertical)
349 fNeededSize = prc->right - prc->left;
350 else
351 fNeededSize = prc->bottom - prc->top;
352 ReserveBorderSpace();
353 return S_OK;
354 }
355
356 HRESULT STDMETHODCALLTYPE CBaseBar::ShowDW(BOOL fShow)
357 {
358 fVisible = fShow ? true : false;
359 ShowWindow(fShow);
360 ReserveBorderSpace();
361 return S_OK;
362 }
363
364 HRESULT STDMETHODCALLTYPE CBaseBar::CloseDW(DWORD dwReserved)
365 {
366 ShowDW(0);
367 // Detach from our client
368 SetClient(NULL);
369 // Destroy our site
370 SetSite(NULL);
371 return S_OK;
372 }
373
374 HRESULT STDMETHODCALLTYPE CBaseBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
375 {
376 ReserveBorderSpace();
377 return S_OK;
378 }
379
380 HRESULT STDMETHODCALLTYPE CBaseBar::SetSite(IUnknown *pUnkSite)
381 {
382 fSite = pUnkSite;
383 return S_OK;
384 }
385
386 HRESULT STDMETHODCALLTYPE CBaseBar::GetSite(REFIID riid, void **ppvSite)
387 {
388 if (ppvSite == NULL)
389 return E_POINTER;
390 *ppvSite = fSite;
391 if (fSite.p != NULL)
392 fSite.p->AddRef();
393 return S_OK;
394 }
395
396 HRESULT STDMETHODCALLTYPE CBaseBar::GetClassID(CLSID *pClassID)
397 {
398 if (pClassID == NULL)
399 return E_POINTER;
400 // TODO: what class to return here?
401 return E_NOTIMPL;
402 }
403
404 HRESULT STDMETHODCALLTYPE CBaseBar::IsDirty()
405 {
406 return E_NOTIMPL;
407 }
408
409 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IStream *pStm)
410 {
411 return E_NOTIMPL;
412 }
413
414 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IStream *pStm, BOOL fClearDirty)
415 {
416 return E_NOTIMPL;
417 }
418
419 HRESULT STDMETHODCALLTYPE CBaseBar::GetSizeMax(ULARGE_INTEGER *pcbSize)
420 {
421 if (pcbSize == NULL)
422 return E_POINTER;
423 return E_NOTIMPL;
424 }
425
426 HRESULT STDMETHODCALLTYPE CBaseBar::InitNew()
427 {
428 return E_NOTIMPL;
429 }
430
431 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
432 {
433 return E_NOTIMPL;
434 }
435
436 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
437 {
438 return E_NOTIMPL;
439 }
440
441 LRESULT CBaseBar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
442 {
443 DWORD dwWidth;
444 DWORD dwHeight;
445 CComPtr<IOleWindow> pClient;
446 HWND clientHwnd;
447 HRESULT hr;
448
449 if (fVisible)
450 {
451 dwWidth = LOWORD(lParam);
452 dwHeight = HIWORD(lParam);
453
454 // substract resizing grips to child's window size
455 if (fVertical)
456 dwWidth -= GetSystemMetrics(SM_CXFRAME);
457 else
458 dwHeight -= GetSystemMetrics(SM_CXFRAME);
459 hr = fClient->QueryInterface(IID_PPV_ARG(IOleWindow, &pClient));
460 if (FAILED_UNEXPECTEDLY(hr))
461 return 0;
462 hr = pClient->GetWindow(&clientHwnd);
463 if (FAILED_UNEXPECTEDLY(hr))
464 return 0;
465 ::SetWindowPos(clientHwnd, NULL, 0, (fVertical) ? 0 : GetSystemMetrics(SM_CXFRAME), dwWidth, dwHeight, NULL);
466 bHandled = TRUE;
467 }
468 return 0;
469 }
470
471 LRESULT CBaseBar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
472 {
473 if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd)
474 {
475 bHandled = FALSE;
476 return 0;
477 }
478 if (fVertical)
479 SetCursor(LoadCursor(NULL, IDC_SIZEWE));
480 else
481 SetCursor(LoadCursor(NULL, IDC_SIZENS));
482 return 1;
483 }
484
485 LRESULT CBaseBar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
486 {
487 CComPtr<IWinEventHandler> winEventHandler;
488 LRESULT result;
489 HRESULT hResult;
490
491 result = 0;
492 if (fClient.p != NULL)
493 {
494 hResult = fClient->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
495 if (SUCCEEDED(hResult) && winEventHandler.p != NULL)
496 hResult = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
497 }
498 return result;
499 }
500
501 LRESULT CBaseBar::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
502 {
503 SetCapture();
504 fTracking = true;
505 fLastLocation.x = (short)LOWORD(lParam);
506 fLastLocation.y = (short)HIWORD(lParam);
507 return 0;
508 }
509
510 LRESULT CBaseBar::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
511 {
512 ReleaseCapture();
513 fTracking = false;
514 return 0;
515 }
516
517 LRESULT CBaseBar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
518 {
519 POINT newLocation;
520 int delta;
521
522 if (fTracking)
523 {
524 newLocation.x = (short)LOWORD(lParam);
525 newLocation.y = (short)HIWORD(lParam);
526 if (fVertical)
527 delta = newLocation.x - fLastLocation.x;
528 else
529 delta = fLastLocation.y - newLocation.y;
530 if (fNeededSize + delta < 0)
531 return 0;
532 fNeededSize += delta;
533 fLastLocation = newLocation;
534 ReserveBorderSpace();
535 }
536 return 0;
537 }
538
539 LRESULT CBaseBar::OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
540 {
541 fTracking = false;
542 return 0;
543 }
544
545 LRESULT CBaseBar::OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
546 {
547 fTracking = false;
548 return 0;
549 }
550
551 HRESULT CBaseBar_CreateInstance(REFIID riid, void **ppv, BOOL vertical)
552 {
553 return ShellObjectCreatorInit<CBaseBar, BOOL>(vertical, riid, ppv);
554 }