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