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