diff options
Diffstat (limited to 'svtools/source')
-rw-r--r-- | svtools/source/control/makefile.mk | 4 | ||||
-rw-r--r-- | svtools/source/control/toolbarmenu.cxx | 1800 | ||||
-rw-r--r-- | svtools/source/control/toolbarmenuacc.cxx | 956 | ||||
-rw-r--r-- | svtools/source/control/toolbarmenuimp.hxx | 313 | ||||
-rw-r--r-- | svtools/source/control/valueimp.hxx | 1 | ||||
-rw-r--r-- | svtools/source/control/valueset.cxx | 28 | ||||
-rw-r--r-- | svtools/source/uno/makefile.mk | 4 | ||||
-rw-r--r-- | svtools/source/uno/popupmenucontrollerbase.cxx | 420 | ||||
-rw-r--r-- | svtools/source/uno/popupwindowcontroller.cxx | 226 | ||||
-rw-r--r-- | svtools/source/uno/toolboxcontroller.cxx | 109 |
10 files changed, 3846 insertions, 15 deletions
diff --git a/svtools/source/control/makefile.mk b/svtools/source/control/makefile.mk index a40a81163eb3..a2e622730635 100644 --- a/svtools/source/control/makefile.mk +++ b/svtools/source/control/makefile.mk @@ -51,7 +51,9 @@ EXCEPTIONSFILES=\ $(SLO)$/scriptedtext.obj\ $(SLO)$/fmtfield.obj \ $(SLO)$/inettbc.obj \ - $(SLO)$/valueacc.obj + $(SLO)$/valueacc.obj \ + $(SLO)$/toolbarmenu.obj \ + $(SLO)$/toolbarmenuacc.obj SLOFILES=\ $(EXCEPTIONSFILES) \ diff --git a/svtools/source/control/toolbarmenu.cxx b/svtools/source/control/toolbarmenu.cxx new file mode 100644 index 000000000000..bb332c77cc49 --- /dev/null +++ b/svtools/source/control/toolbarmenu.cxx @@ -0,0 +1,1800 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <comphelper/processfactory.hxx> + +#include <vcl/dockwin.hxx> +#include <vcl/decoview.hxx> +#include <vcl/image.hxx> +#include <vcl/taskpanelist.hxx> + +#include "svtools/valueset.hxx" +#include "svtools/toolbarmenu.hxx" +#include "toolbarmenuimp.hxx" + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::accessibility; + +namespace svtools { + +// -------------------------------------------------------------------- + +static Window* GetTopMostParentSystemWindow( Window* pWindow ) +{ + OSL_ASSERT( pWindow ); + if ( pWindow ) + { + // ->manually search topmost system window + // required because their might be another system window between this and the top window + pWindow = pWindow->GetParent(); + SystemWindow* pTopMostSysWin = NULL; + while ( pWindow ) + { + if ( pWindow->IsSystemWindow() ) + pTopMostSysWin = (SystemWindow*)pWindow; + pWindow = pWindow->GetParent(); + } + pWindow = pTopMostSysWin; + OSL_ASSERT( pWindow ); + return pWindow; + } + + return NULL; +} + +// -------------------------------------------------------------------- + +void ToolbarMenuEntry::init( int nEntryId, MenuItemBits nBits ) +{ + mnEntryId = nEntryId; + mnBits = nBits; + + mbHasText = false; + mbHasImage = false; + mbChecked = false; + mbEnabled = true; + + mpControl = NULL; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maText = rText; + mbHasText = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maImage = rImage; + mbHasImage = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + maText = rText; + mbHasText = true; + + maImage = rImage; + mbHasImage = true; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits ) +: mrMenu( rMenu ) +{ + init( nEntryId, nBits ); + + if( pControl ) + { + mpControl = pControl; + mpControl->Show(); + } +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry::~ToolbarMenuEntry() +{ + if( mxAccContext.is() ) + { + Reference< XComponent > xComponent( mxAccContext, UNO_QUERY ); + if( xComponent.is() ) + xComponent->dispose(); + mxAccContext.clear(); + } + delete mpControl; +} + +// -------------------------------------------------------------------- + +const Reference< XAccessibleContext >& ToolbarMenuEntry::GetAccessible( bool bCreate /* = false */ ) +{ + if( !mxAccContext.is() && bCreate ) + { + if( mpControl ) + { + mxAccContext = Reference< XAccessibleContext >( mpControl->GetAccessible( TRUE ), UNO_QUERY ); + } + else + { + mxAccContext = Reference< XAccessibleContext >( new ToolbarMenuEntryAcc( this ) ); + } + } + + return mxAccContext; +} + +// -------------------------------------------------------------------- + +sal_Int32 ToolbarMenuEntry::getAccessibleChildCount() throw (RuntimeException) +{ + if( mpControl ) + { + const Reference< XAccessibleContext >& xContext = GetAccessible( true ); + if( xContext.is() ) + { + return xContext->getAccessibleChildCount(); + } + } + return 1; +} + +// -------------------------------------------------------------------- + +Reference< XAccessible > ToolbarMenuEntry::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const Reference< XAccessibleContext >& xContext = GetAccessible( true ); + if( mpControl ) + { + if( xContext.is() ) + { + return xContext->getAccessibleChild(index); + } + } + else if( index == 0 ) + { + Reference< XAccessible > xRet( xContext, UNO_QUERY ); + if( xRet.is() ) + return xRet; + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +ToolbarMenu_Impl::ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame ) +: mrMenu( rMenu ) +, mxFrame( xFrame ) +, mxServiceManager( ::comphelper::getProcessServiceFactory() ) +, mnCheckPos(0) +, mnImagePos(0) +, mnTextPos(0) +, mnHighlightedEntry(-1) +, mnSelectedEntry(-1) +, mnLastColumn(0) +{ +} + +// -------------------------------------------------------------------- + +ToolbarMenu_Impl::~ToolbarMenu_Impl() +{ + setAccessible( 0 ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::setAccessible( ToolbarMenuAcc* pAccessible ) +{ + if( mxAccessible.get() != pAccessible ) + { + if( mxAccessible.is() ) + mxAccessible->dispose(); + + mxAccessible.set( pAccessible ); + } +} + +// ----------------------------------------------------------------------- + +void ToolbarMenu_Impl::fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ) +{ + if( mxAccessible.is() ) + mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue ); +} + +// ----------------------------------------------------------------------- + +bool ToolbarMenu_Impl::hasAccessibleListeners() +{ + return( mxAccessible.is() && mxAccessible->HasAccessibleListeners() ); +} + +// -------------------------------------------------------------------- + +sal_Int32 ToolbarMenu_Impl::getAccessibleChildCount() throw (RuntimeException) +{ + sal_Int32 nCount = 0; + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + if( pEntry->mpControl ) + { + nCount += pEntry->getAccessibleChildCount(); + } + else + { + nCount += 1; + } + } + } + + return nCount; +} + +// -------------------------------------------------------------------- + +Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( sal_Int32 index ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( index < nCount ) + { + return pEntry->getAccessibleChild( index ); + } + index -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +void ToolbarMenu_Impl::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( nChildIndex < nCount ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xSel->selectAccessibleChild(nChildIndex); + } + else if( pEntry->mnEntryId != TITLE_ID ) + { + mrMenu.implSelectEntry( nEntry ); + } + return; + } + nChildIndex -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +sal_Bool ToolbarMenu_Impl::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const int nEntryCount = maEntryVector.size(); + for( int nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = maEntryVector[nEntry]; + if( pEntry ) + { + const sal_Int32 nCount = pEntry->getAccessibleChildCount(); + if( nChildIndex < nCount ) + { + if( mnHighlightedEntry == nEntry ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xSel->isAccessibleChildSelected(nChildIndex); + } + return true; + } + else + { + return false; + } + } + nChildIndex -= nCount; + } + } + + throw IndexOutOfBoundsException(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu_Impl::clearAccessibleSelection() +{ + if( mnHighlightedEntry != -1 ) + { + mrMenu.implHighlightEntry( mnHighlightedEntry, false ); + mnHighlightedEntry = -1; + } +} + +// -------------------------------------------------------------------- + +IMPL_LINK( ToolbarMenu, HighlightHdl, Control *, pControl ) +{ + (void)pControl; + if( mpImpl->hasAccessibleListeners() ) + mpImpl->fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); + return 0; +} + +// ==================================================================== + +ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, WinBits nBits ) +: DockingWindow(pParentWindow, nBits) +{ + implInit(rFrame); +} + +// -------------------------------------------------------------------- + +ToolbarMenu::ToolbarMenu( const Reference< XFrame >& rFrame, Window* pParentWindow, const ResId& rResId ) +: DockingWindow(pParentWindow, rResId) +{ + implInit(rFrame); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implInit(const Reference< XFrame >& rFrame) +{ + mpImpl = new ToolbarMenu_Impl( *this, rFrame ); + + initWindow(); + + Window* pWindow = GetTopMostParentSystemWindow( this ); + if ( pWindow ) + ((SystemWindow *)pWindow)->GetTaskPaneList()->AddWindow( this ); +} + +// -------------------------------------------------------------------- + +ToolbarMenu::~ToolbarMenu() +{ + Window* pWindow = GetTopMostParentSystemWindow( this ); + if ( pWindow ) + ((SystemWindow *)pWindow)->GetTaskPaneList()->RemoveWindow( this ); + + if ( mpImpl->mxStatusListener.is() ) + { + mpImpl->mxStatusListener->dispose(); + mpImpl->mxStatusListener.clear(); + } + + // delete all menu entries + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + delete mpImpl->maEntryVector[nEntry]; + } + + delete mpImpl; +} + +// -------------------------------------------------------------------- + +int ToolbarMenu::getSelectedEntryId() const +{ + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnSelectedEntry ); + return pEntry ? pEntry->mnEntryId : -1; +} + +// -------------------------------------------------------------------- + +int ToolbarMenu::getHighlightedEntryId() const +{ + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + return pEntry ? pEntry->mnEntryId : -1; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::checkEntry( int nEntryId, bool bChecked ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->mbChecked != bChecked ) + { + pEntry->mbChecked = bChecked; + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::isEntryChecked( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + return pEntry && pEntry->mbChecked; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::enableEntry( int nEntryId, bool bEnable ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->mbEnabled != bEnable ) + { + pEntry->mbEnabled = bEnable; + if( pEntry->mpControl ) + { + pEntry->mpControl->Enable( bEnable ); + + // hack for the valueset to make it paint itself anew + pEntry->mpControl->Resize(); + } + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::isEntryEnabled( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + return pEntry && pEntry->mbEnabled; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::setEntryText( int nEntryId, const String& rStr ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->maText != rStr ) + { + pEntry->maText = rStr; + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +const String& ToolbarMenu::getEntryText( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry ) + return pEntry->maText; + else + { + static String aEmptyStr; + return aEmptyStr; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::setEntryImage( int nEntryId, const Image& rImage ) +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry && pEntry->maImage != rImage ) + { + pEntry->maImage = rImage; + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +const Image& ToolbarMenu::getEntryImage( int nEntryId ) const +{ + ToolbarMenuEntry* pEntry = implSearchEntry( nEntryId ); + if( pEntry ) + return pEntry->maImage; + else + { + static Image aEmptyImage; + return aEmptyImage; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::initWindow() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + SetControlBackground( GetSettings().GetStyleSettings().GetFaceGradientColor() ); + + SetPointFont( rStyleSettings.GetMenuFont() ); + SetBackground( Wallpaper( GetControlBackground() ) ); + SetTextColor( rStyleSettings.GetMenuTextColor() ); + SetTextFillColor(); + SetLineColor(); + + mpImpl->maSize = implCalcSize(); +} + +// -------------------------------------------------------------------- + +Size ToolbarMenu::implCalcSize() +{ + const long nFontHeight = GetTextHeight(); + long nExtra = nFontHeight/4; + + Size aSz; + Size aMaxImgSz; + long nMaxTextWidth = 0; + long nMinMenuItemHeight = nFontHeight+2; + sal_Bool bCheckable = sal_False; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + const bool bUseImages = rSettings.GetUseImagesInMenus(); + + // get maximum image size + if( bUseImages ) + { + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry && pEntry->mbHasImage ) + { + Size aImgSz( pEntry->maImage.GetSizePixel() ); + nMinMenuItemHeight = std::max( nMinMenuItemHeight, aImgSz.Height() + 6 ); + aMaxImgSz.Width() = std::max( aMaxImgSz.Width(), aImgSz.Width() ); + } + } + } + + mpImpl->mnCheckPos = nExtra; + mpImpl->mnImagePos = nExtra; + mpImpl->mnTextPos = mpImpl->mnImagePos + aMaxImgSz.Width(); + + if ( aMaxImgSz.Width() ) + mpImpl->mnTextPos += std::max( nExtra, 7L ); + if ( bCheckable ) + mpImpl->mnTextPos += 16; + + // set heights, calc maximum width + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + if( pEntry ) + { + if ( ( pEntry->mnBits ) & ( MIB_RADIOCHECK | MIB_CHECKABLE ) ) + bCheckable = sal_True; + + // Text: + if( pEntry->mbHasText || pEntry->mbHasImage ) + { + pEntry->maSize.Height() = nMinMenuItemHeight; + + if( pEntry->mbHasText ) + { + long nTextWidth = GetCtrlTextWidth( pEntry->maText ) + mpImpl->mnTextPos + nExtra; + nMaxTextWidth = std::max( nTextWidth, nMaxTextWidth ); + } + } + // Control: + else if( pEntry->mpControl ) + { + Size aControlSize( pEntry->mpControl->GetOutputSizePixel() ); + + nMaxTextWidth = std::max( aControlSize.Width(), nMaxTextWidth ); + pEntry->maSize.Height() = aControlSize.Height() + 1; + } + + } + } + + aSz.Width() = nMaxTextWidth + (BORDER_X<<1); + + // positionate controls + int nY = BORDER_Y; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + if( pEntry ) + { + pEntry->maSize.Width() = nMaxTextWidth; + + if( pEntry->mpControl ) + { + Size aControlSize( pEntry->mpControl->GetOutputSizePixel() ); + Point aControlPos( (aSz.Width() - aControlSize.Width())>>1, nY); + + pEntry->mpControl->SetPosPixel( aControlPos ); + + pEntry->maRect = Rectangle( aControlPos, aControlSize ); + } + else + { + pEntry->maRect = Rectangle( Point( 0, nY ), pEntry->maSize ); + } + + nY += pEntry->maSize.Height(); + } + else + { + nY += SEPARATOR_HEIGHT; + } + } + + aSz.Height() += nY + BORDER_Y; + + return aSz; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::GetFocus() +{ + if( mpImpl->mnHighlightedEntry == -1 ) + implChangeHighlightEntry( 0 ); + + DockingWindow::GetFocus(); + + // Tell the accessible object that we got the focus. + if( mpImpl->mxAccessible.is() ) + mpImpl->mxAccessible->GetFocus(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::LoseFocus() +{ + if( mpImpl->mnHighlightedEntry != -1 ) + implChangeHighlightEntry( -1 ); + + DockingWindow::LoseFocus(); + + // Tell the accessible object that we lost the focus. + if( mpImpl->mxAccessible.is() ) + mpImpl->mxAccessible->LoseFocus(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rStr, nItemBits ) ); +} + + +#if 0 +todo acc selectentry? + if( ImplHasAccessibleListeners() ) + { + // focus event (deselect) + if( nOldItem ) + { + const USHORT nPos = GetItemPos( nItemId ); + + if( nPos != VALUESET_ITEM_NOTFOUND ) + { + ValueItemAcc* pItemAcc = ValueItemAcc::getImplementation( + mpImpl->mpItemList->GetObject( nPos )->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ) ); + + if( pItemAcc ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + if( !mpImpl->mbIsTransientChildrenDisabled) + { + aOldAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >( + static_cast< ::cppu::OWeakObject* >( pItemAcc )); + ImplFireAccessibleEvent (::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny ); + } + else + { + aOldAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny ); + } + } + } + } + + // focus event (select) + const USHORT nPos = GetItemPos( mnSelItemId ); + + ValueSetItem* pItem; + if( nPos != VALUESET_ITEM_NOTFOUND ) + pItem = mpImpl->mpItemList->GetObject(nPos); + else + pItem = mpNoneItem; + + ValueItemAcc* pItemAcc = NULL; + if (pItem != NULL) + pItemAcc = ValueItemAcc::getImplementation(pItem->GetAccessible( mpImpl->mbIsTransientChildrenDisabled ) ); + + if( pItemAcc ) + { + ::com::sun::star::uno::Any aOldAny, aNewAny; + if( !mpImpl->mbIsTransientChildrenDisabled) + { + aNewAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >( + static_cast< ::cppu::OWeakObject* >( pItemAcc )); + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny ); + } + else + { + aNewAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED; + pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny ); + } + } + + // selection event + ::com::sun::star::uno::Any aOldAny, aNewAny; + ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny ); + } + } +} + +#endif + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const Image& rImage, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, const Image& rImage, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, rImage, rStr, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( int nEntryId, Control* pControl, MenuItemBits nItemBits ) +{ + appendEntry( new ToolbarMenuEntry( *this, nEntryId, pControl, nItemBits ) ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendEntry( ToolbarMenuEntry* pEntry ) +{ + mpImpl->maEntryVector.push_back( pEntry ); + mpImpl->maSize = implCalcSize(); + if( IsVisible() ) + Invalidate(); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::appendSeparator() +{ + appendEntry( 0 ); +} + +// -------------------------------------------------------------------- + +/** creates an empty ValueSet that is initialized and can be inserted with appendEntry. */ +ValueSet* ToolbarMenu::createEmptyValueSetControl() +{ + ValueSet* pSet = new ValueSet( this, WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT ); + pSet->EnableFullItemMode( FALSE ); + pSet->SetColor( GetControlBackground() ); + pSet->SetHighlightHdl( LINK( this, ToolbarMenu, HighlightHdl ) ); + return pSet; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implGetEntry( int nEntry ) const +{ + if( (nEntry < 0) || (nEntry >= (int)mpImpl->maEntryVector.size() ) ) + return NULL; + + return mpImpl->maEntryVector[nEntry]; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implSearchEntry( int nEntryId ) const +{ + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* p = mpImpl->maEntryVector[nEntry]; + if( p && p->mnEntryId == nEntryId ) + { + return p; + } + } + + return NULL; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implHighlightEntry( int nHighlightEntry, bool bHighlight ) +{ + Size aSz( GetOutputSizePixel() ); + long nX = 0, nY = 0; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry && (nEntry == nHighlightEntry) ) + { + // no highlights for controls only items + if( pEntry->mpControl ) + break; + + bool bRestoreLineColor = false; + Color oldLineColor; + bool bDrawItemRect = true; + + Rectangle aItemRect( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ); + if ( pEntry->mnBits & MIB_POPUPSELECT ) + { + long nFontHeight = GetTextHeight(); + aItemRect.Right() -= nFontHeight + nFontHeight/4; + } + + if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) + { + Size aPxSize( GetOutputSizePixel() ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pEntry->maSize.Height() ) ) ); + Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) ); + DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, + Region( aCtrlRect ), + CTRL_STATE_ENABLED, + ImplControlValue(), + OUString() ); + if( bHighlight && IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) ) + { + bDrawItemRect = false; + if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM, + Region( aItemRect ), + CTRL_STATE_SELECTED | ( pEntry->mbEnabled? CTRL_STATE_ENABLED: 0 ), + ImplControlValue(), + OUString() ) ) + { + bDrawItemRect = bHighlight; + } + } + else + bDrawItemRect = bHighlight; + Pop(); + } + if( bDrawItemRect ) + { + if ( bHighlight ) + { + if( pEntry->mbEnabled ) + SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + else + { + SetFillColor(); + oldLineColor = GetLineColor(); + SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + bRestoreLineColor = true; + } + } + else + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + + DrawRect( aItemRect ); + } + implPaint( pEntry, bHighlight ); + if( bRestoreLineColor ) + SetLineColor( oldLineColor ); + break; + } + + nY += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implSelectEntry( int nSelectedEntry ) +{ + mpImpl->mnSelectedEntry = nSelectedEntry; + + ToolbarMenuEntry* pEntry = NULL; + if( nSelectedEntry != -1 ) + pEntry = mpImpl->maEntryVector[ nSelectedEntry ]; + + if( pEntry ) + mpImpl->maSelectHdl.Call( this ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseButtonDown( const MouseEvent& rMEvt ) +{ + implHighlightEntry( rMEvt, true ); + + implSelectEntry( mpImpl->mnHighlightedEntry ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseButtonUp( const MouseEvent& ) +{ +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::MouseMove( const MouseEvent& rMEvt ) +{ + if ( !IsVisible() ) + return; + + implHighlightEntry( rMEvt, false ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implHighlightEntry( const MouseEvent& rMEvt, bool bMBDown ) +{ + long nY = 0; + long nMouseY = rMEvt.GetPosPixel().Y(); + Size aOutSz = GetOutputSizePixel(); + if ( ( nMouseY >= 0 ) && ( nMouseY < aOutSz.Height() ) ) + { + bool bHighlighted = FALSE; + + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + if( pEntry ) + { + long nOldY = nY; + nY += pEntry->maSize.Height(); + + if( pEntry->mnEntryId != TITLE_ID ) + { + if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) ) + { + if( bMBDown ) + { + if( nEntry != mpImpl->mnHighlightedEntry ) + { + implChangeHighlightEntry( nEntry ); + } + } + else + { + if ( nEntry != mpImpl->mnHighlightedEntry ) + { + implChangeHighlightEntry( nEntry ); + } + } + bHighlighted = true; + } + } + } + else + { + nY += SEPARATOR_HEIGHT; + } + } + if ( !bHighlighted ) + implChangeHighlightEntry( -1 ); + } + else + { + implChangeHighlightEntry( -1 ); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::implChangeHighlightEntry( int nEntry ) +{ + if( mpImpl->mnHighlightedEntry != -1 ) + { + implHighlightEntry( mpImpl->mnHighlightedEntry, false ); + } + + mpImpl->mnHighlightedEntry = nEntry; + Invalidate(); + + if( mpImpl->mnHighlightedEntry != -1 ) + { + implHighlightEntry( mpImpl->mnHighlightedEntry, true ); + } + + if( mpImpl->hasAccessibleListeners() ) + mpImpl->fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); +} + +// -------------------------------------------------------------------- + +static bool implCheckSubControlCursorMove( Control* pControl, bool bUp, int& nLastColumn ) +{ + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl ); + if( pValueSet ) + { + USHORT nItemPos = pValueSet->GetItemPos( pValueSet->GetSelectItemId() ); + if( nItemPos != VALUESET_ITEM_NOTFOUND ) + { + const USHORT nColCount = pValueSet->GetColCount(); + const USHORT nLine = nItemPos / nColCount; + + nLastColumn = nItemPos - (nLine * nColCount); + + if( bUp ) + { + return nLine > 0; + } + else + { + const USHORT nLineCount = (pValueSet->GetItemCount() + nColCount - 1) / nColCount; + return (nLine+1) < nLineCount; + } + } + } + + return false; +} + +// -------------------------------------------------------------------- + +ToolbarMenuEntry* ToolbarMenu::implCursorUpDown( bool bUp, bool bHomeEnd ) +{ + int n = 0, nLoop = 0; + if( !bHomeEnd ) + { + n = mpImpl->mnHighlightedEntry; + if( n == -1 ) + { + if( bUp ) + n = 0; + else + n = mpImpl->maEntryVector.size()-1; + } + else + { + // if we have a currently selected entry and + // cursor keys are used than check if this entry + // has a control that can use those cursor keys + ToolbarMenuEntry* pData = mpImpl->maEntryVector[n]; + if( pData && pData->mpControl && !pData->mbHasText ) + { + if( implCheckSubControlCursorMove( pData->mpControl, bUp, mpImpl->mnLastColumn ) ) + return pData; + } + } + nLoop = n; + } + else + { + // absolute positioning + if( bUp ) + { + n = mpImpl->maEntryVector.size(); + nLoop = n-1; + } + else + { + n = -1; + nLoop = mpImpl->maEntryVector.size()-1; + } + } + + do + { + if( bUp ) + { + if ( n ) + n--; + else + if( mpImpl->mnHighlightedEntry == -1 ) + n = mpImpl->maEntryVector.size()-1; + else + break; + } + else + { + if( n < ((int)mpImpl->maEntryVector.size()-1) ) + n++; + else + if( mpImpl->mnHighlightedEntry == -1 ) + n = 0; + else + break; + } + + ToolbarMenuEntry* pData = mpImpl->maEntryVector[n]; + if( pData && (pData->mnEntryId != TITLE_ID) ) + { + implChangeHighlightEntry( n ); + return pData; + } + } while ( n != nLoop ); + + return 0; +} + +// -------------------------------------------------------------------- + +static void implHighlightControl( USHORT nCode, Control* pControl, int nLastColumn ) +{ + ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl ); + if( pValueSet ) + { + const USHORT nItemCount = pValueSet->GetItemCount(); + USHORT nItemPos = VALUESET_ITEM_NOTFOUND; + switch( nCode ) + { + case KEY_UP: + { + const USHORT nColCount = pValueSet->GetColCount(); + const USHORT nLastLine = nItemCount / nColCount; + nItemPos = std::min( ((nLastLine-1) * nColCount) + nLastColumn, nItemCount-1 ); + break; + } + case KEY_DOWN: + nItemPos = std::min( nLastColumn, nItemCount-1 ); + break; + case KEY_END: + nItemPos = nItemCount -1; + break; + case KEY_HOME: + nItemPos = 0; + break; + } + pValueSet->SelectItem( pValueSet->GetItemId( nItemPos ) ); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::KeyInput( const KeyEvent& rKEvent ) +{ + Control* pForwardControl = 0; + USHORT nCode = rKEvent.GetKeyCode().GetCode(); + switch ( nCode ) + { + case KEY_UP: + case KEY_DOWN: + { + int nOldEntry = mpImpl->mnHighlightedEntry; + ToolbarMenuEntry*p = implCursorUpDown( nCode == KEY_UP, false ); + if( p && p->mpControl ) + { + if( nOldEntry != mpImpl->mnHighlightedEntry ) + { + implHighlightControl( nCode, p->mpControl, mpImpl->mnLastColumn ); + } + else + { + // in case we are in a system floating window, GrabFocus does not work :-/ + pForwardControl = p->mpControl; + } + } + } + break; + case KEY_END: + case KEY_HOME: + { + ToolbarMenuEntry* p = implCursorUpDown( nCode == KEY_END, true ); + if( p && p->mpControl ) + { + implHighlightControl( nCode, p->mpControl, mpImpl->mnLastColumn ); + } + } + break; + case KEY_F6: + case KEY_ESCAPE: + { + // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document + if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() ) + break; + + implSelectEntry( -1 ); + } + break; + + case KEY_RETURN: + { + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + if ( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) ) + { + if( pEntry->mpControl ) + { + pForwardControl = pEntry->mpControl; + } + else + { + implSelectEntry( mpImpl->mnHighlightedEntry ); + } + } + } + break; + default: + { + ToolbarMenuEntry* pEntry = implGetEntry( mpImpl->mnHighlightedEntry ); + if ( pEntry && pEntry->mbEnabled && pEntry->mpControl && !pEntry->mbHasText ) + { + pForwardControl = pEntry->mpControl; + } + } + + } + if( pForwardControl ) + pForwardControl->KeyInput( rKEvent ); + +} + +// -------------------------------------------------------------------- +static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight ) +{ + BOOL bNativeOk = FALSE; + if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + ImplControlValue aControlValue; + Region aCtrlRegion( i_rRect ); + ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED; + + aControlValue.setTristateVal( BUTTONVALUE_ON ); + + bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, + aCtrlRegion, nState, aControlValue, + rtl::OUString() ); + } + + if( ! bNativeOk ) + { + const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings(); + Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() ); + i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor ); + } +} + +static long ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) +{ + rMaxWidth = rCheckHeight = rRadioHeight = 0; + + ImplControlValue aVal; + Region aNativeBounds; + Region aNativeContent; + Point tmp( 0, 0 ); + Region aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) ); + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_CHECK_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rCheckHeight = aNativeBounds.GetBoundRect().GetHeight(); + rMaxWidth = aNativeContent.GetBoundRect().GetWidth(); + } + } + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_RADIO_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rRadioHeight = aNativeBounds.GetBoundRect().GetHeight(); + rMaxWidth = Max (rMaxWidth, aNativeContent.GetBoundRect().GetWidth()); + } + } + return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight; +} + +void ToolbarMenu::implPaint( ToolbarMenuEntry* pThisOnly, bool bHighlighted ) +{ + USHORT nBorder = 0; long nStartY = 0; // from Menu implementations, needed when we support native menu background & scrollable menu + + long nFontHeight = GetTextHeight(); +// long nExtra = nFontHeight/4; + + long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0; + ImplGetNativeCheckAndRadioSize( this, nCheckHeight, nRadioHeight, nMaxCheckWidth ); + + DecorationView aDecoView( this ); + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + + int nOuterSpace = 0; // ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder; + Point aTopLeft( nOuterSpace, nOuterSpace ), aTmpPos; + + Size aOutSz( GetOutputSizePixel() ); + const int nEntryCount = mpImpl->maEntryVector.size(); + int nEntry; + for( nEntry = 0; nEntry < nEntryCount; nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpImpl->maEntryVector[nEntry]; + + Point aPos( aTopLeft ); + aPos.Y() += nBorder; + aPos.Y() += nStartY; + + + if( (pEntry == 0) && !pThisOnly ) + { + // Separator + aTmpPos.Y() = aPos.Y() + ((SEPARATOR_HEIGHT-2)/2); + aTmpPos.X() = aPos.X() + 2 + nOuterSpace; + SetLineColor( rSettings.GetShadowColor() ); + DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + aTmpPos.Y()++; + SetLineColor( rSettings.GetLightColor() ); + DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + SetLineColor(); + } + else if( !pThisOnly || ( pEntry == pThisOnly ) ) + { + const bool bTitle = pEntry->mnEntryId == TITLE_ID; + + if ( pThisOnly && bHighlighted ) + SetTextColor( rSettings.GetMenuHighlightTextColor() ); + + if( aPos.Y() >= 0 ) + { + long nTextOffsetY = ((pEntry->maSize.Height()-nFontHeight)/2); + + USHORT nTextStyle = 0; + USHORT nSymbolStyle = 0; + USHORT nImageStyle = 0; + + if( !pEntry->mbEnabled ) + { + nTextStyle |= TEXT_DRAW_DISABLE; + nSymbolStyle |= SYMBOL_DRAW_DISABLE; + nImageStyle |= IMAGE_DRAW_DISABLE; + } + + Rectangle aOuterCheckRect( Point( aPos.X()+mpImpl->mnCheckPos, aPos.Y() ), Size( pEntry->maSize.Height(), pEntry->maSize.Height() ) ); + aOuterCheckRect.Left() += 1; + aOuterCheckRect.Right() -= 1; + aOuterCheckRect.Top() += 1; + aOuterCheckRect.Bottom() -= 1; + + if( bTitle ) + { + // fill the background + Rectangle aRect( aTopLeft, Size( aOutSz.Width(), pEntry->maSize.Height() ) ); + SetFillColor(rSettings.GetDialogColor()); + SetLineColor(); + DrawRect(aRect); + SetLineColor( rSettings.GetLightColor() ); + DrawLine( aRect.TopLeft(), aRect.TopRight() ); + SetLineColor( rSettings.GetShadowColor() ); + DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); + } + + // CheckMark + if ( pEntry->HasCheck() ) + { + // draw selection transparent marker if checked + // onto that either a checkmark or the item image + // will be painted + // however do not do this if native checks will be painted since + // the selection color too often does not fit the theme's check and/or radio + + if( !pEntry->mbHasImage ) + { + if( this->IsNativeControlSupported( CTRL_MENU_POPUP, + (pEntry->mnBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_CHECK_MARK + : PART_MENU_ITEM_RADIO_MARK ) ) + { + ControlPart nPart = ((pEntry->mnBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_RADIO_MARK + : PART_MENU_ITEM_CHECK_MARK); + + ControlState nState = 0; + + if ( pEntry->mbChecked ) + nState |= CTRL_STATE_PRESSED; + + if ( pEntry->mbEnabled ) + nState |= CTRL_STATE_ENABLED; + + if ( bHighlighted ) + nState |= CTRL_STATE_SELECTED; + + long nCtrlHeight = (pEntry->mnBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight; + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2; + + Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) ); + DrawNativeControl( CTRL_MENU_POPUP, nPart, Region( aCheckRect ), nState, ImplControlValue(), OUString() ); + } + else if ( pEntry->mbChecked ) // by default do nothing for unchecked items + { + ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted ); + + SymbolType eSymbol; + Size aSymbolSize; + if ( pEntry->mnBits & MIB_RADIOCHECK ) + { + eSymbol = SYMBOL_RADIOCHECKMARK; + aSymbolSize = Size( nFontHeight/2, nFontHeight/2 ); + } + else + { + eSymbol = SYMBOL_CHECKMARK; + aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 ); + } + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2; + Rectangle aRect( aTmpPos, aSymbolSize ); + aDecoView.DrawSymbol( aRect, eSymbol, GetTextColor(), nSymbolStyle ); + } + } + } + + // Image: + if( pEntry->mbHasImage ) + { + // Don't render an image for a check thing + /* if((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pEntry->HasCheck() )*/ + { + if( pEntry->mbChecked ) + ImplPaintCheckBackground( this, aOuterCheckRect, pThisOnly && bHighlighted ); + aTmpPos = aOuterCheckRect.TopLeft(); + aTmpPos.X() += (aOuterCheckRect.GetWidth()-pEntry->maImage.GetSizePixel().Width())/2; + aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pEntry->maImage.GetSizePixel().Height())/2; + DrawImage( aTmpPos, pEntry->maImage, nImageStyle ); + } + } + + // Text: + if( pEntry->mbHasText ) + { + aTmpPos.X() = aPos.X() + (bTitle ? 4 : mpImpl->mnTextPos); + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC; + + DrawCtrlText( aTmpPos, pEntry->maText, 0, pEntry->maText.Len(), nStyle, NULL, NULL ); // pVector, pDisplayText ); + } + +/* + // Accel + if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) + { + XubString aAccText = pData->aAccelKey.GetName(); + aTmpPos.X() = aOutSz.Width() - this->GetTextWidth( aAccText ); + aTmpPos.X() -= 4*nExtra; + + aTmpPos.X() -= nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + this->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle ); + } +*/ + +/* + // SubMenu? + if ( !bLayout && !bIsMenuBar && pData->pSubMenu ) + { + aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nExtra/2; + aTmpPos.Y() += ( pEntry->maSize.Height() / 2 ) - ( nFontHeight/4 ); + if ( pEntry->mnBits & MIB_POPUPSELECT ) + { + this->SetTextColor( rSettings.GetMenuTextColor() ); + Point aTmpPos2( aPos ); + aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4; + aDecoView.DrawFrame( + Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pEntry->maSize.Height() ) ), FRAME_DRAW_GROUP ); + } + aDecoView.DrawSymbol( + Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ), + SYMBOL_SPIN_RIGHT, this->GetTextColor(), nSymbolStyle ); +// if ( pEntry->mnBits & MIB_POPUPSELECT ) +// { +// aTmpPos.Y() += nFontHeight/2 ; +// this->SetLineColor( rSettings.GetShadowColor() ); +// this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) ); +// this->SetLineColor( rSettings.GetLightColor() ); +// aTmpPos.Y()++; +// this->DrawLine( aTmpPos, Point( aTmpPos.X() + nFontHeight/3, aTmpPos.Y() ) ); +// this->SetLineColor(); +// } + } +*/ + + if ( pThisOnly && bHighlighted ) + { + // This restores the normal menu or menu bar text + // color for when it is no longer highlighted. + SetTextColor( rSettings.GetMenuTextColor() ); + } + } + } + + aTopLeft.Y() += pEntry ? pEntry->maSize.Height() : SEPARATOR_HEIGHT; + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::Paint( const Rectangle& ) +{ + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + + implPaint(); + + if( mpImpl->mnHighlightedEntry != -1 ) + implHighlightEntry( mpImpl->mnHighlightedEntry, true ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::RequestHelp( const HelpEvent& rHEvt ) +{ + DockingWindow::RequestHelp( rHEvt ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::StateChanged( StateChangedType nType ) +{ + DockingWindow::StateChanged( nType ); + + if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) + { + initWindow(); + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::DataChanged( const DataChangedEvent& rDCEvt ) +{ + DockingWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + initWindow(); + Invalidate(); + } +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) ) + { + implCursorUpDown( pData->GetDelta() > 0L, false ); + } + } +} + +// -------------------------------------------------------------------- + +Reference< ::com::sun::star::accessibility::XAccessible > ToolbarMenu::CreateAccessible() +{ + mpImpl->setAccessible( new ToolbarMenuAcc( *mpImpl ) ); + return Reference< XAccessible >( mpImpl->mxAccessible.get() ); +} + +// -------------------------------------------------------------------- + +// todo: move to new base class that will replace SfxPopupWindo +void ToolbarMenu::AddStatusListener( const rtl::OUString& rCommandURL ) +{ + initStatusListener(); + mpImpl->mxStatusListener->addStatusListener( rCommandURL ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::RemoveStatusListener( const rtl::OUString& rCommandURL ) +{ + mpImpl->mxStatusListener->removeStatusListener( rCommandURL ); +} +// -------------------------------------------------------------------- + + +void ToolbarMenu::UpdateStatus( const rtl::OUString& rCommandURL ) +{ + mpImpl->mxStatusListener->updateStatus( rCommandURL ); +} + +// -------------------------------------------------------------------- + +// XStatusListener (subclasses must override this one to get the status updates +void SAL_CALL ToolbarMenu::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& /*Event*/ ) throw ( ::com::sun::star::uno::RuntimeException ) +{ +} + +// -------------------------------------------------------------------- + +class ToolbarMenuStatusListener : public svt::FrameStatusListener +{ +public: + ToolbarMenuStatusListener( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame, + ToolbarMenu& rToolbarMenu ); + + virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException ); + + ToolbarMenu* mpMenu; +}; + +// -------------------------------------------------------------------- + +ToolbarMenuStatusListener::ToolbarMenuStatusListener( + const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xServiceManager, + const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame, + ToolbarMenu& rToolbarMenu ) +: svt::FrameStatusListener( xServiceManager, xFrame ) +, mpMenu( &rToolbarMenu ) +{ +} + +// -------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuStatusListener::dispose() throw (::com::sun::star::uno::RuntimeException) +{ + mpMenu = 0; + svt::FrameStatusListener::dispose(); +} + +// -------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuStatusListener::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + if( mpMenu ) + mpMenu->statusChanged( Event ); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::initStatusListener() +{ + if( !mpImpl->mxStatusListener.is() ) + mpImpl->mxStatusListener.set( new ToolbarMenuStatusListener( mpImpl->mxServiceManager, mpImpl->mxFrame, *this ) ); +} + +// -------------------------------------------------------------------- + +bool ToolbarMenu::IsInPopupMode() +{ + return GetDockingManager()->IsInPopupMode(this); +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::EndPopupMode() +{ + GetDockingManager()->EndPopupMode(this); +} + +// -------------------------------------------------------------------- + +const Size& ToolbarMenu::getMenuSize() const +{ + return mpImpl->maSize; +} + +// -------------------------------------------------------------------- + +void ToolbarMenu::SetSelectHdl( const Link& rLink ) +{ + mpImpl->maSelectHdl = rLink; +} + +// -------------------------------------------------------------------- + +const Link& ToolbarMenu::GetSelectHdl() const +{ + return mpImpl->maSelectHdl; +} + +// -------------------------------------------------------------------- + +Reference< XFrame > ToolbarMenu::GetFrame() const +{ + return mpImpl->mxFrame; +} + +// -------------------------------------------------------------------- + + +// -------------------------------------------------------------------- + +} + + diff --git a/svtools/source/control/toolbarmenuacc.cxx b/svtools/source/control/toolbarmenuacc.cxx new file mode 100644 index 000000000000..702c1f72b83d --- /dev/null +++ b/svtools/source/control/toolbarmenuacc.cxx @@ -0,0 +1,956 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <unotools/accessiblestatesethelper.hxx> + +#include <vcl/svapp.hxx> + +#include "svtools/toolbarmenu.hxx" + +#include "toolbarmenuimp.hxx" + +using ::rtl::OUString; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; + +namespace svtools { + +// ------------------ +// - ToolbarMenuAcc - +// ------------------ + +ToolbarMenuAcc::ToolbarMenuAcc( ToolbarMenu_Impl& rParent ) +: ToolbarMenuAccComponentBase(m_aMutex) +, mpParent( &rParent ) +, mbIsFocused(false) +{ +} + +// ----------------------------------------------------------------------------- + +ToolbarMenuAcc::~ToolbarMenuAcc() +{ +} + +// ----------------------------------------------------------------------- + +void ToolbarMenuAcc::FireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue ) +{ + if( nEventId ) + { + EventListenerVector aTmpListeners( mxEventListeners ); + EventListenerVector::const_iterator aIter( aTmpListeners.begin() ); + AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + try + { + (*aIter)->notifyEvent( aEvtObject ); + } + catch( Exception& ) + { + } + + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +void ToolbarMenuAcc::GetFocus (void) +{ + mbIsFocused = true; + FireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), Any( AccessibleStateType::FOCUSED ) ); +} + +// ----------------------------------------------------------------------------- + +void ToolbarMenuAcc::LoseFocus (void) +{ + mbIsFocused = false; + FireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any( AccessibleStateType::FOCUSED ), Any() ); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleContext > SAL_CALL ToolbarMenuAcc::getAccessibleContext() throw (RuntimeException) +{ + ThrowIfDisposed(); + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getAccessibleChildCount() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->getAccessibleChildCount(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->getAccessibleChild(i); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleParent() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + + Reference< XAccessible > xRet; + + Window* pParent = mpParent->mrMenu.GetParent(); + if( pParent ) + xRet = pParent->GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getAccessibleIndexInParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + Window* pParent = mpParent->mrMenu.GetParent(); + if( pParent ) + { + for( USHORT i = 0, nCount = pParent->GetChildCount(); i < nCount ; i++ ) + { + if( pParent->GetChild( i ) == &mpParent->mrMenu ) + return i; + } + } + + return 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ToolbarMenuAcc::getAccessibleRole() throw (RuntimeException) +{ + ThrowIfDisposed(); + return AccessibleRole::LIST; +} + +// ----------------------------------------------------------------------------- + +OUString SAL_CALL ToolbarMenuAcc::getAccessibleDescription() throw (RuntimeException) +{ + ThrowIfDisposed(); + return OUString( RTL_CONSTASCII_USTRINGPARAM( "ToolbarMenu" ) ); +} + +// ----------------------------------------------------------------------------- + +OUString SAL_CALL ToolbarMenuAcc::getAccessibleName() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + OUString aRet; + + if( mpParent ) + aRet = mpParent->mrMenu.GetAccessibleName(); + + if( !aRet.getLength() ) + { + Window* pLabel = mpParent->mrMenu.GetLabeledBy(); + if( pLabel && pLabel != &mpParent->mrMenu ) + aRet = OutputDevice::GetNonMnemonicString( pLabel->GetText() ); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleRelationSet > SAL_CALL ToolbarMenuAcc::getAccessibleRelationSet() throw (RuntimeException) +{ + ThrowIfDisposed(); + return Reference< XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleStateSet > SAL_CALL ToolbarMenuAcc::getAccessibleStateSet() throw (RuntimeException) +{ + ThrowIfDisposed(); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper(); + + // Set some states. + pStateSet->AddState (AccessibleStateType::ENABLED); + pStateSet->AddState (AccessibleStateType::SENSITIVE); + pStateSet->AddState (AccessibleStateType::SHOWING); + pStateSet->AddState (AccessibleStateType::VISIBLE); + pStateSet->AddState (AccessibleStateType::MANAGES_DESCENDANTS); + pStateSet->AddState (AccessibleStateType::FOCUSABLE); + if (mbIsFocused) + pStateSet->AddState (AccessibleStateType::FOCUSED); + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +Locale SAL_CALL ToolbarMenuAcc::getLocale() throw (IllegalAccessibleComponentStateException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const ::rtl::OUString aEmptyStr; + Reference< XAccessible > xParent( getAccessibleParent() ); + Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + if( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale (); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::addEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard(m_aMutex); + + if( rxListener.is() ) + { + EventListenerVector::const_iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = true; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::removeEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + ThrowIfDisposed(); + ::osl::MutexGuard aGuard(m_aMutex); + + if( rxListener.is() ) + { + EventListenerVector::iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = true; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuAcc::containsPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + ThrowIfDisposed(); + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getAccessibleAtPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + Reference< XAccessible > xRet; + + const Point aVclPoint( aPoint.X, aPoint.Y ); + + const int nEntryCount = mpParent->maEntryVector.size(); + for( int nEntry = 0; (nEntry < nEntryCount) && !xRet.is(); nEntry++ ) + { + ToolbarMenuEntry* pEntry = mpParent->maEntryVector[nEntry]; + if( pEntry && pEntry->maRect.IsInside( aVclPoint ) ) + { + if( pEntry->mpControl ) + { + awt::Point aChildPoint( aPoint.X - pEntry->maRect.Left(), aPoint.Y - pEntry->maRect.Top() ); + Reference< XAccessibleComponent > xComp( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + xRet = xComp->getAccessibleAtPoint(aChildPoint); + } + else + { + xRet = Reference< XAccessible >( pEntry->GetAccessible(true), UNO_QUERY ); + } + } + } + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ToolbarMenuAcc::getBounds() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aOutPos( mpParent->mrMenu.GetPosPixel() ); + const Size aOutSize( mpParent->mrMenu.GetOutputSizePixel() ); + awt::Rectangle aRet; + + aRet.X = aOutPos.X(); + aRet.Y = aOutPos.Y(); + aRet.Width = aOutSize.Width(); + aRet.Height = aOutSize.Height(); + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuAcc::getLocation() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aOutPos( mpParent->mrMenu.GetPosPixel() ); + return awt::Point( aOutPos.X(), aOutPos.Y() ); +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuAcc::getLocationOnScreen() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Point aScreenPos( mpParent->mrMenu.OutputToAbsoluteScreenPixel( Point() ) ); + return awt::Point( aScreenPos.X(), aScreenPos.Y() ); +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ToolbarMenuAcc::getSize() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + const Size aOutSize( mpParent->mrMenu.GetOutputSizePixel() ); + return awt::Size( aOutSize.Width(), aOutSize.Height() ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::grabFocus() throw (RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + mpParent->mrMenu.GrabFocus(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL ToolbarMenuAcc::getAccessibleKeyBinding() throw (RuntimeException) +{ + ThrowIfDisposed(); + return Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getForeground() throw (RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetMenuTextColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getBackground() throw (RuntimeException) +{ + ThrowIfDisposed(); + UINT32 nColor = Application::GetSettings().GetStyleSettings().GetMenuColor().GetColor(); + return static_cast<sal_Int32>(nColor); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + mpParent->selectAccessibleChild( nChildIndex ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuAcc::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + return mpParent->isAccessibleChildSelected( nChildIndex ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::clearAccessibleSelection() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + mpParent->clearAccessibleSelection(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::selectAllAccessibleChildren() throw (RuntimeException) +{ + ThrowIfDisposed(); + // unsupported due to single selection only +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuAcc::getSelectedAccessibleChildCount() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ThrowIfDisposed(); + + return mpParent->mnHighlightedEntry != -1 ? 1 : 0; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuAcc::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + + if( (mpParent->mnHighlightedEntry != -1) && (nSelectedChildIndex == 0) ) + { + ToolbarMenuEntry* pEntry = mpParent->maEntryVector[ mpParent->mnHighlightedEntry ]; + if( pEntry ) + { + if( pEntry->mpControl ) + { + Reference< XAccessibleSelection > xSel( pEntry->GetAccessible(true), UNO_QUERY_THROW ); + return xSel->getSelectedAccessibleChild(0); + } + else + return Reference< XAccessible >( pEntry->GetAccessible(true), UNO_QUERY ); + } + } + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::deselectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ThrowIfDisposed(); + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // Because of the single selection we can reset the whole selection when + // the specified child is currently selected. + if (isAccessibleChildSelected(nChildIndex)) + mpParent->clearAccessibleSelection(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuAcc::disposing (void) +{ + EventListenerVector aListenerListCopy; + + { + // Make a copy of the list and clear the original. + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard (m_aMutex); + aListenerListCopy = mxEventListeners; + mxEventListeners.clear(); + + // Reset the pointer to the parent. It has to be the one who has + // disposed us because he is dying. + mpParent = NULL; + } + + // Inform all listeners that this objects is disposing. + EventListenerVector::const_iterator aListenerIterator (aListenerListCopy.begin()); + EventObject aEvent (static_cast<XAccessible*>(this)); + while(aListenerIterator != aListenerListCopy.end()) + { + try + { + (*aListenerIterator)->disposing (aEvent); + } + catch( Exception& ) + { + // Ignore exceptions. + } + + ++aListenerIterator; + } +} + +void ToolbarMenuAcc::ThrowIfDisposed (void) throw (DisposedException) +{ + if(rBHelper.bDisposed || rBHelper.bInDispose) + { + throw DisposedException ( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), static_cast<XWeak*>(this)); + } +} + +// ----------------------- +// - ToolbarMenuEntryAcc - +// ----------------------- + +ToolbarMenuEntryAcc::ToolbarMenuEntryAcc( ToolbarMenuEntry* pParent ) +: ToolbarMenuEntryAccBase( m_aMutex ) +, mpParent( pParent ) +{ +} + +// ----------------------------------------------------------------------------- + +ToolbarMenuEntryAcc::~ToolbarMenuEntryAcc() +{ +} + +// ----------------------------------------------------------------------- + +void ToolbarMenuEntryAcc::FireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue ) +{ + if( nEventId ) + { + EventListenerVector aTmpListeners( mxEventListeners ); + ::std::vector< Reference< XAccessibleEventListener > >::const_iterator aIter( aTmpListeners.begin() ); + AccessibleEventObject aEvtObject; + + aEvtObject.EventId = nEventId; + aEvtObject.Source = static_cast<XWeak*>(this); + aEvtObject.NewValue = rNewValue; + aEvtObject.OldValue = rOldValue; + + while( aIter != aTmpListeners.end() ) + { + (*aIter)->notifyEvent( aEvtObject ); + aIter++; + } + } +} + + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::disposing (void) +{ + EventListenerVector aListenerListCopy; + + { + // Make a copy of the list and clear the original. + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard (m_aMutex); + aListenerListCopy = mxEventListeners; + mxEventListeners.clear(); + + // Reset the pointer to the parent. It has to be the one who has + // disposed us because he is dying. + mpParent = NULL; + } + + // Inform all listeners that this objects is disposing. + EventListenerVector::const_iterator aListenerIterator (aListenerListCopy.begin()); + EventObject aEvent (static_cast<XAccessible*>(this)); + while(aListenerIterator != aListenerListCopy.end()) + { + try + { + (*aListenerIterator)->disposing (aEvent); + } + catch( Exception& ) + { + // Ignore exceptions. + } + + ++aListenerIterator; + } +} +// ----------------------------------------------------------------------------- + +Reference< XAccessibleContext > SAL_CALL ToolbarMenuEntryAcc::getAccessibleContext() throw (RuntimeException) +{ + return this; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getAccessibleChildCount() throw (RuntimeException) +{ + return 0; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleChild( sal_Int32 ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + Reference< XAccessible > xRet; + + if( mpParent ) + xRet = mpParent->mrMenu.GetAccessible(); + + return xRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getAccessibleIndexInParent() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + // The index defaults to -1 to indicate the child does not belong to its + // parent. + sal_Int32 nIndexInParent = -1; + + if( mpParent ) + { + Reference< XAccessibleContext > xParent( mpParent->mrMenu.GetAccessible(), UNO_QUERY ); + + if( xParent.is() ) + { + Reference< XAccessible > xThis( this ); + + const sal_Int32 nCount = xParent->getAccessibleChildCount(); + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + if( xParent->getAccessibleChild(nIndex) == xThis ) + { + nIndexInParent = nIndex; + break; + } + } + } + } + + return nIndexInParent; +} + +// ----------------------------------------------------------------------------- + +sal_Int16 SAL_CALL ToolbarMenuEntryAcc::getAccessibleRole() throw (RuntimeException) +{ + return AccessibleRole::LIST_ITEM; +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ToolbarMenuEntryAcc::getAccessibleDescription() throw (RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "ToolbarMenu item" ) ); +} + +// ----------------------------------------------------------------------------- + +::rtl::OUString SAL_CALL ToolbarMenuEntryAcc::getAccessibleName() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + String aRet; + + if( mpParent ) + { + aRet = mpParent->maText; + + if( !aRet.Len() ) + { + aRet = String( RTL_CONSTASCII_USTRINGPARAM( "Item " ) ); + aRet += String::CreateFromInt32( mpParent->mnEntryId ); + } + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleRelationSet > SAL_CALL ToolbarMenuEntryAcc::getAccessibleRelationSet() throw (RuntimeException) +{ + return Reference< XAccessibleRelationSet >(); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessibleStateSet > SAL_CALL ToolbarMenuEntryAcc::getAccessibleStateSet() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper; + + if( mpParent ) + { + pStateSet->AddState (AccessibleStateType::ENABLED); + pStateSet->AddState (AccessibleStateType::SENSITIVE); + pStateSet->AddState (AccessibleStateType::SHOWING); + pStateSet->AddState (AccessibleStateType::VISIBLE); + pStateSet->AddState (AccessibleStateType::TRANSIENT); + if( mpParent->mnEntryId != TITLE_ID ) + { + pStateSet->AddState( AccessibleStateType::SELECTABLE ); + + // SELECTED + if( mpParent->mrMenu.getHighlightedEntryId() == mpParent->mnEntryId ) + pStateSet->AddState( AccessibleStateType::SELECTED ); + } + } + + return pStateSet; +} + +// ----------------------------------------------------------------------------- + +Locale SAL_CALL ToolbarMenuEntryAcc::getLocale() throw (IllegalAccessibleComponentStateException, RuntimeException) +{ + const ::rtl::OUString aEmptyStr; + Locale aRet( aEmptyStr, aEmptyStr, aEmptyStr ); + + Reference< XAccessible > xParent( getAccessibleParent() ); + if( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + + if( xParentContext.is() ) + aRet = xParentContext->getLocale(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::addEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + EventListenerVector::const_iterator aIter( mxEventListeners.begin() ); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + bFound = true; + else + aIter++; + } + + if (!bFound) + mxEventListeners.push_back( rxListener ); + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::removeEventListener( const Reference< XAccessibleEventListener >& rxListener ) throw (RuntimeException) +{ + const ::vos::OGuard aGuard( maMutex ); + + if( rxListener.is() ) + { + EventListenerVector::iterator aIter = mxEventListeners.begin(); + bool bFound = false; + + while( !bFound && ( aIter != mxEventListeners.end() ) ) + { + if( *aIter == rxListener ) + { + mxEventListeners.erase( aIter ); + bFound = true; + } + else + aIter++; + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL ToolbarMenuEntryAcc::containsPoint( const awt::Point& aPoint ) throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + const Point aSize( aRect.Width, aRect.Height ); + const Point aNullPoint, aTestPoint( aPoint.X, aPoint.Y ); + + return Rectangle( aNullPoint, aSize ).IsInside( aTestPoint ); +} + +// ----------------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ToolbarMenuEntryAcc::getAccessibleAtPoint( const awt::Point& ) throw (RuntimeException) +{ + Reference< XAccessible > xRet; + return xRet; +} + +// ----------------------------------------------------------------------------- + +awt::Rectangle SAL_CALL ToolbarMenuEntryAcc::getBounds() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Rectangle aRet; + + if( mpParent ) + { + Rectangle aRect( mpParent->maRect ); + Point aOrigin; + Rectangle aParentRect( aOrigin, mpParent->mrMenu.GetOutputSizePixel() ); + + aRect.Intersection( aParentRect ); + + aRet.X = aRect.Left(); + aRet.Y = aRect.Top(); + aRet.Width = aRect.GetWidth(); + aRet.Height = aRect.GetHeight(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuEntryAcc::getLocation() throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + return awt::Point( aRect.X, aRect.Y ); +} + +// ----------------------------------------------------------------------------- + +awt::Point SAL_CALL ToolbarMenuEntryAcc::getLocationOnScreen() throw (RuntimeException) +{ + const vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + awt::Point aRet; + + if( mpParent ) + { + const Point aScreenPos( mpParent->mrMenu.OutputToAbsoluteScreenPixel( mpParent->maRect.TopLeft() ) ); + + aRet.X = aScreenPos.X(); + aRet.Y = aScreenPos.Y(); + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +awt::Size SAL_CALL ToolbarMenuEntryAcc::getSize() throw (RuntimeException) +{ + const awt::Rectangle aRect( getBounds() ); + awt::Size aRet; + + aRet.Width = aRect.Width; + aRet.Height = aRect.Height; + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL ToolbarMenuEntryAcc::grabFocus() throw (RuntimeException) +{ + // nothing to do +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL ToolbarMenuEntryAcc::getAccessibleKeyBinding() throw (RuntimeException) +{ + return Any(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getForeground( ) throw (RuntimeException) +{ + return static_cast<sal_Int32>(Application::GetSettings().GetStyleSettings().GetMenuTextColor().GetColor()); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL ToolbarMenuEntryAcc::getBackground( ) throw (RuntimeException) +{ + return static_cast<sal_Int32>(Application::GetSettings().GetStyleSettings().GetMenuColor().GetColor()); +} + +} diff --git a/svtools/source/control/toolbarmenuimp.hxx b/svtools/source/control/toolbarmenuimp.hxx new file mode 100644 index 000000000000..1d9037b61dc5 --- /dev/null +++ b/svtools/source/control/toolbarmenuimp.hxx @@ -0,0 +1,313 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <vos/mutex.hxx> +#include <vcl/image.hxx> +#include <vcl/menu.hxx> + +#include <cppuhelper/compbase4.hxx> +#include <cppuhelper/compbase5.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +#include <rtl/ref.hxx> + +#include <vector> + +#include "framestatuslistener.hxx" + +#include "svtools/valueset.hxx" + +namespace svtools { + +struct ToolbarMenu_Impl; +class ToolbarMenu; +class ToolbarMenuEntry; + +typedef ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener > > EventListenerVector; +typedef std::vector< ToolbarMenuEntry * > ToolbarMenuEntryVector; + +const int EXTRAITEMHEIGHT = 0; // 4; +const int SEPARATOR_HEIGHT = 4; +const int TITLE_ID = -1; +const int BORDER_X = 0; +const int BORDER_Y = 0; + +// -------------------- +// - ToolbarMenuEntry - +// -------------------- + +class ToolbarMenuEntry +{ +public: + ToolbarMenu& mrMenu; + + int mnEntryId; + MenuItemBits mnBits; + Size maSize; + + bool mbHasText; + bool mbHasImage; + bool mbChecked; + bool mbEnabled; + + String maText; + Image maImage; + Control* mpControl; + Rectangle maRect; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > mxAccContext; + +public: + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const String& rText, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, const Image& rImage, const String& rText, MenuItemBits nBits ); + ToolbarMenuEntry( ToolbarMenu& rMenu, int nEntryId, Control* pControl, MenuItemBits nBits ); + ~ToolbarMenuEntry(); + + void init( int nEntryId, MenuItemBits nBits ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& GetAccessible( bool bCreate = false ); + + sal_Int32 getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessibleChild( sal_Int32 index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + void selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + bool HasCheck() const + { + return mbChecked || ( mnBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) ); + } +}; + +// --------------- +// - ToolbarMenuAcc - +// --------------- + +typedef ::cppu::WeakComponentImplHelper5< + ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent, + ::com::sun::star::accessibility::XAccessibleSelection > + ToolbarMenuAccComponentBase; + +class ToolbarMenuAcc : + public ::comphelper::OBaseMutex, + public ToolbarMenuAccComponentBase +{ +public: + + ToolbarMenuAcc( ToolbarMenu_Impl& rParent ); + ~ToolbarMenuAcc(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + +public: + + /** Called by the corresponding ToolbarMenu when it gets the focus. + Stores the new focus state and broadcasts a state change event. + */ + void GetFocus (void); + + /** Called by the corresponding ToolbarMenu when it loses the focus. + Stores the new focus state and broadcasts a state change event. + */ + void LoseFocus (void); + + + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + using cppu::WeakComponentImplHelper5<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection>::addEventListener; + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + using cppu::WeakComponentImplHelper5<com::sun::star::accessibility::XAccessible, com::sun::star::accessibility::XAccessibleEventBroadcaster, com::sun::star::accessibility::XAccessibleContext, com::sun::star::accessibility::XAccessibleComponent, com::sun::star::accessibility::XAccessibleSelection>::removeEventListener; + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleSelection + virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL clearAccessibleSelection( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL selectAllAccessibleChildren( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + +private: + EventListenerVector mxEventListeners; + ToolbarMenu_Impl* mpParent; + /// The current FOCUSED state. + bool mbIsFocused; + + /** Tell all listeners that the object is dying. This callback is + usually called from the WeakComponentImplHelper class. + */ + virtual void SAL_CALL disposing (void); + + /** Check whether or not the object has been disposed (or is in the + state of beeing disposed). If that is the case then + DisposedException is thrown to inform the (indirect) caller of the + foul deed. + */ + void ThrowIfDisposed (void) throw (::com::sun::star::lang::DisposedException); +}; + +// ----------------------- +// - ToolbarMenuEntryAcc - +// ----------------------- + +typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent > ToolbarMenuEntryAccBase; + +class ToolbarMenuEntryAcc : public ::comphelper::OBaseMutex, + public ToolbarMenuEntryAccBase +{ +public: + ToolbarMenuEntryAcc( ToolbarMenuEntry* pParent ); + ~ToolbarMenuEntryAcc(); + + void FireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool HasAccessibleListeners() const { return( mxEventListeners.size() > 0 ); } + + // XAccessible + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + using ToolbarMenuEntryAccBase::addEventListener; + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + using ToolbarMenuEntryAccBase::removeEventListener; + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getAccessibleRole( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleDescription( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground( ) throw (::com::sun::star::uno::RuntimeException); + +private: + EventListenerVector mxEventListeners; + ::vos::OMutex maMutex; + ToolbarMenuEntry* mpParent; + + /** Tell all listeners that the object is dying. This callback is + usually called from the WeakComponentImplHelper class. + */ + virtual void SAL_CALL disposing (void); +}; + +// ----------------------------------------------------------------------------- + +struct ToolbarMenu_Impl +{ + ToolbarMenu& mrMenu; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > mxFrame; + rtl::Reference< svt::FrameStatusListener > mxStatusListener; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceManager; + rtl::Reference< ToolbarMenuAcc > mxAccessible; + ToolbarMenuEntryVector maEntryVector; + + int mnCheckPos; + int mnImagePos; + int mnTextPos; + + int mnHighlightedEntry; + int mnSelectedEntry; + int mnLastColumn; + + Size maSize; + + Link maSelectHdl; + + ToolbarMenu_Impl( ToolbarMenu& rMenu, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame ); + ~ToolbarMenu_Impl(); + + void setAccessible( ToolbarMenuAcc* pAccessible ); + + void fireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue ); + bool hasAccessibleListeners(); + + sal_Int32 getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessibleChild( sal_Int32 index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + void selectAccessibleChild( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + sal_Bool isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + void clearAccessibleSelection(); +}; + +} diff --git a/svtools/source/control/valueimp.hxx b/svtools/source/control/valueimp.hxx index f74cdf00a4db..abde4a015ab8 100644 --- a/svtools/source/control/valueimp.hxx +++ b/svtools/source/control/valueimp.hxx @@ -111,6 +111,7 @@ struct ValueSet_Impl { ::std::auto_ptr< ValueItemList > mpItemList; bool mbIsTransientChildrenDisabled; + Link maHighlightHdl; ValueSet_Impl() : mpItemList( ::std::auto_ptr< ValueItemList >( new ValueItemList() ) ), mbIsTransientChildrenDisabled( false ) diff --git a/svtools/source/control/valueset.cxx b/svtools/source/control/valueset.cxx index bb48c11c7c0b..92c51bd6640e 100644 --- a/svtools/source/control/valueset.cxx +++ b/svtools/source/control/valueset.cxx @@ -1418,7 +1418,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) { USHORT nLastItem = (USHORT)mpImpl->mpItemList->Count(); USHORT nItemPos = VALUESET_ITEM_NOTFOUND; - USHORT nCurPos; + USHORT nCurPos = VALUESET_ITEM_NONEITEM; USHORT nCalcPos; if ( !nLastItem || !ImplGetFirstItem() ) @@ -1431,8 +1431,6 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) if ( mnSelItemId ) nCurPos = GetItemPos( mnSelItemId ); - else - nCurPos = VALUESET_ITEM_NONEITEM; nCalcPos = nCurPos; //switch off selection mode if key travelling is used @@ -1528,6 +1526,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) nCalcPos - ( nLineCount * mnCols )); else { +#if 0 if( (KEY_UP == rKEvt.GetKeyCode().GetCode() ) && (GetStyle() & WB_MENUSTYLEVALUESET) ) { Window* pParent = GetParent(); @@ -1536,6 +1535,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) break; } else +#endif { if ( mpNoneItem ) { @@ -1580,6 +1580,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) nCalcPos + ( nLineCount * mnCols )); else { +#if 0 if( (KEY_DOWN == rKEvt.GetKeyCode().GetCode() ) && (GetStyle() & WB_MENUSTYLEVALUESET) ) { Window* pParent = GetParent(); @@ -1588,6 +1589,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) break; } else +#endif { if ( mpNoneItem ) { @@ -1620,7 +1622,6 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) bDefault = TRUE; break; } - if(!bDefault) EndSelection(); if ( nItemPos != VALUESET_ITEM_NOTFOUND ) @@ -1630,6 +1631,7 @@ void ValueSet::KeyInput( const KeyEvent& rKEvt ) nItemId = GetItemId( nItemPos ); else nItemId = 0; + if ( nItemId != mnSelItemId ) { SelectItem( nItemId ); @@ -2277,6 +2279,8 @@ void ValueSet::SelectItem( USHORT nItemId ) // selection event ::com::sun::star::uno::Any aOldAny, aNewAny; ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny ); + + mpImpl->maHighlightHdl.Call(this); } } } @@ -2749,3 +2753,19 @@ bool ValueSet::IsRTLActive (void) return Application::GetSettings().GetLayoutRTL() && IsRTLEnabled(); } +// ----------------------------------------------------------------------- + +void ValueSet::SetHighlightHdl( const Link& rLink ) +{ + mpImpl->maHighlightHdl = rLink; +} + +// ----------------------------------------------------------------------- + +const Link& ValueSet::GetHighlightHdl() const +{ + return mpImpl->maHighlightHdl; +} + +// ----------------------------------------------------------------------- + diff --git a/svtools/source/uno/makefile.mk b/svtools/source/uno/makefile.mk index 7bfe37624947..665301e9112d 100644 --- a/svtools/source/uno/makefile.mk +++ b/svtools/source/uno/makefile.mk @@ -55,7 +55,9 @@ SLOFILES= \ $(SLO)$/unoevent.obj \ $(SLO)$/unoiface.obj \ $(SLO)$/unoimap.obj \ - $(SLO)$/svtxgridcontrol.obj + $(SLO)$/svtxgridcontrol.obj \ + $(SLO)$/popupwindowcontroller.obj \ + $(SLO)$/popupmenucontrollerbase.obj # --- Targets ------------------------------------------------------ diff --git a/svtools/source/uno/popupmenucontrollerbase.cxx b/svtools/source/uno/popupmenucontrollerbase.cxx new file mode 100644 index 000000000000..ac75a1b9a24b --- /dev/null +++ b/svtools/source/uno/popupmenucontrollerbase.cxx @@ -0,0 +1,420 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include "svtools/popupmenucontrollerbase.hxx" + + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/awt/MenuItemStyle.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/awt/XMenuExtended.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#ifndef _VCL_MENU_HXX_ +#include <vcl/menu.hxx> +#endif +#include <vcl/svapp.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/logfile.hxx> +#include <vos/mutex.hxx> + +//_________________________________________________________________________________________________________________ +// Defines +//_________________________________________________________________________________________________________________ +// + +using ::rtl::OUString; + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::frame; +using namespace com::sun::star::beans; +using namespace com::sun::star::util; + +namespace svt +{ + +struct PopupMenuControllerBaseDispatchInfo +{ + Reference< XDispatch > mxDispatch; + const URL maURL; + const Sequence< PropertyValue > maArgs; + + PopupMenuControllerBaseDispatchInfo( const Reference< XDispatch >& xDispatch, const URL& rURL, const Sequence< PropertyValue >& rArgs ) + : mxDispatch( xDispatch ), maURL( rURL ), maArgs( rArgs ) {} +}; + +PopupMenuControllerBase::PopupMenuControllerBase( const Reference< XMultiServiceFactory >& xServiceManager ) : + ::comphelper::OBaseMutex(), + PopupMenuControllerBaseType(m_aMutex), + m_bInitialized( false ), + m_xServiceManager( xServiceManager ) +{ + if ( m_xServiceManager.is() ) + m_xURLTransformer.set( m_xServiceManager->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer"))),UNO_QUERY ); +} + +PopupMenuControllerBase::~PopupMenuControllerBase() +{ +} + +// protected function +void PopupMenuControllerBase::throwIfDisposed() throw ( RuntimeException ) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + throw com::sun::star::lang::DisposedException(); +} + +// protected function +void PopupMenuControllerBase::resetPopupMenu( com::sun::star::uno::Reference< com::sun::star::awt::XPopupMenu >& rPopupMenu ) +{ + VCLXPopupMenu* pPopupMenu = 0; + if ( rPopupMenu.is() && rPopupMenu->getItemCount() > 0 ) + { + pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu ); + if ( pPopupMenu ) + { + vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); + + PopupMenu* pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu(); + pVCLPopupMenu->Clear(); + } + } +} + +void SAL_CALL PopupMenuControllerBase::disposing() +{ + // Reset our members and set disposed flag + osl::MutexGuard aLock( m_aMutex ); + m_xFrame.clear(); + m_xDispatch.clear(); + m_xPopupMenu.clear(); + m_xServiceManager.clear(); +} + +// XServiceInfo + +sal_Bool SAL_CALL PopupMenuControllerBase::supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException) +{ + const Sequence< rtl::OUString > aSNL( getSupportedServiceNames() ); + const rtl::OUString * pArray = aSNL.getConstArray(); + + for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return true; + + return false; +} + +// XEventListener +void SAL_CALL PopupMenuControllerBase::disposing( const EventObject& ) throw ( RuntimeException ) +{ + osl::MutexGuard aLock( m_aMutex ); + m_xFrame.clear(); + m_xDispatch.clear(); + m_xPopupMenu.clear(); +} + +// XMenuListener +void SAL_CALL PopupMenuControllerBase::highlight( const awt::MenuEvent& ) throw (RuntimeException) +{ +} + +void PopupMenuControllerBase::impl_select(const Reference< XDispatch >& _xDispatch,const URL& aURL) +{ + Sequence<PropertyValue> aArgs; + OSL_ENSURE(_xDispatch.is(),"PopupMenuControllerBase::impl_select: No dispatch"); + if ( _xDispatch.is() ) + _xDispatch->dispatch( aURL, aArgs ); +} + +void SAL_CALL PopupMenuControllerBase::select( const awt::MenuEvent& rEvent ) throw (RuntimeException) +{ + throwIfDisposed(); + + osl::MutexGuard aLock( m_aMutex ); + + Reference< awt::XMenuExtended > xExtMenu( m_xPopupMenu, UNO_QUERY ); + if( xExtMenu.is() ) + { + Sequence<PropertyValue> aArgs; + dispatchCommand( xExtMenu->getCommand( rEvent.MenuId ), aArgs ); + } +} + +void PopupMenuControllerBase::dispatchCommand( const ::rtl::OUString& sCommandURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) +{ + osl::MutexGuard aLock( m_aMutex ); + + throwIfDisposed(); + + try + { + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW ); + URL aURL; + aURL.Complete = sCommandURL; + m_xURLTransformer->parseStrict( aURL ); + + Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, OUString(), 0 ), UNO_QUERY_THROW ); + + Application::PostUserEvent( STATIC_LINK(0, PopupMenuControllerBase, ExecuteHdl_Impl), new PopupMenuControllerBaseDispatchInfo( xDispatch, aURL, rArgs ) ); + + } + catch( Exception& ) + { + } + +} + +IMPL_STATIC_LINK_NOINSTANCE( PopupMenuControllerBase, ExecuteHdl_Impl, PopupMenuControllerBaseDispatchInfo*, pDispatchInfo ) +{ + pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs ); + delete pDispatchInfo; + return 0; +} + +void SAL_CALL PopupMenuControllerBase::activate( const awt::MenuEvent& ) throw (RuntimeException) +{ +} + +void SAL_CALL PopupMenuControllerBase::deactivate( const awt::MenuEvent& ) throw (RuntimeException) +{ +} + +void SAL_CALL PopupMenuControllerBase::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException ) +{ + osl::ClearableMutexGuard aLock( m_aMutex ); + throwIfDisposed(); + aLock.clear(); + + updateCommand( m_aCommandURL ); +} + +void SAL_CALL PopupMenuControllerBase::updateCommand( const rtl::OUString& rCommandURL ) +{ + osl::ClearableMutexGuard aLock( m_aMutex ); + Reference< XStatusListener > xStatusListener( static_cast< OWeakObject* >( this ), UNO_QUERY ); + Reference< XDispatch > xDispatch( m_xDispatch ); + URL aTargetURL; + aTargetURL.Complete = rCommandURL; + m_xURLTransformer->parseStrict( aTargetURL ); + aLock.clear(); + + // Add/remove status listener to get a status update once + if ( xDispatch.is() ) + { + xDispatch->addStatusListener( xStatusListener, aTargetURL ); + xDispatch->removeStatusListener( xStatusListener, aTargetURL ); + } +} + + +// XDispatchProvider +Reference< XDispatch > SAL_CALL +PopupMenuControllerBase::queryDispatch( + const URL& /*aURL*/, + const rtl::OUString& /*sTarget*/, + sal_Int32 /*nFlags*/ ) +throw( RuntimeException ) +{ + // must be implemented by subclass + osl::MutexGuard aLock( m_aMutex ); + throwIfDisposed(); + + return Reference< XDispatch >(); +} + +Sequence< Reference< XDispatch > > SAL_CALL PopupMenuControllerBase::queryDispatches( const Sequence< DispatchDescriptor >& lDescriptor ) throw( RuntimeException ) +{ + // Create return list - which must have same size then the given descriptor + // It's not allowed to pack it! + osl::ClearableMutexGuard aLock( m_aMutex ); + throwIfDisposed(); + aLock.clear(); + + sal_Int32 nCount = lDescriptor.getLength(); + uno::Sequence< uno::Reference< frame::XDispatch > > lDispatcher( nCount ); + + // Step over all descriptors and try to get any dispatcher for it. + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = queryDispatch( lDescriptor[i].FeatureURL , + lDescriptor[i].FrameName , + lDescriptor[i].SearchFlags ); + } + + return lDispatcher; +} + +// XDispatch +void SAL_CALL +PopupMenuControllerBase::dispatch( + const URL& /*aURL*/, + const Sequence< PropertyValue >& /*seqProperties*/ ) +throw( ::com::sun::star::uno::RuntimeException ) +{ + // must be implemented by subclass + osl::MutexGuard aLock( m_aMutex ); + throwIfDisposed(); +} + +void SAL_CALL +PopupMenuControllerBase::addStatusListener( + const Reference< XStatusListener >& xControl, + const URL& aURL ) +throw( ::com::sun::star::uno::RuntimeException ) +{ + osl::ResettableMutexGuard aLock( m_aMutex ); + throwIfDisposed(); + aLock.clear(); + + bool bStatusUpdate( false ); + rBHelper.addListener( ::getCppuType( &xControl ), xControl ); + + aLock.reset(); + if ( aURL.Complete.indexOf( m_aBaseURL ) == 0 ) + bStatusUpdate = true; + aLock.clear(); + + if ( bStatusUpdate ) + { + // Dummy update for popup menu controllers + FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.IsEnabled = sal_True; + aEvent.Requery = sal_False; + aEvent.State = Any(); + xControl->statusChanged( aEvent ); + } +} + +void SAL_CALL PopupMenuControllerBase::removeStatusListener( + const Reference< XStatusListener >& xControl, + const URL& /*aURL*/ ) +throw( ::com::sun::star::uno::RuntimeException ) +{ + rBHelper.removeListener( ::getCppuType( &xControl ), xControl ); +} + +::rtl::OUString PopupMenuControllerBase::determineBaseURL( const ::rtl::OUString& aURL ) +{ + // Just use the main part of the URL for popup menu controllers + sal_Int32 nQueryPart( 0 ); + sal_Int32 nSchemePart( 0 ); + rtl::OUString aMainURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:" )); + + nSchemePart = aURL.indexOf( ':' ); + if (( nSchemePart > 0 ) && + ( aURL.getLength() > ( nSchemePart+1 ))) + { + nQueryPart = aURL.indexOf( '?', nSchemePart ); + if ( nQueryPart > 0 ) + aMainURL += aURL.copy( nSchemePart, nQueryPart-nSchemePart ); + else if ( nQueryPart == -1 ) + aMainURL += aURL.copy( nSchemePart+1 ); + } + + return aMainURL; +} + +// XInitialization +void SAL_CALL PopupMenuControllerBase::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) +{ + osl::MutexGuard aLock( m_aMutex ); + + sal_Bool bInitalized( m_bInitialized ); + if ( !bInitalized ) + { + PropertyValue aPropValue; + rtl::OUString aCommandURL; + Reference< XFrame > xFrame; + + for ( int i = 0; i < aArguments.getLength(); i++ ) + { + if ( aArguments[i] >>= aPropValue ) + { + if ( aPropValue.Name.equalsAscii( "Frame" )) + aPropValue.Value >>= xFrame; + else if ( aPropValue.Name.equalsAscii( "CommandURL" )) + aPropValue.Value >>= aCommandURL; + } + } + + if ( xFrame.is() && aCommandURL.getLength() ) + { + m_xFrame = xFrame; + m_aCommandURL = aCommandURL; + m_aBaseURL = determineBaseURL( aCommandURL ); + m_bInitialized = true; + } + } +} +// XPopupMenuController +void SAL_CALL PopupMenuControllerBase::setPopupMenu( const Reference< awt::XPopupMenu >& xPopupMenu ) throw ( RuntimeException ) +{ + osl::MutexGuard aLock( m_aMutex ); + throwIfDisposed(); + + if ( m_xFrame.is() && !m_xPopupMenu.is() ) + { + // Create popup menu on demand + vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() ); + + m_xPopupMenu = xPopupMenu; + m_xPopupMenu->addMenuListener( Reference< awt::XMenuListener >( (OWeakObject*)this, UNO_QUERY )); + + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); + + URL aTargetURL; + aTargetURL.Complete = m_aCommandURL; + m_xURLTransformer->parseStrict( aTargetURL ); + m_xDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 ); + + impl_setPopupMenu(); + + updatePopupMenu(); + } +} +void PopupMenuControllerBase::impl_setPopupMenu() +{ +} +} diff --git a/svtools/source/uno/popupwindowcontroller.cxx b/svtools/source/uno/popupwindowcontroller.cxx new file mode 100644 index 000000000000..d431dd7911a8 --- /dev/null +++ b/svtools/source/uno/popupwindowcontroller.cxx @@ -0,0 +1,226 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <toolkit/helper/vclunohelper.hxx> + +#include <vcl/toolbox.hxx> +#include <vcl/svapp.hxx> + +#include "svtools/popupwindowcontroller.hxx" + +using rtl::OUString; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + + +namespace svt +{ + +class PopupWindowControllerImpl +{ +public: + PopupWindowControllerImpl(); + ~PopupWindowControllerImpl(); + + void SetPopupWindow( ::Window* pPopupWindow ); + + DECL_LINK( WindowEventListener, VclSimpleEvent* ); + DECL_STATIC_LINK( PopupWindowControllerImpl, AsyncDeleteWindowHdl, Window* ); + +private: + ::Window* mpPopupWindow; +}; + +PopupWindowControllerImpl::PopupWindowControllerImpl() +: mpPopupWindow( 0 ) +{ +} + +PopupWindowControllerImpl::~PopupWindowControllerImpl() +{ + if( mpPopupWindow ) + SetPopupWindow(0); +} + +void PopupWindowControllerImpl::SetPopupWindow( ::Window* pPopupWindow ) +{ + if( mpPopupWindow ) + { + mpPopupWindow->RemoveEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener ) ); + Application::PostUserEvent( STATIC_LINK( this, PopupWindowControllerImpl, AsyncDeleteWindowHdl ), mpPopupWindow ); + } + mpPopupWindow = pPopupWindow; + if( mpPopupWindow ) + { + mpPopupWindow->AddEventListener( LINK( this, PopupWindowControllerImpl, WindowEventListener )); + } +} + +IMPL_LINK( PopupWindowControllerImpl, WindowEventListener, VclSimpleEvent*, pEvent ) +{ + VclWindowEvent* pWindowEvent = dynamic_cast< VclWindowEvent* >( pEvent ); + if( pWindowEvent ) + { + switch( pWindowEvent->GetId() ) + { + case VCLEVENT_WINDOW_CLOSE: + case VCLEVENT_WINDOW_ENDPOPUPMODE: + SetPopupWindow(0); + break; + } + } + return 1; +} + +//-------------------------------------------------------------------- + +IMPL_STATIC_LINK( PopupWindowControllerImpl, AsyncDeleteWindowHdl, Window*, pWindow ) +{ + (void)*pThis; + delete pWindow; + return 0; +} + +//======================================================================== +// class PopupWindowController +//======================================================================== + +PopupWindowController::PopupWindowController( const Reference< lang::XMultiServiceFactory >& rServiceManager, + const Reference< frame::XFrame >& xFrame, + const OUString& aCommandURL ) +: svt::ToolboxController( rServiceManager, xFrame, aCommandURL ) +, mpImpl( new PopupWindowControllerImpl() ) +{ +} + +PopupWindowController::~PopupWindowController() +{ +} + +// XInterface +Any SAL_CALL PopupWindowController::queryInterface( const Type& aType ) +throw (RuntimeException) +{ + Any a( ToolboxController::queryInterface( aType ) ); + if ( a.hasValue() ) + return a; + + return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this )); +} + +void SAL_CALL PopupWindowController::acquire() throw () +{ + ToolboxController::acquire(); +} + +void SAL_CALL PopupWindowController::release() throw () +{ + ToolboxController::release(); +} + +// XServiceInfo +sal_Bool SAL_CALL PopupWindowController::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + const Sequence< OUString > aSNL( getSupportedServiceNames() ); + const OUString * pArray = aSNL.getConstArray(); + + for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return true; + + return false; +} + +// XInitialization +void SAL_CALL PopupWindowController::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ + svt::ToolboxController::initialize( aArguments ); + if( m_aCommandURL.getLength() ) + addStatusListener( m_aCommandURL ); +} + +// XComponent +void SAL_CALL PopupWindowController::dispose() throw (RuntimeException) +{ + if( m_aCommandURL.getLength() ) + removeStatusListener( m_aCommandURL ); + + svt::ToolboxController::dispose(); +} + + +// XStatusListener +void SAL_CALL PopupWindowController::statusChanged( const frame::FeatureStateEvent& rEvent ) throw ( RuntimeException ) +{ + svt::ToolboxController::statusChanged(rEvent); + enable( rEvent.IsEnabled ); +} + +// XToolbarController +void SAL_CALL PopupWindowController::execute( sal_Int16 KeyModifier ) throw (RuntimeException) +{ + svt::ToolboxController::execute( KeyModifier ); +} + +void SAL_CALL PopupWindowController::click() throw (RuntimeException) +{ + svt::ToolboxController::click(); +} + +void SAL_CALL PopupWindowController::doubleClick() throw (RuntimeException) +{ + svt::ToolboxController::doubleClick(); +} + +Reference< awt::XWindow > SAL_CALL PopupWindowController::createPopupWindow() throw (RuntimeException) +{ + ToolBox* pToolBox = dynamic_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); + if( pToolBox ) + { + ::Window* pWin = createPopupWindow(pToolBox); + if( pWin ) + { + pWin->EnableDocking(true); + mpImpl->SetPopupWindow(pWin); + ::Window::GetDockingManager()->StartPopupMode( pToolBox, pWin, FLOATWIN_POPUPMODE_NOFOCUSCLOSE|FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE |FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE ); + } + } + return Reference< awt::XWindow >(); +} + +Reference< awt::XWindow > SAL_CALL PopupWindowController::createItemWindow( const Reference< awt::XWindow >& /*Parent*/ ) + throw (RuntimeException) +{ + return Reference< awt::XWindow >(); +} + +} + diff --git a/svtools/source/uno/toolboxcontroller.cxx b/svtools/source/uno/toolboxcontroller.cxx index 3f0b4e7c0ee6..d9b84aa2e356 100644 --- a/svtools/source/uno/toolboxcontroller.cxx +++ b/svtools/source/uno/toolboxcontroller.cxx @@ -43,6 +43,8 @@ #endif #include <vcl/toolbox.hxx> +using ::rtl::OUString; + using namespace ::cppu; using namespace ::com::sun::star::awt; using namespace ::com::sun::star::uno; @@ -54,10 +56,29 @@ using namespace ::com::sun::star::frame; namespace svt { + +struct DispatchInfo +{ + Reference< XDispatch > mxDispatch; + const URL maURL; + const Sequence< PropertyValue > maArgs; + + DispatchInfo( const Reference< XDispatch >& xDispatch, const URL& rURL, const Sequence< PropertyValue >& rArgs ) + : mxDispatch( xDispatch ), maURL( rURL ), maArgs( rArgs ) {} +}; + struct ToolboxController_Impl { ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > m_xParentWindow; ::com::sun::star::uno::Reference< ::com::sun::star::util::XURLTransformer > m_xUrlTransformer; + rtl::OUString m_sModuleName; + sal_uInt16 m_nToolBoxId; + + DECL_STATIC_LINK( ToolboxController_Impl, ExecuteHdl_Impl, DispatchInfo* ); + + ToolboxController_Impl() + : m_nToolBoxId( SAL_MAX_UINT16 ) + {} }; ToolboxController::ToolboxController( @@ -166,11 +187,6 @@ void SAL_CALL ToolboxController::release() throw () void SAL_CALL ToolboxController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException ) { - const rtl::OUString aFrameName( RTL_CONSTASCII_USTRINGPARAM( "Frame" )); - const rtl::OUString aCommandURLName( RTL_CONSTASCII_USTRINGPARAM( "CommandURL" )); - const rtl::OUString aServiceManagerName( RTL_CONSTASCII_USTRINGPARAM( "ServiceManager" )); - const rtl::OUString aParentWindow( RTL_CONSTASCII_USTRINGPARAM( "ParentWindow" )); - bool bInitialized( true ); { @@ -192,14 +208,16 @@ throw ( Exception, RuntimeException ) { if ( aArguments[i] >>= aPropValue ) { - if ( aPropValue.Name.equalsAscii( "Frame" )) + if ( aPropValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Frame") )) m_xFrame.set(aPropValue.Value,UNO_QUERY); - else if ( aPropValue.Name.equalsAscii( "CommandURL" )) + else if ( aPropValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CommandURL") )) aPropValue.Value >>= m_aCommandURL; - else if ( aPropValue.Name.equalsAscii( "ServiceManager" )) + else if ( aPropValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ServiceManager") )) m_xServiceManager.set(aPropValue.Value,UNO_QUERY); - else if ( aPropValue.Name.equalsAscii( "ParentWindow" )) + else if ( aPropValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ParentWindow") )) m_pImpl->m_xParentWindow.set(aPropValue.Value,UNO_QUERY); + else if ( aPropValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ModuleName" ) ) ) + aPropValue.Value >>= m_pImpl->m_sModuleName; } } @@ -704,4 +722,77 @@ Reference< ::com::sun::star::awt::XWindow > ToolboxController::getParent() const { return m_pImpl->m_xParentWindow; } + +const rtl::OUString& ToolboxController::getModuleName() const +{ + return m_pImpl->m_sModuleName; +} + +void ToolboxController::dispatchCommand( const OUString& sCommandURL, const Sequence< PropertyValue >& rArgs ) +{ + try + { + Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY_THROW ); + URL aURL; + aURL.Complete = sCommandURL; + getURLTransformer()->parseStrict( aURL ); + + Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( aURL, OUString(), 0 ), UNO_QUERY_THROW ); + + Application::PostUserEvent( STATIC_LINK(0, ToolboxController_Impl, ExecuteHdl_Impl), new DispatchInfo( xDispatch, aURL, rArgs ) ); + + } + catch( Exception& ) + { + } +} + +//-------------------------------------------------------------------- + +IMPL_STATIC_LINK_NOINSTANCE( ToolboxController_Impl, ExecuteHdl_Impl, DispatchInfo*, pDispatchInfo ) +{ + pDispatchInfo->mxDispatch->dispatch( pDispatchInfo->maURL, pDispatchInfo->maArgs ); + delete pDispatchInfo; + return 0; +} + +void ToolboxController::enable( bool bEnable ) +{ + ToolBox* pToolBox = 0; + sal_uInt16 nItemId = 0; + if( getToolboxId( nItemId, &pToolBox ) ) + { + pToolBox->EnableItem( nItemId, bEnable ? TRUE : FALSE ); + } +} + +bool ToolboxController::getToolboxId( sal_uInt16& rItemId, ToolBox** ppToolBox ) +{ + if( (m_pImpl->m_nToolBoxId != SAL_MAX_UINT16) && (ppToolBox == 0) ) + return m_pImpl->m_nToolBoxId; + + ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) ); + + if( (m_pImpl->m_nToolBoxId == SAL_MAX_UINT16) && pToolBox ) + { + const sal_uInt16 nCount = pToolBox->GetItemCount(); + for ( sal_uInt16 nPos = 0; nPos < nCount; ++nPos ) + { + const sal_uInt16 nItemId = pToolBox->GetItemId( nPos ); + if ( pToolBox->GetItemCommand( nItemId ) == String( m_aCommandURL ) ) + { + m_pImpl->m_nToolBoxId = nItemId; + break; + } + } + } + + if( ppToolBox ) + *ppToolBox = pToolBox; + + rItemId = m_pImpl->m_nToolBoxId; + + return (rItemId != SAL_MAX_UINT16) && (( ppToolBox == 0) || (*ppToolBox != 0) ); +} + } // svt |