Sync with trunk (r48545)
[reactos.git] / dll / win32 / browseui / addressband.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 Implements the navigation band of the cabinet window
23 */
24 #include <windows.h>
25 #include <shlobj.h>
26 #include <shlobj_undoc.h>
27 #include <shlguid.h>
28 #include <shlguid_undoc.h>
29 #include <tchar.h>
30 #include <atlbase.h>
31 #include <atlcom.h>
32 #include <atlwin.h>
33 #include "resource.h"
34 #include "addressband.h"
35
36 /*
37 TODO:
38 ****Add command handler for show/hide Go button to OnWinEvent
39 ****Add tooltip notify handler
40 **Properly implement GetBandInfo
41 **Add support for showing/hiding Go button
42 **Fix so Go button will be shown/hidden properly on load
43 **Add correct text to Go button
44 **Implement TranslateAcceleratorIO
45 Implement Exec
46 Implement QueryService
47 Implement Load
48 Implement Save
49 */
50
51 CAddressBand::CAddressBand()
52 {
53 fEditControl = NULL;
54 fGoButton = NULL;
55 fComboBox = NULL;
56 fGoButtonShown = false;
57 }
58
59 CAddressBand::~CAddressBand()
60 {
61 }
62
63 void CAddressBand::FocusChange(BOOL bFocus)
64 {
65 // m_bFocus = bFocus;
66
67 //Inform the input object site that the focus has changed.
68 if (fSite)
69 {
70 #if 0
71 fSite->OnFocusChangeIS((IDockingWindow *)this, bFocus);
72 #endif
73 }
74 }
75
76 HRESULT STDMETHODCALLTYPE CAddressBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
77 {
78 if (pdbi->dwMask & DBIM_MINSIZE)
79 {
80 pdbi->ptMinSize.x = 400;
81 pdbi->ptMinSize.y = 22;
82 }
83 if (pdbi->dwMask & DBIM_MAXSIZE)
84 {
85 pdbi->ptMaxSize.x = 0;
86 pdbi->ptMaxSize.y = 0;
87 }
88 if (pdbi->dwMask & DBIM_INTEGRAL)
89 {
90 pdbi->ptIntegral.x = 0;
91 pdbi->ptIntegral.y = 0;
92 }
93 if (pdbi->dwMask & DBIM_ACTUAL)
94 {
95 pdbi->ptActual.x = 400;
96 pdbi->ptActual.y = 22;
97 }
98 if (pdbi->dwMask & DBIM_TITLE)
99 wcscpy(pdbi->wszTitle, L"Address");
100 if (pdbi->dwMask & DBIM_MODEFLAGS)
101 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
102 if (pdbi->dwMask & DBIM_BKCOLOR)
103 pdbi->crBkgnd = 0;
104 return S_OK;
105 }
106
107 HRESULT STDMETHODCALLTYPE CAddressBand::SetSite(IUnknown *pUnkSite)
108 {
109 CComPtr<IShellService> shellService;
110 CComPtr<IUnknown> offset34;
111 HWND parentWindow;
112 IOleWindow *oleWindow;
113 HWND toolbar;
114 static const TBBUTTON buttonInfo[] = { {0, 1, TBSTATE_ENABLED, 0} };
115 HIMAGELIST normalImagelist;
116 HIMAGELIST hotImageList;
117 HINSTANCE shellInstance;
118 HRESULT hResult;
119
120 fSite.Release();
121 if (pUnkSite == NULL)
122 return S_OK;
123 hResult = pUnkSite->QueryInterface(IID_IDockingWindowSite, (void **)&fSite);
124 if (FAILED(hResult))
125 return hResult;
126 parentWindow = NULL;
127 hResult = pUnkSite->QueryInterface(IID_IOleWindow, (void **)&oleWindow);
128 if (SUCCEEDED(hResult))
129 {
130 oleWindow->GetWindow(&parentWindow);
131 oleWindow->Release();
132 }
133 if (!::IsWindow(parentWindow))
134 return E_FAIL;
135
136 toolbar = CreateWindowEx(WS_EX_TOOLWINDOW, WC_COMBOBOXEXW, NULL, WS_CHILD | WS_VISIBLE |
137 WS_CLIPCHILDREN | WS_TABSTOP | CCS_NODIVIDER | CCS_NOMOVEY,
138 0, 0, 500, 250, parentWindow, (HMENU)0xa205, _AtlBaseModule.GetModuleInstance(), 0);
139 if (toolbar == NULL)
140 return E_FAIL;
141 SubclassWindow(toolbar);
142 SendMessage(CBEM_SETEXTENDEDSTYLE, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
143 fEditControl = (HWND)SendMessage(CBEM_GETEDITCONTROL, 0, 0);
144 fComboBox = (HWND)SendMessage(CBEM_GETCOMBOCONTROL, 0, 0);
145 #if 1
146 hResult = CoCreateInstance(CLSID_AddressEditBox, NULL, CLSCTX_INPROC_SERVER, IID_IAddressEditBox, (void **)&fAddressEditBox);
147 if (FAILED(hResult))
148 return hResult;
149 #else
150 // instantiate new version
151 #endif
152 hResult = fAddressEditBox->QueryInterface(IID_IShellService, (void **)&shellService);
153 if (FAILED(hResult))
154 return hResult;
155 hResult = fAddressEditBox->Init(toolbar, fEditControl, 8, pUnkSite /*(IAddressBand *)this*/ );
156 if (FAILED(hResult))
157 return hResult;
158 hResult = shellService->SetOwner(pUnkSite);
159 if (FAILED(hResult))
160 return hResult;
161
162 // TODO: properly initialize this from registry
163 fGoButtonShown = true;
164
165 shellInstance = GetModuleHandle(_T("shell32.dll"));
166 normalImagelist = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL), 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
167 hotImageList = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT), 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
168
169 fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TBSTYLE_LIST |
170 TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE,
171 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
172 SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
173 SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
174 SendMessage(fGoButton, TB_SETIMAGELIST, 0, (LPARAM)normalImagelist);
175 SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, (LPARAM)hotImageList);
176 SendMessage(fGoButton, TB_ADDSTRINGW, (WPARAM)_AtlBaseModule.GetResourceInstance(), IDS_GOBUTTONLABEL);
177 SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM)&buttonInfo);
178
179 return hResult;
180 }
181
182 HRESULT STDMETHODCALLTYPE CAddressBand::GetSite(REFIID riid, void **ppvSite)
183 {
184 if (fSite == NULL)
185 return E_FAIL;
186 return fSite->QueryInterface(riid, ppvSite);
187 }
188
189 HRESULT STDMETHODCALLTYPE CAddressBand::GetWindow(HWND *lphwnd)
190 {
191 if (lphwnd == NULL)
192 return E_POINTER;
193 *lphwnd = m_hWnd;
194 return S_OK;
195 }
196
197 HRESULT STDMETHODCALLTYPE CAddressBand::ContextSensitiveHelp(BOOL fEnterMode)
198 {
199 return E_NOTIMPL;
200 }
201
202 HRESULT STDMETHODCALLTYPE CAddressBand::CloseDW(DWORD dwReserved)
203 {
204 ShowDW(FALSE);
205
206 if (IsWindow())
207 DestroyWindow();
208
209 m_hWnd = NULL;
210
211 return S_OK;
212 }
213
214 HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
215 {
216 return E_NOTIMPL;
217 }
218
219 HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
220 {
221 if (m_hWnd)
222 {
223 if (fShow)
224 ShowWindow(SW_SHOW);
225 else
226 ShowWindow(SW_HIDE);
227 }
228 return S_OK;
229 }
230
231 HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
232 {
233 CComPtr<IOleCommandTarget> oleCommandTarget;
234 HRESULT hResult;
235
236 hResult = fAddressEditBox->QueryInterface(IID_IOleCommandTarget, (void **)&oleCommandTarget);
237 if (FAILED(hResult))
238 return hResult;
239 return oleCommandTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
240 }
241
242 HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
243 {
244 // incomplete
245 return E_NOTIMPL;
246 }
247
248 HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
249 {
250 if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
251 return S_OK;
252 return S_FALSE;
253 }
254
255 HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
256 {
257 // incomplete
258 return S_FALSE;
259 }
260
261 HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
262 {
263 CComPtr<IInputObjectSite> inputObjectSite;
264 HRESULT hResult;
265
266 if (fActivate)
267 {
268 hResult = fSite->QueryInterface(IID_IInputObjectSite, (void **)&inputObjectSite);
269 if (FAILED(hResult))
270 return hResult;
271 hResult = inputObjectSite->OnFocusChangeIS((IDeskBand *)this, fActivate);
272 SetFocus();
273 }
274 return S_OK;
275 }
276
277 HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
278 {
279 CComPtr<IWinEventHandler> winEventHandler;
280 HRESULT hResult;
281
282 switch (uMsg)
283 {
284 case WM_WININICHANGE:
285 break;
286 case WM_COMMAND:
287 if (wParam == IDM_TOOLBARS_GOBUTTON)
288 {
289 // toggle whether the Go button is displayed
290 // setting is Yes or No, stored in key "Software\Microsoft\Internet Explorer\Main" in value ShowGoButton
291 // broadcast change notification to all explorer windows
292 }
293 break;
294 }
295 hResult = fAddressEditBox->QueryInterface(IID_IWinEventHandler, (void **)&winEventHandler);
296 if (FAILED(hResult))
297 return hResult;
298 return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
299 }
300
301 HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
302 {
303 CComPtr<IWinEventHandler> winEventHandler;
304 HRESULT hResult;
305
306 hResult = fAddressEditBox->QueryInterface(IID_IWinEventHandler, (void **)&winEventHandler);
307 if (FAILED(hResult))
308 return hResult;
309 return winEventHandler->IsWindowOwner(hWnd);
310 }
311
312 HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
313 {
314 CComPtr<IAddressBand> addressBand;
315 HRESULT hResult;
316
317 hResult = fAddressEditBox->QueryInterface(IID_IAddressBand, (void **)&addressBand);
318 if (FAILED(hResult))
319 return hResult;
320 return addressBand->FileSysChange(param8, paramC);
321 }
322
323 HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
324 {
325 CComPtr<IAddressBand> addressBand;
326 HRESULT hResult;
327
328 hResult = fAddressEditBox->QueryInterface(IID_IAddressBand, (void **)&addressBand);
329 if (FAILED(hResult))
330 return hResult;
331 return addressBand->Refresh(param8);
332 }
333
334 HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
335 {
336 return E_NOTIMPL;
337 }
338
339 HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
340 {
341 return E_NOTIMPL;
342 }
343
344 HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
345 {
346 if (pClassID == NULL)
347 return E_POINTER;
348 *pClassID = CLSID_SH_AddressBand;
349 return S_OK;
350 }
351
352 HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
353 {
354 return E_NOTIMPL;
355 }
356
357 HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
358 {
359 // incomplete
360 return E_NOTIMPL;
361 }
362
363 HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
364 {
365 // incomplete
366 return E_NOTIMPL;
367 }
368
369 HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
370 {
371 // incomplete
372 return E_NOTIMPL;
373 }
374
375 LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
376 {
377 if (notifyHeader->hwndFrom == fGoButton)
378 {
379 SendMessage(fEditControl, WM_KEYDOWN, 13, 0);
380 SendMessage(fEditControl, WM_KEYUP, 13, 0);
381 }
382 return 0;
383 }
384
385 LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
386 {
387 if (notifyHeader->hwndFrom == fGoButton)
388 {
389 // TODO
390 // Go to "destination path"
391 }
392 return 0;
393 }
394
395 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
396 {
397 POINT pt;
398 POINT ptOrig;
399 HWND parentWindow;
400 LRESULT result;
401
402 if (fGoButtonShown == false)
403 {
404 bHandled = FALSE;
405 return 0;
406 }
407 pt.x = 0;
408 pt.y = 0;
409 parentWindow = GetParent();
410 ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
411 OffsetWindowOrgEx((HDC)wParam, pt.x, pt.y, &ptOrig);
412 result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
413 SetWindowOrgEx((HDC)wParam, ptOrig.x, ptOrig.y, NULL);
414 if (result == 0)
415 {
416 bHandled = FALSE;
417 return 0;
418 }
419 return result;
420 }
421
422 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
423 {
424 RECT goButtonBounds;
425 RECT buttonBounds;
426 long buttonWidth;
427 long buttonHeight;
428 RECT comboBoxBounds;
429 long newHeight;
430 long newWidth;
431
432 if (fGoButtonShown == false)
433 {
434 bHandled = FALSE;
435 return 0;
436 }
437 newHeight = HIWORD(lParam);
438 newWidth = LOWORD(lParam);
439 SendMessage(fGoButton, TB_GETITEMRECT, 0, (LPARAM)&buttonBounds);
440 buttonWidth = buttonBounds.right - buttonBounds.left;
441 buttonHeight = buttonBounds.bottom - buttonBounds.top;
442 DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
443 ::GetWindowRect(fComboBox, &comboBoxBounds);
444 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
445 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
446 goButtonBounds.left = newWidth - buttonWidth;
447 goButtonBounds.top = 0;
448 goButtonBounds.right = newWidth - buttonWidth;
449 goButtonBounds.bottom = newHeight;
450 InvalidateRect(&goButtonBounds, TRUE);
451 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
452 return 0;
453 }
454
455 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
456 {
457 RECT goButtonBounds;
458 RECT buttonBounds;
459 long buttonWidth;
460 long buttonHeight;
461 RECT comboBoxBounds;
462 WINDOWPOS positionInfoCopy;
463 long newHeight;
464 long newWidth;
465
466 if (fGoButtonShown == false)
467 {
468 bHandled = FALSE;
469 return 0;
470 }
471 positionInfoCopy = *(WINDOWPOS *)lParam;
472 newHeight = positionInfoCopy.cy;
473 newWidth = positionInfoCopy.cx;
474 SendMessage(fGoButton, TB_GETITEMRECT, 0, (LPARAM)&buttonBounds);
475 buttonWidth = buttonBounds.right - buttonBounds.left;
476 buttonHeight = buttonBounds.bottom - buttonBounds.top;
477 positionInfoCopy.cx = newWidth - 2 - buttonWidth;
478 DefWindowProc(WM_WINDOWPOSCHANGING, wParam, (LPARAM)&positionInfoCopy);
479 ::GetWindowRect(fComboBox, &comboBoxBounds);
480 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
481 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
482 goButtonBounds.left = newWidth - buttonWidth;
483 goButtonBounds.top = 0;
484 goButtonBounds.right = newWidth - buttonWidth;
485 goButtonBounds.bottom = newHeight;
486 InvalidateRect(&goButtonBounds, TRUE);
487 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
488 return 0;
489 }
490
491 HRESULT CreateAddressBand(REFIID riid, void **ppv)
492 {
493 CComObject<CAddressBand> *theMenuBar;
494 HRESULT hResult;
495
496 if (ppv == NULL)
497 return E_POINTER;
498 *ppv = NULL;
499 ATLTRY (theMenuBar = new CComObject<CAddressBand>);
500 if (theMenuBar == NULL)
501 return E_OUTOFMEMORY;
502 hResult = theMenuBar->QueryInterface (riid, (void **)ppv);
503 if (FAILED (hResult))
504 {
505 delete theMenuBar;
506 return hResult;
507 }
508 return S_OK;
509 }