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 fAdjustNeeded = 0; 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 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 // TODO 419 // Go to "destination path" 420 } 421 return 0; 422 } 423 424 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 425 { 426 POINT pt; 427 POINT ptOrig; 428 HWND parentWindow; 429 LRESULT result; 430 431 if (fGoButtonShown == false) 432 { 433 bHandled = FALSE; 434 return 0; 435 } 436 pt.x = 0; 437 pt.y = 0; 438 parentWindow = GetParent(); 439 ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1); 440 OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig); 441 result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0); 442 SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL); 443 if (result == 0) 444 { 445 bHandled = FALSE; 446 return 0; 447 } 448 return result; 449 } 450 451 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 452 { 453 RECT goButtonBounds; 454 RECT buttonBounds; 455 long buttonWidth; 456 long buttonHeight; 457 RECT comboBoxBounds; 458 long newHeight; 459 long newWidth; 460 461 fAdjustNeeded = 1; 462 463 if (fGoButtonShown == false) 464 { 465 bHandled = FALSE; 466 return 0; 467 } 468 469 newHeight = HIWORD(lParam); 470 newWidth = LOWORD(lParam); 471 472 if (!fGoButton) 473 CreateGoButton(); 474 475 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds)); 476 buttonWidth = buttonBounds.right - buttonBounds.left; 477 buttonHeight = buttonBounds.bottom - buttonBounds.top; 478 479 DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight)); 480 ::GetWindowRect(fComboBox, &comboBoxBounds); 481 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2, 482 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); 483 484 goButtonBounds.left = newWidth - buttonWidth; 485 goButtonBounds.top = 0; 486 goButtonBounds.right = newWidth - buttonWidth; 487 goButtonBounds.bottom = newHeight; 488 InvalidateRect(&goButtonBounds, TRUE); 489 490 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0); 491 return 0; 492 } 493 494 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 495 { 496 RECT goButtonBounds; 497 RECT buttonBounds; 498 long buttonWidth; 499 long buttonHeight; 500 RECT comboBoxBounds; 501 WINDOWPOS positionInfoCopy; 502 long newHeight; 503 long newWidth; 504 505 if (!fGoButtonShown) 506 { 507 bHandled = FALSE; 508 return 0; 509 } 510 511 if (!fGoButton) 512 CreateGoButton(); 513 514 positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam); 515 newHeight = positionInfoCopy.cy; 516 newWidth = positionInfoCopy.cx; 517 518 /* 519 Sometimes when we get here newWidth = 100 which comes from GetBandInfo and is less than the 200 that we need. 520 We need room for the "Address" text (50 pixels), the "GoButton" (50 pixels), the left and right borders (30 pixels) 521 the icon (20 pixels) and the ComboBox (50 pixels) for handling the text of the current directory. This is 200 pixels. 522 When newWidth = 100 the Addressband ComboBox will only have a single character because it becomes 2 pixels wide. 523 The hack below readjusts the width to the minimum required to allow seeing the whole text and prints out a debug message. 524 */ 525 526 if ((newWidth < 200) && (newWidth != 0)) 527 { 528 if (fAdjustNeeded == 1) 529 { 530 ERR("CORE-13003 HACK: Addressband ComboBox width readjusted from %ld to 200.\n", newWidth); 531 newWidth = 200; 532 fAdjustNeeded = 0; 533 } 534 } 535 SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds)); 536 537 buttonWidth = buttonBounds.right - buttonBounds.left; 538 buttonHeight = buttonBounds.bottom - buttonBounds.top; 539 positionInfoCopy.cx = newWidth - 2 - buttonWidth; 540 DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy)); 541 ::GetWindowRect(fComboBox, &comboBoxBounds); 542 ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2, 543 buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); 544 545 goButtonBounds.left = newWidth - buttonWidth; 546 goButtonBounds.top = 0; 547 goButtonBounds.right = newWidth - buttonWidth; 548 goButtonBounds.bottom = newHeight; 549 InvalidateRect(&goButtonBounds, TRUE); 550 551 SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0); 552 return 0; 553 } 554 555 void CAddressBand::CreateGoButton() 556 { 557 const TBBUTTON buttonInfo [] = { { 0, 1, TBSTATE_ENABLED, 0 } }; 558 HINSTANCE shellInstance; 559 560 shellInstance = _AtlBaseModule.GetResourceInstance(); 561 m_himlNormal = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL), 562 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION); 563 m_himlHot = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT), 564 20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION); 565 566 fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS | 567 WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | 568 CCS_NOPARENTALIGN | CCS_NORESIZE, 569 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL); 570 SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); 571 SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0); 572 if (m_himlNormal) 573 SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlNormal)); 574 if (m_himlHot) 575 SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlHot)); 576 SendMessage(fGoButton, TB_ADDSTRINGW, 577 reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL); 578 SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM) &buttonInfo); 579 } 580