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