/**************************************************************
 * 
 * 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_vcl.hxx"

#include "tools/rc.h"
#include "tools/debug.hxx"


#include "vcl/decoview.hxx"
#include "vcl/event.hxx"
#include "vcl/scrbar.hxx"
#include "vcl/button.hxx"
#include "vcl/edit.hxx"
#include "vcl/lstbox.hxx"
#include "vcl/combobox.hxx"

#include "svdata.hxx"
#include "controldata.hxx"
#include "subedit.hxx"
#include "ilstbox.hxx"
#include "dndevdis.hxx"

#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>

// =======================================================================

ListBox::ListBox( WindowType nType ) : Control( nType )
{
	ImplInitListBoxData();
}

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

ListBox::ListBox( Window* pParent, WinBits nStyle ) : Control( WINDOW_LISTBOX )
{
	ImplInitListBoxData();
	ImplInit( pParent, nStyle );
}

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

ListBox::ListBox( Window* pParent, const ResId& rResId ) :
	Control( WINDOW_LISTBOX )
{
	ImplInitListBoxData();
	rResId.SetRT( RSC_LISTBOX );
	WinBits nStyle = ImplInitRes( rResId );
	ImplInit( pParent, nStyle );
	ImplLoadRes( rResId );

	if ( !(nStyle & WB_HIDE ) )
		Show();
}

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

ListBox::~ListBox()
{
    //#109201#
    ImplCallEventListeners( VCLEVENT_OBJECT_DYING );

    delete mpImplLB;

	// Beim zerstoeren des FloatWins macht TH ein GrabFocus auf den Parent,
	// also diese ListBox => PreNotify()...
	mpImplLB = NULL;

	delete mpFloatWin;
	delete mpImplWin;
	delete mpBtn;
}

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

void ListBox::ImplInitListBoxData()
{
	mpFloatWin		= NULL;
	mpImplWin		= NULL;
	mpBtn			= NULL;
	mnDDHeight		= 0;
	mnSaveValue 	= LISTBOX_ENTRY_NOTFOUND;
    mnLineCount     = 0;
	mbDDAutoSize	= true;
    mbEdgeBlending  = false;
}

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

void ListBox::ImplInit( Window* pParent, WinBits nStyle )
{
	nStyle = ImplInitStyle( nStyle );
	if ( !(nStyle & WB_NOBORDER) && ( nStyle & WB_DROPDOWN ) )
		nStyle |= WB_BORDER;

	Control::ImplInit( pParent, nStyle, NULL );
	SetBackground();

    ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener> xDrop = new DNDEventDispatcher(this);

	if( nStyle & WB_DROPDOWN )
	{
        sal_Int32 nLeft, nTop, nRight, nBottom;
        GetBorder( nLeft, nTop, nRight, nBottom );
        mnDDHeight = (sal_uInt16)(GetTextHeight() + nTop + nBottom + 4);

        if( IsNativeWidgetEnabled() &&
            IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
        {
                ImplControlValue aControlValue;
                Rectangle aCtrlRegion( Point( 0, 0 ), Size( 20, mnDDHeight ) );
                Rectangle aBoundingRgn( aCtrlRegion );
                Rectangle aContentRgn( aCtrlRegion );
                if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
                                            CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
                                            aBoundingRgn, aContentRgn ) )
                {
                    sal_Int32 nHeight = aBoundingRgn.GetHeight();
                    if( nHeight > mnDDHeight )
                        mnDDHeight = static_cast<sal_uInt16>(nHeight);
                }
        }

		mpFloatWin = new ImplListBoxFloatingWindow( this );
		mpFloatWin->SetAutoWidth( sal_True );
		mpFloatWin->SetPopupModeEndHdl( LINK( this, ListBox, ImplPopupModeEndHdl ) );
        mpFloatWin->GetDropTarget()->addDropTargetListener(xDrop);

		mpImplWin = new ImplWin( this, (nStyle & (WB_LEFT|WB_RIGHT|WB_CENTER))|WB_NOBORDER );
		mpImplWin->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
		mpImplWin->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
		mpImplWin->Show();
        mpImplWin->GetDropTarget()->addDropTargetListener(xDrop);
        mpImplWin->SetEdgeBlending(GetEdgeBlending());

		mpBtn = new ImplBtn( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
		ImplInitDropDownButton( mpBtn );
		mpBtn->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
		mpBtn->Show();
        mpBtn->GetDropTarget()->addDropTargetListener(xDrop);
	}

	Window* pLBParent = this;
	if ( mpFloatWin )
		pLBParent = mpFloatWin;
	mpImplLB = new ImplListBox( pLBParent, nStyle&(~WB_BORDER) );
	mpImplLB->SetSelectHdl( LINK( this, ListBox, ImplSelectHdl ) );
	mpImplLB->SetScrollHdl( LINK( this, ListBox, ImplScrollHdl ) );
	mpImplLB->SetCancelHdl( LINK( this, ListBox, ImplCancelHdl ) );
	mpImplLB->SetDoubleClickHdl( LINK( this, ListBox, ImplDoubleClickHdl ) );
	mpImplLB->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
	mpImplLB->SetFocusHdl( LINK( this, ListBox, ImplFocusHdl ) );
	mpImplLB->SetListItemSelectHdl( LINK( this, ListBox, ImplListItemSelectHdl ) );
	mpImplLB->SetPosPixel( Point() );
    mpImplLB->SetEdgeBlending(GetEdgeBlending());
	mpImplLB->Show();
    
    mpImplLB->GetDropTarget()->addDropTargetListener(xDrop);
    mpImplLB->SetDropTraget(xDrop);

	if ( mpFloatWin )
	{
		mpFloatWin->SetImplListBox( mpImplLB );
		mpImplLB->SetSelectionChangedHdl( LINK( this, ListBox, ImplSelectionChangedHdl ) );
	}
	else
		mpImplLB->GetMainWindow()->AllowGrabFocus( sal_True );

	SetCompoundControl( sal_True );
}

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

WinBits ListBox::ImplInitStyle( WinBits nStyle )
{
	if ( !(nStyle & WB_NOTABSTOP) )
		nStyle |= WB_TABSTOP;
	if ( !(nStyle & WB_NOGROUP) )
		nStyle |= WB_GROUP;
	return nStyle;
}

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

void ListBox::ImplLoadRes( const ResId& rResId )
{
	Control::ImplLoadRes( rResId );

	sal_uInt16 nSelPos = ReadShortRes();
	sal_uInt16 nNumber = sal::static_int_cast<sal_uInt16>(ReadLongRes());

	for( sal_uInt16 i = 0; i < nNumber; i++ )
	{
		sal_uInt16 nPos = InsertEntry( ReadStringRes(), LISTBOX_APPEND );

		long nId = ReadLongRes();
		if( nId )
			SetEntryData( nPos, (void *)nId );	// ID als UserData
	}

	if( nSelPos < nNumber )
		SelectEntryPos( nSelPos );
}

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

IMPL_LINK( ListBox, ImplSelectHdl, void*, EMPTYARG )
{
	sal_Bool bPopup = IsInDropDown();
	if( IsDropDownBox() )
	{
		if( !mpImplLB->IsTravelSelect() )
		{
			mpFloatWin->EndPopupMode();
			mpImplWin->GrabFocus();
		}

		mpImplWin->SetItemPos( GetSelectEntryPos() );
		mpImplWin->SetString( GetSelectEntry() );
		if( mpImplLB->GetEntryList()->HasImages() )
		{
			Image aImage = mpImplLB->GetEntryList()->GetEntryImage( GetSelectEntryPos() );
			mpImplWin->SetImage( aImage );
		}
		mpImplWin->Invalidate();
	}

	if ( ( !IsTravelSelect() || mpImplLB->IsSelectionChanged() ) || ( bPopup && !IsMultiSelectionEnabled() ) )
		Select();

	return 1;
}
IMPL_LINK( ListBox, ImplFocusHdl, void *, nPos )
{
    ImplCallEventListeners( VCLEVENT_LISTBOX_FOCUS , nPos);
	return 1;
}
IMPL_LINK( ListBox, ImplListItemSelectHdl, void*, EMPTYARG )
{
    ImplCallEventListeners( VCLEVENT_LISTBOX_SELECT );
	return 1;
}

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

IMPL_LINK( ListBox, ImplScrollHdl, void*, EMPTYARG )
{
    ImplCallEventListeners( VCLEVENT_LISTBOX_SCROLLED );
	return 1;
}

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

IMPL_LINK( ListBox, ImplCancelHdl, void*, EMPTYARG )
{
	if( IsInDropDown() )
		mpFloatWin->EndPopupMode();

	return 1;
}

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

IMPL_LINK( ListBox, ImplSelectionChangedHdl, void*, n )
{
	if ( !mpImplLB->IsTrackingSelect() )
	{
		sal_uInt16 nChanged = (sal_uInt16)(sal_uLong)n;
		const ImplEntryList* pEntryList = mpImplLB->GetEntryList();
		if ( pEntryList->IsEntryPosSelected( nChanged ) )
		{
			// Sollte mal ein ImplPaintEntry werden...
			if ( nChanged < pEntryList->GetMRUCount() )
				nChanged = pEntryList->FindEntry( pEntryList->GetEntryText( nChanged ) );
			mpImplWin->SetItemPos( nChanged );
			mpImplWin->SetString( mpImplLB->GetEntryList()->GetEntryText( nChanged ) );
			if( mpImplLB->GetEntryList()->HasImages() )
			{
				Image aImage = mpImplLB->GetEntryList()->GetEntryImage( nChanged );
				mpImplWin->SetImage( aImage );
			}
		}
		else
		{
			mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
			mpImplWin->SetString( ImplGetSVEmptyStr() );
			Image aImage;
			mpImplWin->SetImage( aImage );
		}
		mpImplWin->Invalidate();
	}
	return 1;
}

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

IMPL_LINK( ListBox, ImplDoubleClickHdl, void*, EMPTYARG )
{
	DoubleClick();
	return 1;
}

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

IMPL_LINK( ListBox, ImplClickBtnHdl, void*, EMPTYARG )
{
	if( !mpFloatWin->IsInPopupMode() )
	{
        ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
		mpImplWin->GrabFocus();
		mpBtn->SetPressed( sal_True );
		mpFloatWin->StartFloat( sal_True );
        ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );

        ImplClearLayoutData();
        if( mpImplLB )
            mpImplLB->GetMainWindow()->ImplClearLayoutData();
        if( mpImplWin )
            mpImplWin->ImplClearLayoutData();
	}

	return 0;
}

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

IMPL_LINK( ListBox, ImplPopupModeEndHdl, void*, EMPTYARG )
{
    if( mpFloatWin->IsPopupModeCanceled() )
    {
        if ( ( mpFloatWin->GetPopupModeStartSaveSelection() != LISTBOX_ENTRY_NOTFOUND )
                && !IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
        {
            mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), sal_True );
            sal_Bool bTravelSelect = mpImplLB->IsTravelSelect();
            mpImplLB->SetTravelSelect( sal_True );

            ImplDelData aCheckDelete;
            ImplAddDel( &aCheckDelete );
            Select();
            if ( aCheckDelete.IsDelete() )
                return 0;
            ImplRemoveDel( &aCheckDelete );

            mpImplLB->SetTravelSelect( bTravelSelect );
        }
    }

    ImplClearLayoutData();
    if( mpImplLB )
        mpImplLB->GetMainWindow()->ImplClearLayoutData();
    if( mpImplWin )
        mpImplWin->ImplClearLayoutData();

    mpBtn->SetPressed( sal_False );
    ImplCallEventListeners( VCLEVENT_DROPDOWN_CLOSE );
	return 0;
}

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

void ListBox::ToggleDropDown()
{
    if( IsDropDownBox() )
    {
        if( mpFloatWin->IsInPopupMode() )
            mpFloatWin->EndPopupMode();
        else
        {
            ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
            mpImplWin->GrabFocus();
            mpBtn->SetPressed( sal_True );
            mpFloatWin->StartFloat( sal_True );
            ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
        }
    }
}

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

void ListBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
{
	mpImplLB->GetMainWindow()->ImplInitSettings( sal_True, sal_True, sal_True );

	Point aPos = pDev->LogicToPixel( rPos );
	Size aSize = pDev->LogicToPixel( rSize );
	Font aFont = mpImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
	OutDevType eOutDevType = pDev->GetOutDevType();

	pDev->Push();
	pDev->SetMapMode();
	pDev->SetFont( aFont );
	pDev->SetTextFillColor();

	// Border/Background
	pDev->SetLineColor();
	pDev->SetFillColor();
	sal_Bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
	sal_Bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
	if ( bBorder || bBackground )
	{
		Rectangle aRect( aPos, aSize );
		if ( bBorder )
		{
            ImplDrawFrame( pDev, aRect );
		}
		if ( bBackground )
		{
			pDev->SetFillColor( GetControlBackground() );
			pDev->DrawRect( aRect );
		}
	}

	// Inhalt
	if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
	{
		pDev->SetTextColor( Color( COL_BLACK ) );
	}
	else
	{
		if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
		{
			const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
			pDev->SetTextColor( rStyleSettings.GetDisableColor() );
		}
		else
		{
			pDev->SetTextColor( GetTextColor() );
		}
	}

	long        nOnePixel = GetDrawPixel( pDev, 1 );
    sal_uInt16      nTextStyle = TEXT_DRAW_VCENTER;
    Rectangle   aTextRect( aPos, aSize );

    if ( GetStyle() & WB_CENTER )
        nTextStyle |= TEXT_DRAW_CENTER;
    else if ( GetStyle() & WB_RIGHT )
        nTextStyle |= TEXT_DRAW_RIGHT;
    else
        nTextStyle |= TEXT_DRAW_LEFT;

    aTextRect.Left() += 3*nOnePixel;
    aTextRect.Right() -= 3*nOnePixel;

    if ( IsDropDownBox() )
	{
		XubString	aText = GetSelectEntry();
		long		nTextHeight = pDev->GetTextHeight();
		long		nTextWidth = pDev->GetTextWidth( aText );
		long		nOffX = 3*nOnePixel;
		long		nOffY = (aSize.Height()-nTextHeight) / 2;

		// Clipping?
		if ( (nOffY < 0) ||
			 ((nOffY+nTextHeight) > aSize.Height()) ||
			 ((nOffX+nTextWidth) > aSize.Width()) )
		{
			Rectangle aClip( aPos, aSize );
			if ( nTextHeight > aSize.Height() )
				aClip.Bottom() += nTextHeight-aSize.Height()+1;  // Damit HP-Drucker nicht 'weg-optimieren'
			pDev->IntersectClipRegion( aClip );
		}

		pDev->DrawText( aTextRect, aText, nTextStyle );
	}
	else
	{
		long		nTextHeight = pDev->GetTextHeight();
		sal_uInt16		nLines = (sal_uInt16)(aSize.Height() / nTextHeight);
		Rectangle	aClip( aPos, aSize );

        pDev->IntersectClipRegion( aClip );

        if ( !nLines )
			nLines = 1;

        for ( sal_uInt16 n = 0; n < nLines; n++ )
		{
			sal_uInt16 nEntry = n+mpImplLB->GetTopEntry();
			sal_Bool bSelected = mpImplLB->GetEntryList()->IsEntryPosSelected( nEntry );
			if ( bSelected )
			{
				pDev->SetFillColor( COL_BLACK );
				pDev->DrawRect( Rectangle(	Point( aPos.X(), aPos.Y() + n*nTextHeight ),
											Point( aPos.X() + aSize.Width(), aPos.Y() + (n+1)*nTextHeight + 2*nOnePixel ) ) );
				pDev->SetFillColor();
				pDev->SetTextColor( COL_WHITE );
			}

            aTextRect.Top() = aPos.Y() + n*nTextHeight;
            aTextRect.Bottom() = aTextRect.Top() + nTextHeight;

            pDev->DrawText( aTextRect, mpImplLB->GetEntryList()->GetEntryText( nEntry ), nTextStyle );

            if ( bSelected )
				pDev->SetTextColor( COL_BLACK );
		}
	}

	pDev->Pop();
}

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

void ListBox::GetFocus()
{
	if ( mpImplLB )
	{
		if( IsDropDownBox() )
			mpImplWin->GrabFocus();
		else
			mpImplLB->GrabFocus();
	}

	Control::GetFocus();
}

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

Window* ListBox::GetPreferredKeyInputWindow()
{
	if ( mpImplLB )
	{
		if( IsDropDownBox() )
			return mpImplWin->GetPreferredKeyInputWindow();
		else
			return mpImplLB->GetPreferredKeyInputWindow();
	}

	return Control::GetPreferredKeyInputWindow();
}

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

void ListBox::LoseFocus()
{
	if( IsDropDownBox() )
		mpImplWin->HideFocus();
	else
		mpImplLB->HideFocus();

	Control::LoseFocus();
}

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

void ListBox::DataChanged( const DataChangedEvent& rDCEvt )
{
	Control::DataChanged( rDCEvt );

	if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
		 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
		 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
		  (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
	{
        SetBackground();    // due to a hack in Window::UpdateSettings the background must be reset
                            // otherwise it will overpaint NWF drawn listboxes
		Resize();
		mpImplLB->Resize(); // Wird nicht durch ListBox::Resize() gerufen, wenn sich die ImplLB nicht aendert.

		if ( mpImplWin )
		{
			mpImplWin->SetSettings( GetSettings() );	// Falls noch nicht eingestellt...
			ImplInitFieldSettings( mpImplWin, sal_True, sal_True, sal_True );

			mpBtn->SetSettings( GetSettings() );
			ImplInitDropDownButton( mpBtn );
		}


		if ( IsDropDownBox() )
			Invalidate();
	}
}

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

void ListBox::EnableAutoSize( bool bAuto )
{
	mbDDAutoSize = bAuto;
	if ( mpFloatWin )
	{
		if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
        {
            // use GetListBoxMaximumLineCount here; before, was on fixed number of five
            AdaptDropDownLineCountToMaximum();
        }
		else if ( !bAuto )
        {
			mpFloatWin->SetDropDownLineCount( 0 );
        }
	}
}

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

void ListBox::EnableDDAutoWidth( sal_Bool b )
{
    if ( mpFloatWin )
        mpFloatWin->SetAutoWidth( b );
}

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

sal_Bool ListBox::IsDDAutoWidthEnabled() const
{
    return mpFloatWin ? mpFloatWin->IsAutoWidth() : sal_False;
}

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

void ListBox::SetDropDownLineCount( sal_uInt16 nLines )
{
    mnLineCount = nLines;
	if ( mpFloatWin )
		mpFloatWin->SetDropDownLineCount( mnLineCount );
}

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

void ListBox::AdaptDropDownLineCountToMaximum()
{
    // adapt to maximum allowed number
    SetDropDownLineCount(std::min(GetEntryCount(), GetSettings().GetStyleSettings().GetListBoxMaximumLineCount()));
}

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

sal_uInt16 ListBox::GetDropDownLineCount() const
{
    if ( mpFloatWin )
        return mpFloatWin->GetDropDownLineCount();
	return mnLineCount;
}

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

void ListBox::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
{
	if( IsDropDownBox() && ( nFlags & WINDOW_POSSIZE_SIZE ) )
	{
		Size aPrefSz = mpFloatWin->GetPrefSize();
		if ( ( nFlags & WINDOW_POSSIZE_HEIGHT ) && ( nHeight >= 2*mnDDHeight ) )
			aPrefSz.Height() = nHeight-mnDDHeight;
		if ( nFlags & WINDOW_POSSIZE_WIDTH )
			aPrefSz.Width() = nWidth;
		mpFloatWin->SetPrefSize( aPrefSz );

		if ( IsAutoSizeEnabled() && ! (nFlags & WINDOW_POSSIZE_DROPDOWN) )
			nHeight = mnDDHeight;
	}

	Control::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
}

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

void ListBox::Resize()
{
	Size aOutSz = GetOutputSizePixel();
	if( IsDropDownBox() )
	{
		// initialize the dropdown button size with the standard scrollbar width
		long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
		long	nTop = 0;
		long	nBottom = aOutSz.Height();

        // note: in case of no border, pBorder will actually be this
		Window *pBorder = GetWindow( WINDOW_BORDER );
		ImplControlValue aControlValue;
		Point aPoint;
		Rectangle aContent, aBound;

		// use the full extent of the control
		Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );

		if ( GetNativeControlRegion( CTRL_LISTBOX, PART_BUTTON_DOWN,
					aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
		{
			// convert back from border space to local coordinates
			aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
			aContent.Move( -aPoint.X(), -aPoint.Y() );

			// use the themes drop down size for the button
			aOutSz.Width() = aContent.Left();
			mpBtn->SetPosSizePixel( aContent.Left(), nTop, aContent.Right(), (nBottom-nTop) );

			// adjust the size of the edit field
			if ( GetNativeControlRegion( CTRL_LISTBOX, PART_SUB_EDIT,
						aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
			{
				// convert back from border space to local coordinates
				aContent.Move( -aPoint.X(), -aPoint.Y() );

				// use the themes drop down size
                if( ! (GetStyle() & WB_BORDER) && ImplGetSVData()->maNWFData.mbNoFocusRects )
                {
                    // no border but focus ring behavior -> we have a problem; the
                    // native rect relies on the border to draw the focus
                    // let's do the best we can and center vertically, so it doesn't look
                    // completely wrong.
                    Size aSz( GetOutputSizePixel() );
                    long nDiff = aContent.Top() - (aSz.Height() - aContent.GetHeight())/2;
                    aContent.Top() -= nDiff;
                    aContent.Bottom() -= nDiff;
                }
                mpImplWin->SetPosSizePixel( aContent.TopLeft(), aContent.GetSize() );
			}
			else
				mpImplWin->SetSizePixel( aOutSz );
		}
		else
		{
			nSBWidth = CalcZoom( nSBWidth );
			mpImplWin->SetPosSizePixel( 0, 0, aOutSz.Width() - nSBWidth, aOutSz.Height() );
			mpBtn->SetPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
		}
	}
	else
	{
		mpImplLB->SetSizePixel( aOutSz );
	}

	// FloatingWindow-Groesse auch im unsichtbare Zustand auf Stand halten,
	// weil KEY_PGUP/DOWN ausgewertet wird...
	if ( mpFloatWin )
		mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );

    Control::Resize();
}

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

void ListBox::FillLayoutData() const
{
    mpControlData->mpLayoutData = new vcl::ControlLayoutData();
    const Control* pMainWin = mpImplLB->GetMainWindow();
    if( mpFloatWin )
    {
        // dropdown mode
        AppendLayoutData( *mpImplWin );
        mpImplWin->SetLayoutDataParent( this );
        if( mpFloatWin->IsReallyVisible() )
        {
            AppendLayoutData( *pMainWin );
            pMainWin->SetLayoutDataParent( this );
        }
    }
    else
    {
        AppendLayoutData( *pMainWin );
        pMainWin->SetLayoutDataParent( this );
    }
}

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

long ListBox::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPos ) const
{
    if( !HasLayoutData() )
        FillLayoutData();

    // check whether rPoint fits at all
    long nIndex = Control::GetIndexForPoint( rPoint );
    if( nIndex != -1 )
    {
        // point must be either in main list window
        // or in impl window (dropdown case)
        ImplListBoxWindow* pMain = mpImplLB->GetMainWindow();
    
        // convert coordinates to ImplListBoxWindow pixel coordinate space
        Point aConvPoint = LogicToPixel( rPoint );
        aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
        aConvPoint = pMain->AbsoluteScreenToOutputPixel( aConvPoint );
        aConvPoint = pMain->PixelToLogic( aConvPoint );

        // try to find entry
        sal_uInt16 nEntry = pMain->GetEntryPosForPoint( aConvPoint );
        if( nEntry == LISTBOX_ENTRY_NOTFOUND )
        {
            // not found, maybe dropdown case
            if( mpImplWin && mpImplWin->IsReallyVisible() )
            {
                // convert to impl window pixel coordinates
                aConvPoint = LogicToPixel( rPoint );
                aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
                aConvPoint = mpImplWin->AbsoluteScreenToOutputPixel( aConvPoint );

                // check whether converted point is inside impl window
                Size aImplWinSize = mpImplWin->GetOutputSizePixel();
                if( aConvPoint.X() >= 0 && aConvPoint.Y() >= 0 && aConvPoint.X() < aImplWinSize.Width() && aConvPoint.Y() < aImplWinSize.Height() )
                {
                    // inside the impl window, the position is the current item pos
                    rPos = mpImplWin->GetItemPos();
                }
                else
                    nIndex = -1;
            }
            else
                nIndex = -1;
        }
        else
            rPos = nEntry;

        DBG_ASSERT( nIndex != -1, "found index for point, but relative index failed" );
    }

    // get line relative index
    if( nIndex != -1 )
        nIndex = ToRelativeLineIndex( nIndex );

    return nIndex;
}

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

void ListBox::StateChanged( StateChangedType nType )
{
	if( nType == STATE_CHANGE_READONLY )
	{
		if( mpImplWin )
			mpImplWin->Enable( !IsReadOnly() );
		if( mpBtn )
			mpBtn->Enable( !IsReadOnly() );
	}
	else if( nType == STATE_CHANGE_ENABLE )
	{
		mpImplLB->Enable( IsEnabled() );
		if( mpImplWin )
		{
			mpImplWin->Enable( IsEnabled() );
			if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
					&& ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
			{
				GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
			}
			else
				mpImplWin->Invalidate();
		}
		if( mpBtn )
			mpBtn->Enable( IsEnabled() );
	}
	else if( nType == STATE_CHANGE_UPDATEMODE )
	{
		mpImplLB->SetUpdateMode( IsUpdateMode() );
	}
	else if ( nType == STATE_CHANGE_ZOOM )
	{
		mpImplLB->SetZoom( GetZoom() );
		if ( mpImplWin )
		{
			mpImplWin->SetZoom( GetZoom() );
			mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
			mpImplWin->Invalidate();
		}
		Resize();
	}
	else if ( nType == STATE_CHANGE_CONTROLFONT )
	{
		mpImplLB->SetControlFont( GetControlFont() );
		if ( mpImplWin )
		{
			mpImplWin->SetControlFont( GetControlFont() );
			mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
			mpImplWin->Invalidate();
		}
		Resize();
	}
	else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
	{
		mpImplLB->SetControlForeground( GetControlForeground() );
		if ( mpImplWin )
		{
			mpImplWin->SetControlForeground( GetControlForeground() );
			mpImplWin->SetTextColor( GetControlForeground() );
			mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
			mpImplWin->Invalidate();
		}
	}
	else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
	{
		mpImplLB->SetControlBackground( GetControlBackground() );
		if ( mpImplWin )
		{
			if ( mpImplWin->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL) )
			{
				// Transparent background
				mpImplWin->SetBackground();
				mpImplWin->SetControlBackground();
			}
			else
			{
				mpImplWin->SetBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
				mpImplWin->SetControlBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
			}
			mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
			mpImplWin->Invalidate();
		}
	}
	else if ( nType == STATE_CHANGE_STYLE )
	{
		SetStyle( ImplInitStyle( GetStyle() ) );
		mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) ? sal_True : sal_False );
	    sal_Bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) ? sal_True : sal_False;
	    mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
	}
    else if( nType == STATE_CHANGE_MIRRORING )
    {
        if( mpBtn )
        {
            mpBtn->EnableRTL( IsRTLEnabled() );
            ImplInitDropDownButton( mpBtn );
        }
        mpImplLB->EnableRTL( IsRTLEnabled() );
        if( mpImplWin )
            mpImplWin->EnableRTL( IsRTLEnabled() );
        Resize();
    }

	Control::StateChanged( nType );
}

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

long ListBox::PreNotify( NotifyEvent& rNEvt )
{
	long nDone = 0;
	if ( mpImplLB )
	{
		if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( rNEvt.GetWindow() == mpImplWin ) )
		{
			KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
			switch( aKeyEvt.GetKeyCode().GetCode() )
			{
				case KEY_DOWN:
				{
					if( mpFloatWin && !mpFloatWin->IsInPopupMode() &&
						aKeyEvt.GetKeyCode().IsMod2() )
					{
                        ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
						mpBtn->SetPressed( sal_True );
						mpFloatWin->StartFloat( sal_False );
                        ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
						nDone = 1;
					}
					else
					{
						nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
					}
				}
				break;
				case KEY_UP:
				{
					if( mpFloatWin && mpFloatWin->IsInPopupMode() &&
						aKeyEvt.GetKeyCode().IsMod2() )
					{
						mpFloatWin->EndPopupMode();
						nDone = 1;
					}
					else
					{
						nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
					}
				}
				break;
				case KEY_RETURN:
				{
					if( IsInDropDown() )
					{
						mpImplLB->ProcessKeyInput( aKeyEvt );
						nDone = 1;
					}
				}
				break;

				default:
                {
					nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
                }
			}
		}
		else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
		{
			if ( IsInDropDown() && !HasChildPathFocus( sal_True ) )
				mpFloatWin->EndPopupMode();
		}
		else if ( (rNEvt.GetType() == EVENT_COMMAND) &&
				  (rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL) &&
				  (rNEvt.GetWindow() == mpImplWin) )
		{
            sal_uInt16 nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
            if  (   ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
                ||  (   ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
                    &&  HasChildPathFocus()
                    )
                )
            {
                nDone = mpImplLB->HandleWheelAsCursorTravel( *rNEvt.GetCommandEvent() );
            }
            else
            {
                nDone = 0;  // don't eat this event, let the default handling happen (i.e. scroll the context)
            }
		}
	}

	return nDone ? nDone : Control::PreNotify( rNEvt );
}

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

void ListBox::Select()
{
    ImplCallEventListenersAndHandler( VCLEVENT_LISTBOX_SELECT, maSelectHdl, this );
}

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

void ListBox::DoubleClick()
{
    ImplCallEventListenersAndHandler( VCLEVENT_LISTBOX_DOUBLECLICK, maDoubleClickHdl, this );
}

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

void ListBox::Clear()
{
	mpImplLB->Clear();
	if( IsDropDownBox() )
	{
		mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
		mpImplWin->SetString( ImplGetSVEmptyStr() );
		Image aImage;
		mpImplWin->SetImage( aImage );
		mpImplWin->Invalidate();
	}
    CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED, (void*) sal_IntPtr(-1) );
}

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

void ListBox::SetNoSelection()
{
	mpImplLB->SetNoSelection();
	if( IsDropDownBox() )
	{
		mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
		mpImplWin->SetString( ImplGetSVEmptyStr() );
		Image aImage;
		mpImplWin->SetImage( aImage );
		mpImplWin->Invalidate();
	}
	NotifyVCLEvent( VCLEVENT_LISTBOX_STATEUPDATE);
}

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

sal_uInt16 ListBox::InsertEntry( const XubString& rStr, sal_uInt16 nPos )
{
	sal_uInt16 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr );
	nRealPos = sal::static_int_cast<sal_uInt16>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
    CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
	return nRealPos;
}

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

sal_uInt16 ListBox::InsertEntry( const Image& rImage, sal_uInt16 nPos )
{
	sal_uInt16 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rImage );
	nRealPos = sal::static_int_cast<sal_uInt16>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
    CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
	return nRealPos;
}

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

sal_uInt16 ListBox::InsertEntry( const XubString& rStr, const Image& rImage, sal_uInt16 nPos )
{
	sal_uInt16 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr, rImage );
	nRealPos = sal::static_int_cast<sal_uInt16>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
    CallEventListeners( VCLEVENT_LISTBOX_ITEMADDED, (void*) sal_IntPtr(nRealPos) );
	return nRealPos;
}

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

void ListBox::RemoveEntry( const XubString& rStr )
{
	RemoveEntry( GetEntryPos( rStr ) );
}

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

void ListBox::RemoveEntry( sal_uInt16 nPos )
{
	mpImplLB->RemoveEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
    CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED, (void*) sal_IntPtr(nPos) );
}

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

Image ListBox::GetEntryImage( sal_uInt16 nPos ) const
{
    if ( mpImplLB->GetEntryList()->HasEntryImage( nPos ) )
        return mpImplLB->GetEntryList()->GetEntryImage( nPos );
    return Image();
}

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

sal_uInt16 ListBox::GetEntryPos( const XubString& rStr ) const
{
	sal_uInt16 nPos = mpImplLB->GetEntryList()->FindEntry( rStr );
	if ( nPos != LISTBOX_ENTRY_NOTFOUND )
		nPos = sal::static_int_cast<sal_uInt16>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
	return nPos;
}

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

sal_uInt16 ListBox::GetEntryPos( const void* pData ) const
{
	sal_uInt16 nPos = mpImplLB->GetEntryList()->FindEntry( pData );
	if ( nPos != LISTBOX_ENTRY_NOTFOUND )
		nPos = sal::static_int_cast<sal_uInt16>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
	return nPos;
}

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

XubString ListBox::GetEntry( sal_uInt16 nPos ) const
{
	return mpImplLB->GetEntryList()->GetEntryText( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

sal_uInt16 ListBox::GetEntryCount() const
{
	return mpImplLB->GetEntryList()->GetEntryCount() - mpImplLB->GetEntryList()->GetMRUCount();
}

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

XubString ListBox::GetSelectEntry( sal_uInt16 nIndex ) const
{
	return GetEntry( GetSelectEntryPos( nIndex ) );
}

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

sal_uInt16 ListBox::GetSelectEntryCount() const
{
	return mpImplLB->GetEntryList()->GetSelectEntryCount();
}

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

sal_uInt16 ListBox::GetSelectEntryPos( sal_uInt16 nIndex ) const
{
	sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( nIndex );
	if ( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
			nPos = mpImplLB->GetEntryList()->FindEntry( mpImplLB->GetEntryList()->GetEntryText( nPos ) );
		nPos = sal::static_int_cast<sal_uInt16>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
	}
	return nPos;
}

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

sal_Bool ListBox::IsEntrySelected( const XubString& rStr ) const
{
	return IsEntryPosSelected( GetEntryPos( rStr ) );
}

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

sal_Bool ListBox::IsEntryPosSelected( sal_uInt16 nPos ) const
{
	return mpImplLB->GetEntryList()->IsEntryPosSelected( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

void ListBox::SelectEntry( const XubString& rStr, sal_Bool bSelect )
{
	SelectEntryPos( GetEntryPos( rStr ), bSelect );
}

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

void ListBox::SelectEntryPos( sal_uInt16 nPos, sal_Bool bSelect )
{
	if ( nPos < mpImplLB->GetEntryList()->GetEntryCount() )
	{
		sal_uInt16 oldSelectCount = GetSelectEntryCount(), newSelectCount = 0, nCurrentPos = mpImplLB->GetCurrentPos();
		mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), bSelect );
		newSelectCount = GetSelectEntryCount();
		if (oldSelectCount == 0 && newSelectCount > 0)
			NotifyVCLEvent( VCLEVENT_LISTBOX_STATEUPDATE);
		//Only when bSelect == true, send both Selection & Focus events
		if (nCurrentPos != nPos && bSelect)
		{
			ImplCallEventListeners( VCLEVENT_LISTBOX_SELECT, reinterpret_cast<void*>(nPos));
			if (HasFocus())
				ImplCallEventListeners( VCLEVENT_LISTBOX_FOCUS, reinterpret_cast<void*>(nPos));
		}
	}
}

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

void ListBox::SetEntryData( sal_uInt16 nPos, void* pNewData )
{
	mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount(), pNewData );
}

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

void* ListBox::GetEntryData( sal_uInt16 nPos ) const
{
	return mpImplLB->GetEntryList()->GetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

void ListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
{
	mpImplLB->SetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount(), nFlags );
}

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

long ListBox::GetEntryFlags( sal_uInt16 nPos ) const
{
	return mpImplLB->GetEntryList()->GetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

void ListBox::SetTopEntry( sal_uInt16 nPos )
{
	mpImplLB->SetTopEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

void ListBox::ShowProminentEntry( sal_uInt16 nPos )
{
	mpImplLB->ShowProminentEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
}

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

sal_uInt16 ListBox::GetTopEntry() const
{
	sal_uInt16 nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
	if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
		nPos = 0;
	return nPos;
}

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

void ListBox::SetProminentEntryType( ProminentEntry eType )
{
    mpImplLB->SetProminentEntryType( eType );
}

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

ProminentEntry ListBox::GetProminentEntryType() const
{
    return mpImplLB->GetProminentEntryType();
}

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

sal_Bool ListBox::IsTravelSelect() const
{
	return mpImplLB->IsTravelSelect();
}

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

sal_Bool ListBox::IsInDropDown() const
{
	return mpFloatWin && mpFloatWin->IsInPopupMode();
}

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

long ListBox::CalcWindowSizePixel( sal_uInt16 nLines ) const
{
	return mpImplLB->GetEntryHeight() * nLines;
}

Rectangle ListBox::GetBoundingRectangle( sal_uInt16 nItem ) const
{
    Rectangle aRect = mpImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
    Rectangle aOffset = mpImplLB->GetMainWindow()->GetWindowExtentsRelative( (Window*)this );
    aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
    return aRect;
}

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

void ListBox::EnableMultiSelection( sal_Bool bMulti )
{
	EnableMultiSelection( bMulti, sal_False );
}

void ListBox::EnableMultiSelection( sal_Bool bMulti, sal_Bool bStackSelection )
{
	mpImplLB->EnableMultiSelection( bMulti, bStackSelection );

	// WB_SIMPLEMODE:
	// Die MultiListBox verh�lt sich wie eine normale ListBox.
	// Die Mehrfachselektion kann nur �ber entsprechende Zusatztasten erfolgen.

	sal_Bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) ? sal_True : sal_False;
	mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );

	// ohne Focus ist das Traveln in einer MultiSelection nicht zu sehen:
	if ( mpFloatWin )
		mpImplLB->GetMainWindow()->AllowGrabFocus( bMulti );
}

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

sal_Bool ListBox::IsMultiSelectionEnabled() const
{
	return mpImplLB->IsMultiSelectionEnabled();
}

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

Size ListBox::CalcMinimumSize() const
{
	Size aSz;
	if ( !IsDropDownBox() )
        aSz = mpImplLB->CalcSize (mnLineCount ? mnLineCount : mpImplLB->GetEntryList()->GetEntryCount());
	else
	{
		aSz.Height() = mpImplLB->CalcSize( 1 ).Height();
		aSz.Height() += 4; // add a space between entry and border
        // size to maxmimum entry width and add a little breathing space
		aSz.Width() = mpImplLB->GetMaxEntryWidth() + 4;
        // do not create ultrathin ListBoxes, it doesn't look good
        if( aSz.Width() < GetSettings().GetStyleSettings().GetScrollBarSize() )
            aSz.Width() = GetSettings().GetStyleSettings().GetScrollBarSize();

        // try native borders; scrollbar size may not be a good indicator
        // see how large the edit area inside is to estimate what is needed for the dropdown
		ImplControlValue aControlValue;
		Point aPoint;
		Rectangle aContent, aBound;
        Size aTestSize( 100, 20 );
		Rectangle aArea( aPoint, aTestSize );
        if( const_cast<ListBox*>(this)->GetNativeControlRegion(
                       CTRL_LISTBOX, PART_SUB_EDIT, aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
        {
            // use the themes drop down size
            aSz.Width() += aTestSize.Width() - aContent.GetWidth();
        }
        else
            aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
	}

	aSz = CalcWindowSize( aSz );
    
	if ( IsDropDownBox() ) // check minimum height of dropdown box
    {
        ImplControlValue aControlValue;
        Rectangle aRect( Point( 0, 0 ), aSz );
        Rectangle aContent, aBound;
        if( const_cast<ListBox*>(this)->GetNativeControlRegion(
                       CTRL_LISTBOX, PART_ENTIRE_CONTROL, aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
        {
            if( aBound.GetHeight() > aSz.Height() )
                aSz.Height() = aBound.GetHeight();
        }
    }
    
	return aSz;
}

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

Size ListBox::GetOptimalSize(WindowSizeType eType) const
{
    switch (eType) {
    case WINDOWSIZE_MINIMUM:
        return CalcMinimumSize();
    default:
        return Control::GetOptimalSize( eType );
    }
}

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

Size ListBox::CalcAdjustedSize( const Size& rPrefSize ) const
{
	Size aSz = rPrefSize;
	sal_Int32 nLeft, nTop, nRight, nBottom;
	((Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
	aSz.Height() -= nTop+nBottom;
	if ( !IsDropDownBox() )
	{
		long nEntryHeight = CalcSize( 1, 1 ).Height();
		long nLines = aSz.Height() / nEntryHeight;
		if ( nLines < 1 )
			nLines = 1;
		aSz.Height() = nLines * nEntryHeight;
	}
	else
	{
		aSz.Height() = mnDDHeight;
	}
	aSz.Height() += nTop+nBottom;

	aSz = CalcWindowSize( aSz );
	return aSz;
}

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

Size ListBox::CalcSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
{
	// ggf. werden ScrollBars eingeblendet
	Size aMinSz = CalcMinimumSize();
//	aMinSz = ImplCalcOutSz( aMinSz );

	Size aSz;

	// Hoehe
	if ( nLines )
	{
		if ( !IsDropDownBox() )
			aSz.Height() = mpImplLB->CalcSize( nLines ).Height();
		else
			aSz.Height() = mnDDHeight;
	}
	else
		aSz.Height() = aMinSz.Height();

	// Breite
	if ( nColumns )
		aSz.Width() = nColumns * GetTextWidth( XubString( 'X' ) );
	else
		aSz.Width() = aMinSz.Width();

	if ( IsDropDownBox() )
		aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();

	if ( !IsDropDownBox() )
	{
		if ( aSz.Width() < aMinSz.Width() )
			aSz.Height() += GetSettings().GetStyleSettings().GetScrollBarSize();
		if ( aSz.Height() < aMinSz.Height() )
			aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
	}

	aSz = CalcWindowSize( aSz );
	return aSz;
}

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

void ListBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
{
	long nCharWidth = GetTextWidth( UniString( 'x' ) );
	if ( !IsDropDownBox() )
	{
		Size aOutSz = mpImplLB->GetMainWindow()->GetOutputSizePixel();
		rnCols = (sal_uInt16) (aOutSz.Width()/nCharWidth);
		rnLines = (sal_uInt16) (aOutSz.Height()/mpImplLB->GetEntryHeight());
	}
	else
	{
		Size aOutSz = mpImplWin->GetOutputSizePixel();
		rnCols = (sal_uInt16) (aOutSz.Width()/nCharWidth);
		rnLines = 1;
	}
}

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

IMPL_LINK( ListBox, ImplUserDrawHdl, UserDrawEvent*, pEvent )
{
	UserDraw( *pEvent );
	return 1;
}

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

void ListBox::UserDraw( const UserDrawEvent& )
{
}

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

void ListBox::DrawEntry( const UserDrawEvent& rEvt, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos )
{
	if ( rEvt.GetDevice() == mpImplLB->GetMainWindow() )
		mpImplLB->GetMainWindow()->DrawEntry( rEvt.GetItemId(), bDrawImage, bDrawText, bDrawTextAtImagePos );
	else if ( rEvt.GetDevice() == mpImplWin )
		mpImplWin->DrawEntry( bDrawImage, bDrawText, bDrawTextAtImagePos );
}

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

void ListBox::SetUserItemSize( const Size& rSz )
{
	mpImplLB->GetMainWindow()->SetUserItemSize( rSz );
	if ( mpImplWin )
		mpImplWin->SetUserItemSize( rSz );
}

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

const Size& ListBox::GetUserItemSize() const
{
	return mpImplLB->GetMainWindow()->GetUserItemSize();
}

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

void ListBox::EnableUserDraw( sal_Bool bUserDraw )
{
	mpImplLB->GetMainWindow()->EnableUserDraw( bUserDraw );
	if ( mpImplWin )
		mpImplWin->EnableUserDraw( bUserDraw );
}

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

sal_Bool ListBox::IsUserDrawEnabled() const
{
	return mpImplLB->GetMainWindow()->IsUserDrawEnabled();
}

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

void ListBox::SetReadOnly( sal_Bool bReadOnly )
{
	if ( mpImplLB->IsReadOnly() != bReadOnly )
	{
		mpImplLB->SetReadOnly( bReadOnly );
		StateChanged( STATE_CHANGE_READONLY );
	}
}

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

sal_Bool ListBox::IsReadOnly() const
{
	return mpImplLB->IsReadOnly();
}

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

void ListBox::SetSeparatorPos( sal_uInt16 n )
{
	mpImplLB->SetSeparatorPos( n );
}

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

void ListBox::SetSeparatorPos()
{
	mpImplLB->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
}

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

sal_uInt16 ListBox::GetSeparatorPos() const
{
	return mpImplLB->GetSeparatorPos();
}

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

void ListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
{
	mpImplLB->SetMRUEntries( rEntries, cSep );
}

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

XubString ListBox::GetMRUEntries( xub_Unicode cSep ) const
{
	return mpImplLB->GetMRUEntries( cSep );
}

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

void ListBox::SetMaxMRUCount( sal_uInt16 n )
{
	mpImplLB->SetMaxMRUCount( n );
}

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

sal_uInt16 ListBox::GetMaxMRUCount() const
{
	return mpImplLB->GetMaxMRUCount();
}
sal_uInt16 ListBox::GetMRUCount() const
{
	return mpImplLB->GetEntryList()->GetMRUCount();
}

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

sal_uInt16 ListBox::GetDisplayLineCount() const
{
    return mpImplLB->GetDisplayLineCount();
}

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

// pb: #106948# explicit mirroring for calc

void ListBox::EnableMirroring()
{
    mpImplLB->EnableMirroring();
}

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

Rectangle ListBox::GetDropDownPosSizePixel() const
{
    return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ListBox*>(this) ) : Rectangle();
}

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

const Wallpaper& ListBox::GetDisplayBackground() const
{
    // !!! recursion does not occur because the ImplListBox is default
    // initialized to a nontransparent color in Window::ImplInitData
    return mpImplLB->GetDisplayBackground();
}

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

void ListBox::SetEdgeBlending(bool bNew)
{
    if(mbEdgeBlending != bNew)
    {
        mbEdgeBlending = bNew;

        if(IsDropDownBox())
        {
            mpImplWin->Invalidate();
        }
        else
        {
            mpImplLB->Invalidate();
        }

        if(mpImplWin)
        {
            mpImplWin->SetEdgeBlending(GetEdgeBlending());
        }

        if(mpImplLB)
        {
            mpImplLB->SetEdgeBlending(GetEdgeBlending());
        }

        Invalidate();
    }
}

// =======================================================================
MultiListBox::MultiListBox( Window* pParent, WinBits nStyle ) :
	ListBox( WINDOW_MULTILISTBOX )
{
	ImplInit( pParent, nStyle );
	EnableMultiSelection( sal_True );
}

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

MultiListBox::MultiListBox( Window* pParent, const ResId& rResId ) :
	ListBox( WINDOW_MULTILISTBOX )
{
	rResId.SetRT( RSC_MULTILISTBOX );
	WinBits nStyle = ImplInitRes( rResId );
	ImplInit( pParent, nStyle );
	ImplLoadRes( rResId );

	if ( !(nStyle & WB_HIDE ) )
		Show();
	EnableMultiSelection( sal_True );
}