[BROWSEUI]
[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 else
332 {
333 DestroyWindow();
334 }
335 return S_OK;
336 }
337
338 HRESULT STDMETHODCALLTYPE CBaseBar::GetClient(IUnknown **ppunkClient)
339 {
340 if (ppunkClient == NULL)
341 return E_POINTER;
342 *ppunkClient = fClient;
343 if (fClient.p != NULL)
344 fClient.p->AddRef();
345 return S_OK;
346 }
347
348 HRESULT STDMETHODCALLTYPE CBaseBar::OnPosRectChangeDB(LPRECT prc)
349 {
350 if (prc == NULL)
351 return E_POINTER;
352 if (fVertical)
353 fNeededSize = prc->right - prc->left;
354 else
355 fNeededSize = prc->bottom - prc->top;
356 ReserveBorderSpace();
357 return S_OK;
358 }
359
360 HRESULT STDMETHODCALLTYPE CBaseBar::ShowDW(BOOL fShow)
361 {
362 fVisible = fShow ? true : false;
363 ShowWindow(fShow);
364 ReserveBorderSpace();
365 return S_OK;
366 }
367
368 HRESULT STDMETHODCALLTYPE CBaseBar::CloseDW(DWORD dwReserved)
369 {
370 ShowDW(0);
371 // Detach from our client
372 SetClient(NULL);
373 // Destroy our site
374 SetSite(NULL);
375 return S_OK;
376 }
377
378 HRESULT STDMETHODCALLTYPE CBaseBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
379 {
380 ReserveBorderSpace();
381 return S_OK;
382 }
383
384 HRESULT STDMETHODCALLTYPE CBaseBar::SetSite(IUnknown *pUnkSite)
385 {
386 fSite = pUnkSite;
387 return S_OK;
388 }
389
390 HRESULT STDMETHODCALLTYPE CBaseBar::GetSite(REFIID riid, void **ppvSite)
391 {
392 if (ppvSite == NULL)
393 return E_POINTER;
394 *ppvSite = fSite;
395 if (fSite.p != NULL)
396 fSite.p->AddRef();
397 return S_OK;
398 }
399
400 HRESULT STDMETHODCALLTYPE CBaseBar::GetClassID(CLSID *pClassID)
401 {
402 if (pClassID == NULL)
403 return E_POINTER;
404 // TODO: what class to return here?
405 return E_NOTIMPL;
406 }
407
408 HRESULT STDMETHODCALLTYPE CBaseBar::IsDirty()
409 {
410 return E_NOTIMPL;
411 }
412
413 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IStream *pStm)
414 {
415 return E_NOTIMPL;
416 }
417
418 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IStream *pStm, BOOL fClearDirty)
419 {
420 return E_NOTIMPL;
421 }
422
423 HRESULT STDMETHODCALLTYPE CBaseBar::GetSizeMax(ULARGE_INTEGER *pcbSize)
424 {
425 if (pcbSize == NULL)
426 return E_POINTER;
427 return E_NOTIMPL;
428 }
429
430 HRESULT STDMETHODCALLTYPE CBaseBar::InitNew()
431 {
432 return E_NOTIMPL;
433 }
434
435 HRESULT STDMETHODCALLTYPE CBaseBar::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
436 {
437 return E_NOTIMPL;
438 }
439
440 HRESULT STDMETHODCALLTYPE CBaseBar::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
441 {
442 return E_NOTIMPL;
443 }
444
445 LRESULT CBaseBar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
446 {
447 DWORD dwWidth;
448 DWORD dwHeight;
449 CComPtr<IOleWindow> pClient;
450 HWND clientHwnd;
451 HRESULT hr;
452
453 if (fVisible)
454 {
455 dwWidth = LOWORD(lParam);
456 dwHeight = HIWORD(lParam);
457
458 // substract resizing grips to child's window size
459 if (fVertical)
460 dwWidth -= GetSystemMetrics(SM_CXFRAME);
461 else
462 dwHeight -= GetSystemMetrics(SM_CXFRAME);
463 hr = fClient->QueryInterface(IID_PPV_ARG(IOleWindow, &pClient));
464 if (FAILED_UNEXPECTEDLY(hr))
465 return 0;
466 hr = pClient->GetWindow(&clientHwnd);
467 if (FAILED_UNEXPECTEDLY(hr))
468 return 0;
469 ::SetWindowPos(clientHwnd, NULL, 0, (fVertical) ? 0 : GetSystemMetrics(SM_CXFRAME), dwWidth, dwHeight, NULL);
470 bHandled = TRUE;
471 }
472 return 0;
473 }
474
475 LRESULT CBaseBar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
476 {
477 if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd)
478 {
479 bHandled = FALSE;
480 return 0;
481 }
482 if (fVertical)
483 SetCursor(LoadCursor(NULL, IDC_SIZEWE));
484 else
485 SetCursor(LoadCursor(NULL, IDC_SIZENS));
486 return 1;
487 }
488
489 LRESULT CBaseBar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
490 {
491 CComPtr<IWinEventHandler> winEventHandler;
492 LRESULT result;
493 HRESULT hResult;
494
495 result = 0;
496 if (fClient.p != NULL)
497 {
498 hResult = fClient->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
499 if (SUCCEEDED(hResult) && winEventHandler.p != NULL)
500 hResult = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
501 }
502 return result;
503 }
504
505 LRESULT CBaseBar::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
506 {
507 SetCapture();
508 fTracking = true;
509 fLastLocation.x = (short)LOWORD(lParam);
510 fLastLocation.y = (short)HIWORD(lParam);
511 return 0;
512 }
513
514 LRESULT CBaseBar::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
515 {
516 ReleaseCapture();
517 fTracking = false;
518 return 0;
519 }
520
521 LRESULT CBaseBar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
522 {
523 POINT newLocation;
524 int delta;
525
526 if (fTracking)
527 {
528 newLocation.x = (short)LOWORD(lParam);
529 newLocation.y = (short)HIWORD(lParam);
530 if (fVertical)
531 delta = newLocation.x - fLastLocation.x;
532 else
533 delta = fLastLocation.y - newLocation.y;
534 if (fNeededSize + delta < 0)
535 return 0;
536 fNeededSize += delta;
537 fLastLocation = newLocation;
538 ReserveBorderSpace();
539 }
540 return 0;
541 }
542
543 LRESULT CBaseBar::OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
544 {
545 fTracking = false;
546 return 0;
547 }
548
549 LRESULT CBaseBar::OnCaptureChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
550 {
551 fTracking = false;
552 return 0;
553 }
554
555 HRESULT CBaseBar_CreateInstance(REFIID riid, void **ppv, BOOL vertical)
556 {
557 return ShellObjectCreatorInit<CBaseBar, BOOL>(vertical, riid, ppv);
558 }