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