reactos/dll/win32/browseui/addressband.cpp
2018-04-22 15:42:29 +02:00

579 lines
18 KiB
C++

/*
* ReactOS Explorer
*
* Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
Implements the navigation band of the cabinet window
*/
#include "precomp.h"
#include <commoncontrols.h>
#include <shlwapi_undoc.h>
#include <shellapi.h>
/*
TODO:
****Add tooltip notify handler
**Properly implement GetBandInfo
Implement Exec
Implement QueryService
Implement Load
Implement Save
*/
CAddressBand::CAddressBand()
{
fEditControl = NULL;
fGoButton = NULL;
fComboBox = NULL;
fGoButtonShown = false;
fAdjustNeeded = 0;
}
CAddressBand::~CAddressBand()
{
}
void CAddressBand::FocusChange(BOOL bFocus)
{
// m_bFocus = bFocus;
//Inform the input object site that the focus has changed.
if (fSite)
{
#if 0
fSite->OnFocusChangeIS((IDockingWindow *)this, bFocus);
#endif
}
}
HRESULT STDMETHODCALLTYPE CAddressBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
{
if (pdbi->dwMask & DBIM_MINSIZE)
{
if (fGoButtonShown)
pdbi->ptMinSize.x = 100;
else
pdbi->ptMinSize.x = 150;
pdbi->ptMinSize.y = 22;
}
if (pdbi->dwMask & DBIM_MAXSIZE)
{
pdbi->ptMaxSize.x = 0;
pdbi->ptMaxSize.y = 0;
}
if (pdbi->dwMask & DBIM_INTEGRAL)
{
pdbi->ptIntegral.x = 0;
pdbi->ptIntegral.y = 0;
}
if (pdbi->dwMask & DBIM_ACTUAL)
{
if (fGoButtonShown)
pdbi->ptActual.x = 100;
else
pdbi->ptActual.x = 150;
pdbi->ptActual.y = 22;
}
if (pdbi->dwMask & DBIM_TITLE)
{
if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_ADDRESSBANDLABEL, pdbi->wszTitle, _countof(pdbi->wszTitle)))
return HRESULT_FROM_WIN32(GetLastError());
}
if (pdbi->dwMask & DBIM_MODEFLAGS)
pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
if (pdbi->dwMask & DBIM_BKCOLOR)
pdbi->crBkgnd = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::SetSite(IUnknown *pUnkSite)
{
CComPtr<IShellService> shellService;
HWND parentWindow;
HWND combobox;
HRESULT hResult;
IImageList *piml;
if (pUnkSite == NULL)
{
fSite.Release();
return S_OK;
}
fSite.Release();
hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &fSite));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
// get window handle of parent
parentWindow = NULL;
hResult = IUnknown_GetWindow(fSite, &parentWindow);
if (!::IsWindow(parentWindow))
return E_FAIL;
// create combo box ex
combobox = CreateWindowEx(WS_EX_TOOLWINDOW, WC_COMBOBOXEXW, NULL, WS_CHILD | WS_VISIBLE |
WS_CLIPCHILDREN | WS_TABSTOP | CCS_NODIVIDER | CCS_NOMOVEY | CBS_OWNERDRAWFIXED,
0, 0, 500, 250, parentWindow, (HMENU)IDM_TOOLBARS_ADDRESSBAR, _AtlBaseModule.GetModuleInstance(), 0);
if (combobox == NULL)
return E_FAIL;
SubclassWindow(combobox);
HRESULT hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
if (FAILED_UNEXPECTEDLY(hr))
{
SendMessageW(combobox, CBEM_SETIMAGELIST, 0, 0);
}
else
{
SendMessageW(combobox, CBEM_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(piml));
}
SendMessage(CBEM_SETEXTENDEDSTYLE,
CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
fEditControl = reinterpret_cast<HWND>(SendMessage(CBEM_GETEDITCONTROL, 0, 0));
fComboBox = reinterpret_cast<HWND>(SendMessage(CBEM_GETCOMBOCONTROL, 0, 0));
hResult = CAddressEditBox_CreateInstance(IID_PPV_ARG(IAddressEditBox, &fAddressEditBox));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &shellService));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
hResult = fAddressEditBox->Init(combobox, fEditControl, 8, fSite /*(IAddressBand *)this*/);
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
hResult = shellService->SetOwner(fSite);
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
fGoButtonShown = SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
if (fGoButtonShown)
CreateGoButton();
return hResult;
}
HRESULT STDMETHODCALLTYPE CAddressBand::GetSite(REFIID riid, void **ppvSite)
{
if (fSite == NULL)
return E_FAIL;
return fSite->QueryInterface(riid, ppvSite);
}
HRESULT STDMETHODCALLTYPE CAddressBand::GetWindow(HWND *lphwnd)
{
if (lphwnd == NULL)
return E_POINTER;
*lphwnd = m_hWnd;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::CloseDW(DWORD dwReserved)
{
ShowDW(FALSE);
if (IsWindow())
DestroyWindow();
m_hWnd = NULL;
CComPtr<IShellService> pservice;
HRESULT hres = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pservice));
if (SUCCEEDED(hres ))
pservice->SetOwner(NULL);
if (fAddressEditBox) fAddressEditBox.Release();
if (fSite) fSite.Release();
if (m_himlNormal)
ImageList_Destroy(m_himlNormal);
if (m_himlHot)
ImageList_Destroy(m_himlHot);
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(
const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
{
if (m_hWnd)
{
if (fShow)
ShowWindow(SW_SHOW);
else
ShowWindow(SW_HIDE);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(
const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
{
return IUnknown_QueryStatus(fAddressEditBox, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
}
HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup,
DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
// incomplete
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
{
if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
return S_OK;
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
{
if (lpMsg->hwnd == fEditControl)
{
switch (lpMsg->message)
{
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCOMMAND:
case WM_SYSDEADCHAR:
case WM_SYSCHAR:
return S_FALSE;
}
TranslateMessage(lpMsg);
DispatchMessage(lpMsg);
return S_OK;
}
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
{
if (fActivate)
{
IUnknown_OnFocusChangeIS(fSite, static_cast<IDeskBand *>(this), fActivate);
SetFocus();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
{
CComPtr<IWinEventHandler> winEventHandler;
HRESULT hResult;
RECT rect;
if (theResult)
*theResult = 0;
switch (uMsg)
{
case WM_WININICHANGE:
break;
case WM_COMMAND:
if (wParam == IDM_TOOLBARS_GOBUTTON)
{
fGoButtonShown = !SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
SHRegSetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", REG_SZ, fGoButtonShown ? (LPVOID)L"yes" : (LPVOID)L"no", fGoButtonShown ? 8 : 6, SHREGSET_FORCE_HKCU);
if (!fGoButton)
CreateGoButton();
::ShowWindow(fGoButton,fGoButtonShown ? SW_HIDE : SW_SHOW);
GetWindowRect(&rect);
SendMessage(m_hWnd,WM_SIZE,0,MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top));
// broadcast change notification to all explorer windows
}
break;
}
hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
}
HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
{
CComPtr<IWinEventHandler> winEventHandler;
HRESULT hResult;
if (fAddressEditBox)
{
hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
return winEventHandler->IsWindowOwner(hWnd);
}
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
{
CComPtr<IAddressBand> addressBand;
HRESULT hResult;
hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
return addressBand->FileSysChange(param8, paramC);
}
HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
{
CComPtr<IAddressBand> addressBand;
HRESULT hResult;
hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
return addressBand->Refresh(param8);
}
HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
{
if (pClassID == NULL)
return E_POINTER;
*pClassID = CLSID_SH_AddressBand;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
{
// incomplete
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
{
// incomplete
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
// incomplete
return E_NOTIMPL;
}
LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
{
if (notifyHeader->hwndFrom == fGoButton)
{
fAddressEditBox->Execute(0);
}
return 0;
}
LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
{
if (notifyHeader->hwndFrom == fGoButton)
{
// TODO
// Go to "destination path"
}
return 0;
}
LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
POINT pt;
POINT ptOrig;
HWND parentWindow;
LRESULT result;
if (fGoButtonShown == false)
{
bHandled = FALSE;
return 0;
}
pt.x = 0;
pt.y = 0;
parentWindow = GetParent();
::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig);
result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL);
if (result == 0)
{
bHandled = FALSE;
return 0;
}
return result;
}
LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
RECT goButtonBounds;
RECT buttonBounds;
long buttonWidth;
long buttonHeight;
RECT comboBoxBounds;
long newHeight;
long newWidth;
fAdjustNeeded = 1;
if (fGoButtonShown == false)
{
bHandled = FALSE;
return 0;
}
newHeight = HIWORD(lParam);
newWidth = LOWORD(lParam);
if (!fGoButton)
CreateGoButton();
SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
buttonWidth = buttonBounds.right - buttonBounds.left;
buttonHeight = buttonBounds.bottom - buttonBounds.top;
DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
::GetWindowRect(fComboBox, &comboBoxBounds);
::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
goButtonBounds.left = newWidth - buttonWidth;
goButtonBounds.top = 0;
goButtonBounds.right = newWidth - buttonWidth;
goButtonBounds.bottom = newHeight;
InvalidateRect(&goButtonBounds, TRUE);
SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
return 0;
}
LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
RECT goButtonBounds;
RECT buttonBounds;
long buttonWidth;
long buttonHeight;
RECT comboBoxBounds;
WINDOWPOS positionInfoCopy;
long newHeight;
long newWidth;
if (!fGoButtonShown)
{
bHandled = FALSE;
return 0;
}
if (!fGoButton)
CreateGoButton();
positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam);
newHeight = positionInfoCopy.cy;
newWidth = positionInfoCopy.cx;
/*
Sometimes when we get here newWidth = 100 which comes from GetBandInfo and is less than the 200 that we need.
We need room for the "Address" text (50 pixels), the "GoButton" (50 pixels), the left and right borders (30 pixels)
the icon (20 pixels) and the ComboBox (50 pixels) for handling the text of the current directory. This is 200 pixels.
When newWidth = 100 the Addressband ComboBox will only have a single character because it becomes 2 pixels wide.
The hack below readjusts the width to the minimum required to allow seeing the whole text and prints out a debug message.
*/
if ((newWidth < 200) && (newWidth != 0))
{
if (fAdjustNeeded == 1)
{
ERR("CORE-13003 HACK: Addressband ComboBox width readjusted from %ld to 200.\n", newWidth);
newWidth = 200;
fAdjustNeeded = 0;
}
}
SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
buttonWidth = buttonBounds.right - buttonBounds.left;
buttonHeight = buttonBounds.bottom - buttonBounds.top;
positionInfoCopy.cx = newWidth - 2 - buttonWidth;
DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy));
::GetWindowRect(fComboBox, &comboBoxBounds);
::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
goButtonBounds.left = newWidth - buttonWidth;
goButtonBounds.top = 0;
goButtonBounds.right = newWidth - buttonWidth;
goButtonBounds.bottom = newHeight;
InvalidateRect(&goButtonBounds, TRUE);
SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
return 0;
}
void CAddressBand::CreateGoButton()
{
const TBBUTTON buttonInfo [] = { { 0, 1, TBSTATE_ENABLED, 0 } };
HINSTANCE shellInstance;
shellInstance = _AtlBaseModule.GetResourceInstance();
m_himlNormal = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL),
20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
m_himlHot = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT),
20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS |
WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER |
CCS_NOPARENTALIGN | CCS_NORESIZE,
0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
if (m_himlNormal)
SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlNormal));
if (m_himlHot)
SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlHot));
SendMessage(fGoButton, TB_ADDSTRINGW,
reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL);
SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM) &buttonInfo);
}