/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the 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/AccessibleStateType.hpp>
#include <comphelper/processfactory.hxx>

#include <vcl/dockwin.hxx>
#include <vcl/decoview.hxx>
#include <vcl/image.hxx>
#include <vcl/taskpanelist.hxx>
#include <vcl/toolbox.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( sal_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();
}

// --------------------------------------------------------------------
	
Reference< XAccessible > ToolbarMenu_Impl::getAccessibleChild( Control* pControl, sal_Int32 childIndex ) throw (IndexOutOfBoundsException, RuntimeException)
{
	const int nEntryCount = maEntryVector.size();
	for( int nEntry = 0; nEntry < nEntryCount; nEntry++ )
	{
		ToolbarMenuEntry* pEntry = maEntryVector[nEntry];
		if( pEntry && (pEntry->mpControl == pControl) )
		{
			return pEntry->getAccessibleChild( childIndex );
		}
	}

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


// --------------------------------------------------------------------

void ToolbarMenu_Impl::notifyHighlightedEntry()
{
	if( hasAccessibleListeners() )
	{
		ToolbarMenuEntry* pEntry = implGetEntry( mnHighlightedEntry );
		if( pEntry && pEntry->mbEnabled && (pEntry->mnEntryId != TITLE_ID) )
		{
			Any aNew;
			Any aOld( mxOldSelection );
			if( pEntry->mpControl )
			{
				sal_Int32 nChildIndex = 0;
				// todo: if other controls than ValueSet are allowed, addapt this code
				ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
				if( pValueSet )
					nChildIndex = static_cast< sal_Int32 >( pValueSet->GetItemPos( pValueSet->GetSelectItemId() ) );

				if( nChildIndex >= pEntry->getAccessibleChildCount() )
					return;

				aNew <<= getAccessibleChild( pEntry->mpControl, nChildIndex );
			}
			else
			{
				aNew <<= pEntry->GetAccessible(true);
			}

			fireAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOld, aNew );
			fireAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, aOld, aNew );
			fireAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), Any( AccessibleStateType::FOCUSED ) );
			aNew >>= mxOldSelection;
		}
	}
}

// --------------------------------------------------------------------

ToolbarMenuEntry* ToolbarMenu_Impl::implGetEntry( int nEntry ) const
{
	if( (nEntry < 0) || (nEntry >= (int)maEntryVector.size() ) )
		return NULL;

	return maEntryVector[nEntry];
}


// --------------------------------------------------------------------

IMPL_LINK( ToolbarMenu, HighlightHdl, Control *, pControl )
{
	(void)pControl;
	mpImpl->notifyHighlightedEntry();
	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 );

    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	SetControlBackground( rStyleSettings.GetMenuColor() );

    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();

	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::highlightFirstEntry()
{
	implChangeHighlightEntry( 0 );
}

// --------------------------------------------------------------------

void ToolbarMenu::GetFocus()
{
	if( mpImpl->mnHighlightedEntry == -1 )
		implChangeHighlightEntry( 0 );

	DockingWindow::GetFocus();
}

// --------------------------------------------------------------------

void ToolbarMenu::LoseFocus()
{
	if( mpImpl->mnHighlightedEntry != -1 )
		implChangeHighlightEntry( -1 );

	DockingWindow::LoseFocus();
}

// --------------------------------------------------------------------

void ToolbarMenu::appendEntry( int nEntryId, const String& rStr, MenuItemBits nItemBits )
{
	appendEntry( new ToolbarMenuEntry( *this, nEntryId, rStr, nItemBits ) );
}

// --------------------------------------------------------------------

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( sal_False );
	pSet->SetColor( GetControlBackground() );
	pSet->SetHighlightHdl( LINK( this, ToolbarMenu, HighlightHdl ) );
	return pSet;
}

// --------------------------------------------------------------------

ToolbarMenuEntry* ToolbarMenu::implGetEntry( int nEntry ) const
{
	return mpImpl->implGetEntry( 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 )
			{
				if( !bHighlight )
				{
					ValueSet* pValueSet = dynamic_cast< ValueSet* >( pEntry->mpControl );
					if( pValueSet )
					{
						pValueSet->SetNoSelection();
					}
				}
				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,
                                   aCtrlRect,
                                   CTRL_STATE_ENABLED,
                                   ImplControlValue(),
                                   OUString() );
                if( bHighlight && IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) )
                {
                    bDrawItemRect = false;
                    if( sal_False == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM,
                                                    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 = sal_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 );
    }

	mpImpl->notifyHighlightedEntry();
}

// --------------------------------------------------------------------

static bool implCheckSubControlCursorMove( Control* pControl, bool bUp, int& nLastColumn )
{
	ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
	if( pValueSet )
	{
		sal_uInt16 nItemPos = pValueSet->GetItemPos( pValueSet->GetSelectItemId() );
		if( nItemPos != VALUESET_ITEM_NOTFOUND )
		{
			const sal_uInt16 nColCount = pValueSet->GetColCount();
			const sal_uInt16 nLine = nItemPos / nColCount;

			nLastColumn = nItemPos - (nLine * nColCount);
	
			if( bUp )
			{
				return nLine > 0;
			}
			else
			{
				const sal_uInt16 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;
}

// --------------------------------------------------------------------

void ToolbarMenu_Impl::implHighlightControl( sal_uInt16 nCode, Control* pControl )
{
	ValueSet* pValueSet = dynamic_cast< ValueSet* >( pControl );
	if( pValueSet )
	{
		const sal_uInt16 nItemCount = pValueSet->GetItemCount();
		sal_uInt16 nItemPos = VALUESET_ITEM_NOTFOUND;
		switch( nCode )
		{
        case KEY_UP:
		{
			const sal_uInt16 nColCount = pValueSet->GetColCount();
			const sal_uInt16 nLastLine = nItemCount / nColCount;
			nItemPos = std::min( ((nLastLine-1) * nColCount) + mnLastColumn, nItemCount-1 );
			break;
		}
        case KEY_DOWN:
			nItemPos = std::min( mnLastColumn, nItemCount-1 );
			break;
        case KEY_END:
			nItemPos = nItemCount -1;
			break;
        case KEY_HOME:
			nItemPos = 0;
			break;
		}
		pValueSet->SelectItem( pValueSet->GetItemId( nItemPos ) );
		notifyHighlightedEntry();
	}
}

// --------------------------------------------------------------------

void ToolbarMenu::KeyInput( const KeyEvent& rKEvent )
{
	Control* pForwardControl = 0;
    sal_uInt16 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 )
				{
					mpImpl->implHighlightControl( nCode, p->mpControl );
				}
				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 )
			{
				mpImpl->implHighlightControl( nCode, p->mpControl );
			}
		}
		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 )
{
    sal_Bool bNativeOk = sal_False;
    if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
    {
        ImplControlValue    aControlValue;
        ControlState        nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED;
        
        aControlValue.setTristateVal( BUTTONVALUE_ON );
        
        bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, 
                                                  i_rRect, 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, sal_True, sal_False, 2, NULL, &aColor );
    }
}

static long ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth )
{
    rMaxWidth = rCheckHeight = rRadioHeight = 0;
    
    ImplControlValue aVal;
    Rectangle aNativeBounds;
    Rectangle aNativeContent;
    Point tmp( 0, 0 );
    Rectangle aCtrlRegion( 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.GetHeight();
			rMaxWidth = aNativeContent.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.GetHeight();
			rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth());
        }
    }
    return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight;
}

void ToolbarMenu::implPaint( ToolbarMenuEntry* pThisOnly, bool bHighlighted )
{
	sal_uInt16 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();
	const bool bUseImages = rSettings.GetUseImagesInMenus();

	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);

				sal_uInt16  nTextStyle   = 0;
				sal_uInt16  nSymbolStyle = 0;
				sal_uInt16  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, 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 && bUseImages )
				{
					// 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;
					sal_uInt16 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;
}

// --------------------------------------------------------------------


// --------------------------------------------------------------------

}