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 } 553