summaryrefslogtreecommitdiff
path: root/vcl/source/control/ilstbox.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/control/ilstbox.cxx')
-rw-r--r--vcl/source/control/ilstbox.cxx3227
1 files changed, 3227 insertions, 0 deletions
diff --git a/vcl/source/control/ilstbox.cxx b/vcl/source/control/ilstbox.cxx
new file mode 100644
index 000000000000..cd74a4cd88ce
--- /dev/null
+++ b/vcl/source/control/ilstbox.cxx
@@ -0,0 +1,3227 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/event.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/help.hxx>
+#include <vcl/lstbox.h>
+#include <vcl/ilstbox.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/controldata.hxx>
+#include <vcl/unohelp.hxx>
+#ifndef _COM_SUN_STAR_UTIL_XCOLLATOR_HPP_
+#include <com/sun/star/i18n/XCollator.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HDL_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#endif
+
+#define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
+
+using namespace ::com::sun::star;
+
+// =======================================================================
+
+void ImplInitFieldSettings( Window* pWin, BOOL bFont, BOOL bForeground, BOOL bBackground )
+{
+ const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
+
+ if ( bFont )
+ {
+ Font aFont = rStyleSettings.GetFieldFont();
+ if ( pWin->IsControlFont() )
+ aFont.Merge( pWin->GetControlFont() );
+ pWin->SetZoomedPointFont( aFont );
+ }
+
+ if ( bFont || bForeground )
+ {
+ Color aTextColor = rStyleSettings.GetFieldTextColor();
+ if ( pWin->IsControlForeground() )
+ aTextColor = pWin->GetControlForeground();
+ pWin->SetTextColor( aTextColor );
+ }
+
+ if ( bBackground )
+ {
+ if( pWin->IsControlBackground() )
+ pWin->SetBackground( pWin->GetControlBackground() );
+ else
+ pWin->SetBackground( rStyleSettings.GetFieldColor() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplInitDropDownButton( PushButton* pButton )
+{
+ if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
+ else
+ pButton->SetSymbol( SYMBOL_SPIN_DOWN );
+
+ if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ pButton->SetBackground();
+}
+
+// =======================================================================
+
+ImplEntryList::ImplEntryList( Window* pWindow )
+{
+ mpWindow = pWindow;
+ mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
+ mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
+ mnImages = 0;
+ mbCallSelectionChangedHdl = TRUE;
+
+ mnMRUCount = 0;
+ mnMaxMRUCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplEntryList::~ImplEntryList()
+{
+ Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::Clear()
+{
+ mnImages = 0;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ delete pImplEntry;
+ }
+ List::Clear();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ if ( pImplEntry &&
+ ( pImplEntry->mbIsSelected != bSelect ) &&
+ ( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0 ) )
+ {
+ pImplEntry->mbIsSelected = bSelect;
+ if ( mbCallSelectionChangedHdl )
+ maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
+{
+ static uno::Reference< i18n::XCollator > xCollator;
+ if ( !xCollator.is() )
+ xCollator = vcl::unohelper::CreateCollator();
+ if( xCollator.is() )
+ xCollator->loadDefaultCollator (rLocale, 0);
+
+ return xCollator;
+}
+
+USHORT ImplEntryList::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry, BOOL bSort )
+{
+ if ( !!pNewEntry->maImage )
+ mnImages++;
+
+ if ( !bSort || !Count() )
+ {
+ Insert( pNewEntry, nPos );
+ }
+ else
+ {
+ lang::Locale aLocale = Application::GetSettings().GetLocale();
+ uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
+
+ const XubString& rStr = pNewEntry->maStr;
+ ULONG nLow, nHigh, nMid;
+
+ nHigh = Count();
+
+ ImplEntryType* pTemp = GetEntry( (USHORT)(nHigh-1) );
+
+ try
+ {
+ // XXX even though XCollator::compareString returns a sal_Int32 the only
+ // defined values are {-1, 0, 1} which is compatible with StringCompare
+ StringCompare eComp = xCollator.is() ?
+ (StringCompare)xCollator->compareString (rStr, pTemp->maStr)
+ : COMPARE_EQUAL;
+
+ // Schnelles Einfuegen bei sortierten Daten
+ if ( eComp != COMPARE_LESS )
+ {
+ Insert( pNewEntry, LIST_APPEND );
+ }
+ else
+ {
+ nLow = mnMRUCount;
+ pTemp = (ImplEntryType*)GetEntry( (USHORT)nLow );
+
+ eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
+ if ( eComp != COMPARE_GREATER )
+ {
+ Insert( pNewEntry, (ULONG)0 );
+ }
+ else
+ {
+ // Binaeres Suchen
+ nHigh--;
+ do
+ {
+ nMid = (nLow + nHigh) / 2;
+ pTemp = (ImplEntryType*)GetObject( nMid );
+
+ eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
+
+ if ( eComp == COMPARE_LESS )
+ nHigh = nMid-1;
+ else
+ {
+ if ( eComp == COMPARE_GREATER )
+ nLow = nMid + 1;
+ else
+ break;
+ }
+ }
+ while ( nLow <= nHigh );
+
+ if ( eComp != COMPARE_LESS )
+ nMid++;
+
+ Insert( pNewEntry, nMid );
+ }
+ }
+ }
+ catch (uno::RuntimeException& )
+ {
+ // XXX this is arguable, if the exception occured because pNewEntry is
+ // garbage you wouldn't insert it. If the exception occured because the
+ // Collator implementation is garbage then give the user a chance to see
+ // his stuff
+ Insert( pNewEntry, (ULONG)0 );
+ }
+
+ }
+
+ return (USHORT)GetPos( pNewEntry );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::RemoveEntry( USHORT nPos )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
+ if ( pImplEntry )
+ {
+ if ( !!pImplEntry->maImage )
+ mnImages--;
+
+ delete pImplEntry;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindEntry( const XubString& rString, BOOL bSearchMRUArea ) const
+{
+ USHORT nEntries = GetEntryCount();
+ for ( USHORT n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
+ {
+ ImplEntryType* pImplEntry = GetEntry( n );
+ String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
+ if ( aComp == rString )
+ return n;
+ }
+ return LISTBOX_ENTRY_NOTFOUND;
+}
+
+ // -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindMatchingEntry( const XubString& rStr, USHORT nStart, BOOL bForward, BOOL bLazy ) const
+{
+ USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
+ USHORT nEntryCount = GetEntryCount();
+ if ( !bForward )
+ nStart++; // wird sofort dekrementiert
+
+ const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
+ for ( USHORT n = nStart; bForward ? ( n < nEntryCount ) : n; )
+ {
+ if ( !bForward )
+ n--;
+
+ ImplEntryType* pImplEntry = GetEntry( n );
+ BOOL bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
+ if ( bMatch )
+ {
+ nPos = n;
+ break;
+ }
+
+ if ( bForward )
+ n++;
+ }
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindEntry( const void* pData ) const
+{
+ USHORT nPos = LISTBOX_ENTRY_NOTFOUND;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ if ( pImplEntry->mpUserData == pData )
+ {
+ nPos = n;
+ break;
+ }
+ }
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetAddedHeight( USHORT i_nEndIndex, USHORT i_nBeginIndex, long i_nBeginHeight ) const
+{
+ long nHeight = i_nBeginHeight;
+ USHORT nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
+ USHORT nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
+ USHORT nEntryCount = GetEntryCount();
+ if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
+ {
+ // sanity check
+ if( nStop > nEntryCount-1 )
+ nStop = nEntryCount-1;
+ if( nStart > nEntryCount-1 )
+ nStart = nEntryCount-1;
+
+ USHORT nIndex = nStart;
+ while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
+ {
+ nHeight += GetEntryPtr( nIndex )-> mnHeight;
+ nIndex++;
+ }
+ }
+ else
+ nHeight = 0;
+ return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetEntryHeight( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ return pImplEntry ? pImplEntry->mnHeight : 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplEntryList::GetEntryText( USHORT nPos ) const
+{
+ XubString aEntryText;
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ if ( pImplEntry )
+ aEntryText = pImplEntry->maStr;
+ return aEntryText;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::HasEntryImage( USHORT nPos ) const
+{
+ BOOL bImage = FALSE;
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ bImage = !!pImplEntry->maImage;
+ return bImage;
+}
+
+// -----------------------------------------------------------------------
+
+Image ImplEntryList::GetEntryImage( USHORT nPos ) const
+{
+ Image aImage;
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ aImage = pImplEntry->maImage;
+ return aImage;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SetEntryData( USHORT nPos, void* pNewData )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ pImplEntry->mpUserData = pNewData;
+}
+
+// -----------------------------------------------------------------------
+
+void* ImplEntryList::GetEntryData( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ return pImplEntry ? pImplEntry->mpUserData : NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplEntryList::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ if ( pImplEntry )
+ pImplEntry->mnFlags = nFlags;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplEntryList::GetEntryFlags( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
+ return pImplEntry ? pImplEntry->mnFlags : 0;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::GetSelectEntryCount() const
+{
+ USHORT nSelCount = 0;
+ for ( USHORT n = GetEntryCount(); n; )
+ {
+ ImplEntryType* pImplEntry = GetEntry( --n );
+ if ( pImplEntry->mbIsSelected )
+ nSelCount++;
+ }
+ return nSelCount;
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplEntryList::GetSelectEntry( USHORT nIndex ) const
+{
+ return GetEntryText( GetSelectEntryPos( nIndex ) );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::GetSelectEntryPos( USHORT nIndex ) const
+{
+ USHORT nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
+ USHORT nSel = 0;
+ USHORT nEntryCount = GetEntryCount();
+
+ for ( USHORT n = 0; n < nEntryCount; n++ )
+ {
+ ImplEntryType* pImplEntry = GetEntry( n );
+ if ( pImplEntry->mbIsSelected )
+ {
+ if ( nSel == nIndex )
+ {
+ nSelEntryPos = n;
+ break;
+ }
+ nSel++;
+ }
+ }
+
+ return nSelEntryPos;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::IsEntrySelected( const XubString& rStr ) const
+{
+ return IsEntryPosSelected( FindEntry( rStr ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplEntryList::IsEntryPosSelected( USHORT nIndex ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nIndex );
+ return pImplEntry ? pImplEntry->mbIsSelected : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplEntryList::IsEntrySelectable( USHORT nPos ) const
+{
+ ImplEntryType* pImplEntry = GetEntry( nPos );
+ return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplEntryList::FindFirstSelectable( USHORT nPos, bool bForward /* = true */ )
+{
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+
+ if( bForward )
+ {
+ for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
+ {
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+ }
+ }
+ else
+ {
+ while( nPos )
+ {
+ nPos--;
+ if( IsEntrySelectable( nPos ) )
+ return nPos;
+ }
+ }
+
+ return LISTBOX_ENTRY_NOTFOUND;
+}
+
+// =======================================================================
+
+ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
+ Control( pParent, 0 )
+{
+ mpEntryList = new ImplEntryList( this );
+
+ mnTop = 0;
+ mnLeft = 0;
+ mnBorder = 1;
+ mnSelectModifier = 0;
+ mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
+ mbTrack = FALSE;
+ mbImgsDiffSz = FALSE;
+ mbTravelSelect = FALSE;
+ mbTrackingSelect = FALSE;
+ mbSelectionChanged = FALSE;
+ mbMouseMoveSelect = FALSE;
+ mbMulti = FALSE;
+ mbStackMode = FALSE;
+ mbGrabFocus = FALSE;
+ mbUserDrawEnabled = FALSE;
+ mbInUserDraw = FALSE;
+ mbReadOnly = FALSE;
+ mbHasFocusRect = FALSE;
+ mbRight = ( nWinStyle & WB_RIGHT ) ? TRUE : FALSE;
+ mbCenter = ( nWinStyle & WB_CENTER ) ? TRUE : FALSE;
+ mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE ) ? TRUE : FALSE;
+ mbSort = ( nWinStyle & WB_SORT ) ? TRUE : FALSE;
+
+ // pb: #106948# explicit mirroring for calc
+ mbMirroring = FALSE;
+
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+ mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
+ meProminentType = PROMINENT_TOP;
+
+ SetLineColor();
+ SetTextFillColor();
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
+
+ maSearchTimeout.SetTimeout( 2500 );
+ maSearchTimeout.SetTimeoutHdl( LINK( this, ImplListBoxWindow, SearchStringTimeout ) );
+
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+ImplListBoxWindow::~ImplListBoxWindow()
+{
+ maSearchTimeout.Stop();
+ delete mpEntryList;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground )
+{
+ ImplInitFieldSettings( this, bFont, bForeground, bBackground );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplCalcMetrics()
+{
+ mnMaxWidth = 0;
+ mnMaxTxtWidth = 0;
+ mnMaxImgWidth = 0;
+ mnMaxImgTxtWidth= 0;
+ mnMaxImgHeight = 0;
+
+ mnTextHeight = (USHORT)GetTextHeight();
+ mnMaxTxtHeight = mnTextHeight + mnBorder;
+ mnMaxHeight = mnMaxTxtHeight;
+
+ if ( maUserItemSize.Height() > mnMaxHeight )
+ mnMaxHeight = (USHORT) maUserItemSize.Height();
+ if ( maUserItemSize.Width() > mnMaxWidth )
+ mnMaxWidth= (USHORT) maUserItemSize.Width();
+
+ for ( USHORT n = mpEntryList->GetEntryCount(); n; )
+ {
+ ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
+ ImplUpdateEntryMetrics( *pEntry );
+ }
+
+ if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
+ maFocusRect.SetSize( aSz );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBoxWindow, SearchStringTimeout, Timer*, EMPTYARG )
+{
+ maSearchStr.Erase();
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Clear()
+{
+ mpEntryList->Clear();
+
+ mnMaxHeight = mnMaxTxtHeight;
+ mnMaxWidth = 0;
+ mnMaxTxtWidth = 0;
+ mnMaxImgTxtWidth= 0;
+ mnMaxImgWidth = 0;
+ mnMaxImgHeight = 0;
+ mnTop = 0;
+ mnLeft = 0;
+ mbImgsDiffSz = FALSE;
+ ImplClearLayoutData();
+
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+
+ Invalidate();
+}
+
+void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
+{
+ ImplClearLayoutData();
+ maUserItemSize = rSz;
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+struct ImplEntryMetrics
+{
+ BOOL bText;
+ BOOL bImage;
+ long nEntryWidth;
+ long nEntryHeight;
+ long nTextWidth;
+ long nImgWidth;
+ long nImgHeight;
+};
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
+{
+ ImplEntryMetrics aMetrics;
+ aMetrics.bText = rEntry.maStr.Len() ? TRUE : FALSE;
+ aMetrics.bImage = !!rEntry.maImage;
+ aMetrics.nEntryWidth = 0;
+ aMetrics.nEntryHeight = 0;
+ aMetrics.nTextWidth = 0;
+ aMetrics.nImgWidth = 0;
+ aMetrics.nImgHeight = 0;
+
+ if ( aMetrics.bText )
+ {
+ if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ {
+ // multiline case
+ Size aCurSize( PixelToLogic( GetSizePixel() ) );
+ // set the current size to a large number
+ // GetTextRect should shrink it to the actual size
+ aCurSize.Height() = 0x7fffff;
+ Rectangle aTextRect( Point( 0, 0 ), aCurSize );
+ aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
+ aMetrics.nTextWidth = aTextRect.GetWidth();
+ if( aMetrics.nTextWidth > mnMaxTxtWidth )
+ mnMaxTxtWidth = aMetrics.nTextWidth;
+ aMetrics.nEntryWidth = mnMaxTxtWidth;
+ aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
+ }
+ else
+ {
+ // normal single line case
+ aMetrics.nTextWidth = (USHORT)GetTextWidth( rEntry.maStr );
+ if( aMetrics.nTextWidth > mnMaxTxtWidth )
+ mnMaxTxtWidth = aMetrics.nTextWidth;
+ aMetrics.nEntryWidth = mnMaxTxtWidth;
+ aMetrics.nEntryHeight = mnTextHeight + mnBorder;
+ }
+ }
+ if ( aMetrics.bImage )
+ {
+ Size aImgSz = rEntry.maImage.GetSizePixel();
+ aMetrics.nImgWidth = (USHORT) CalcZoom( aImgSz.Width() );
+ aMetrics.nImgHeight = (USHORT) CalcZoom( aImgSz.Height() );
+
+ if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
+ mbImgsDiffSz = TRUE;
+ else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
+ mbImgsDiffSz = TRUE;
+
+ if( aMetrics.nImgWidth > mnMaxImgWidth )
+ mnMaxImgWidth = aMetrics.nImgWidth;
+ if( aMetrics.nImgHeight > mnMaxImgHeight )
+ mnMaxImgHeight = aMetrics.nImgHeight;
+
+ mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
+ aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
+
+ }
+ if ( IsUserDrawEnabled() || aMetrics.bImage )
+ {
+ aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
+ if ( aMetrics.bText )
+ aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
+ aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
+ aMetrics.nEntryHeight );
+ }
+
+ if ( aMetrics.nEntryWidth > mnMaxWidth )
+ mnMaxWidth = aMetrics.nEntryWidth;
+ if ( aMetrics.nEntryHeight > mnMaxHeight )
+ mnMaxHeight = aMetrics.nEntryHeight;
+
+ rEntry.mnHeight = aMetrics.nEntryHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplCallSelect()
+{
+ if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
+ {
+ // Insert the selected entry as MRU, if not allready first MRU
+ USHORT nSelected = GetEntryList()->GetSelectEntryPos( 0 );
+ USHORT nMRUCount = GetEntryList()->GetMRUCount();
+ String aSelected = GetEntryList()->GetEntryText( nSelected );
+ USHORT nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, TRUE );
+ if ( nFirstMatchingEntryPos || !nMRUCount )
+ {
+ BOOL bSelectNewEntry = FALSE;
+ if ( nFirstMatchingEntryPos < nMRUCount )
+ {
+ RemoveEntry( nFirstMatchingEntryPos );
+ nMRUCount--;
+ if ( nFirstMatchingEntryPos == nSelected )
+ bSelectNewEntry = TRUE;
+ }
+ else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
+ {
+ RemoveEntry( nMRUCount - 1 );
+ nMRUCount--;
+ }
+
+ ImplClearLayoutData();
+
+ ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
+ pNewEntry->mbIsSelected = bSelectNewEntry;
+ GetEntryList()->InsertEntry( 0, pNewEntry, FALSE );
+ ImplUpdateEntryMetrics( *pNewEntry );
+ GetEntryList()->SetMRUCount( ++nMRUCount );
+ SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
+ maMRUChangedHdl.Call( NULL );
+ }
+ }
+
+ maSelectHdl.Call( NULL );
+ mbSelectionChanged = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::InsertEntry( USHORT nPos, ImplEntryType* pNewEntry )
+{
+ ImplClearLayoutData();
+ USHORT nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
+
+ if( (GetStyle() & WB_WORDBREAK) )
+ pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
+
+ ImplUpdateEntryMetrics( *pNewEntry );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::RemoveEntry( USHORT nPos )
+{
+ ImplClearLayoutData();
+ mpEntryList->RemoveEntry( nPos );
+ if( mnCurrentPos >= mpEntryList->GetEntryCount() )
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ ImplCalcMetrics();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ mpEntryList->SetEntryFlags( nPos, nFlags );
+ ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
+ if( pEntry )
+ ImplUpdateEntryMetrics( *pEntry );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplShowFocusRect()
+{
+ if ( mbHasFocusRect )
+ HideFocus();
+ ShowFocus( maFocusRect );
+ mbHasFocusRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplHideFocusRect()
+{
+ if ( mbHasFocusRect )
+ {
+ HideFocus();
+ mbHasFocusRect = FALSE;
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
+{
+ long nY = mnBorder;
+
+ USHORT nSelect = mnTop;
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
+ while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
+ {
+ nY += pEntry->mnHeight;
+ pEntry = mpEntryList->GetEntryPtr( ++nSelect );
+ }
+ if( pEntry == NULL )
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ return nSelect;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBoxWindow::IsVisible( USHORT i_nEntry ) const
+{
+ BOOL bRet = FALSE;
+
+ if( i_nEntry >= mnTop )
+ {
+ if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
+ PixelToLogic( GetSizePixel() ).Height() )
+ {
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetLastVisibleEntry() const
+{
+ USHORT nPos = mnTop;
+ long nWindowHeight = GetSizePixel().Height();
+ USHORT nCount = mpEntryList->GetEntryCount();
+ long nDiff;
+ for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
+ nPos++;
+
+ if( nDiff > nWindowHeight && nPos > mnTop )
+ nPos--;
+
+ if( nPos >= nCount )
+ nPos = nCount-1;
+
+ return nPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ mbMouseMoveSelect = FALSE; // Nur bis zum ersten MouseButtonDown
+ maSearchStr.Erase();
+
+ if ( !IsReadOnly() )
+ {
+ if( rMEvt.GetClicks() == 1 )
+ {
+ USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
+ if( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
+ else
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ mnCurrentPos = nSelect;
+ mbTrackingSelect = TRUE;
+ SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
+ mbTrackingSelect = FALSE;
+ if ( mbGrabFocus )
+ GrabFocus();
+
+ StartTracking( STARTTRACK_SCROLLREPEAT );
+ }
+ }
+ if( rMEvt.GetClicks() == 2 )
+ {
+ maDoubleClickHdl.Call( this );
+ }
+ }
+ else // if ( mbGrabFocus )
+ {
+ GrabFocus();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
+ {
+ if ( rMEvt.GetPosPixel().Y() < 0 )
+ {
+ DeselectAll();
+ mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
+ SetTopEntry( 0 );
+ if ( mbStackMode ) // #87072#, #92323#
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rMEvt.GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+
+ }
+ }
+ }
+ else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
+ {
+ Point aPoint;
+ Rectangle aRect( aPoint, GetOutputSizePixel() );
+ if( aRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ if ( IsMouseMoveSelect() )
+ {
+ USHORT nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
+ if( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ nSelect = mpEntryList->GetEntryCount() - 1;
+ nSelect = Min( nSelect, GetLastVisibleEntry() );
+ nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
+ // Select only visible Entries with MouseMove, otherwise Tracking...
+ if ( IsVisible( nSelect ) &&
+ mpEntryList->IsEntrySelectable( nSelect ) &&
+ ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
+ {
+ mbTrackingSelect = TRUE;
+ if ( SelectEntries( nSelect, LET_TRACKING, FALSE, FALSE ) )
+ {
+ if ( mbStackMode ) // #87072#
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rMEvt.GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ mbTrackingSelect = FALSE;
+ }
+ }
+
+ // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
+ // Maustaste in die ListBox faehrt...
+ if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
+ else
+ mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
+ mpEntryList->SetSelectionAnchor( 0 );
+
+ StartTracking( STARTTRACK_SCROLLREPEAT );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DeselectAll()
+{
+ while ( GetEntryList()->GetSelectEntryCount() )
+ {
+ USHORT nS = GetEntryList()->GetSelectEntryPos( 0 );
+ SelectEntry( nS, FALSE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
+ {
+ ImplHideFocusRect();
+ if( bSelect )
+ {
+ if( !mbMulti )
+ {
+ // Selektierten Eintrag deselektieren
+ USHORT nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
+ if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ //SelectEntryPos( nDeselect, FALSE );
+ GetEntryList()->SelectEntry( nDeselect, FALSE );
+ if ( IsUpdateMode() && IsReallyVisible() )
+ ImplPaint( nDeselect, TRUE );
+ }
+ }
+ mpEntryList->SelectEntry( nPos, TRUE );
+ mnCurrentPos = nPos;
+ if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
+ {
+ ImplPaint( nPos );
+ if ( !IsVisible( nPos ) )
+ {
+ ImplClearLayoutData();
+ USHORT nVisibleEntries = GetLastVisibleEntry()-mnTop;
+ if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
+ {
+ Resize();
+ ShowProminentEntry( nPos );
+ }
+ else
+ {
+ ShowProminentEntry( nPos );
+ }
+ }
+ }
+ }
+ else
+ {
+ mpEntryList->SelectEntry( nPos, FALSE );
+ ImplPaint( nPos, TRUE );
+ }
+ mbSelectionChanged = TRUE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBoxWindow::SelectEntries( USHORT nSelect, LB_EVENT_TYPE eLET, BOOL bShift, BOOL bCtrl )
+{
+ BOOL bFocusChanged = FALSE;
+ BOOL bSelectionChanged = FALSE;
+
+ if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
+ {
+ // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
+ if( !mbMulti )
+ {
+ USHORT nDeselect = mpEntryList->GetSelectEntryPos( 0 );
+ if( nSelect != nDeselect )
+ {
+ SelectEntry( nSelect, TRUE );
+ mpEntryList->SetLastSelected( nSelect );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ }
+ // MultiListBox ohne Modifier
+ else if( mbSimpleMode && !bCtrl && !bShift )
+ {
+ USHORT nEntryCount = mpEntryList->GetEntryCount();
+ for ( USHORT nPos = 0; nPos < nEntryCount; nPos++ )
+ {
+ BOOL bSelect = nPos == nSelect;
+ if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
+ {
+ SelectEntry( nPos, bSelect );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ }
+ mpEntryList->SetLastSelected( nSelect );
+ mpEntryList->SetSelectionAnchor( nSelect );
+ }
+ // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
+ else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
+ {
+ // Space fuer Selektionswechsel
+ if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
+ {
+ BOOL bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? TRUE : !mpEntryList->IsEntryPosSelected( nSelect );
+ if ( mbStackMode )
+ {
+ USHORT n;
+ if ( bSelect )
+ {
+ // All entries before nSelect must be selected...
+ for ( n = 0; n < nSelect; n++ )
+ SelectEntry( n, TRUE );
+ }
+ if ( !bSelect )
+ {
+ for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
+ SelectEntry( n, FALSE );
+ }
+ }
+ SelectEntry( nSelect, bSelect );
+ mpEntryList->SetLastSelected( nSelect );
+ mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
+ if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
+ mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
+ bFocusChanged = TRUE;
+ bSelectionChanged = TRUE;
+ }
+ else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
+ ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
+ {
+ mnCurrentPos = nSelect;
+ bFocusChanged = TRUE;
+
+ USHORT nAnchor = mpEntryList->GetSelectionAnchor();
+ if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
+ {
+ nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
+ }
+ if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
+ {
+ // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
+ USHORT nStart = Min( nSelect, nAnchor );
+ USHORT nEnd = Max( nSelect, nAnchor );
+ for ( USHORT n = nStart; n <= nEnd; n++ )
+ {
+ if ( !mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, TRUE );
+ bSelectionChanged = TRUE;
+ }
+ }
+
+ // Ggf. muss noch was deselektiert werden...
+ USHORT nLast = mpEntryList->GetLastSelected();
+ if ( nLast != LISTBOX_ENTRY_NOTFOUND )
+ {
+ if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
+ {
+ for ( USHORT n = nSelect+1; n <= nLast; n++ )
+ {
+ if ( mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, FALSE );
+ bSelectionChanged = TRUE;
+ }
+ }
+ }
+ else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
+ {
+ for ( USHORT n = nLast; n < nSelect; n++ )
+ {
+ if ( mpEntryList->IsEntryPosSelected( n ) )
+ {
+ SelectEntry( n, FALSE );
+ bSelectionChanged = TRUE;
+ }
+ }
+ }
+ }
+ mpEntryList->SetLastSelected( nSelect );
+ }
+ }
+ else if( eLET != LET_TRACKING )
+ {
+ ImplHideFocusRect();
+ ImplPaint( nSelect, TRUE );
+ bFocusChanged = TRUE;
+ }
+ }
+ else if( bShift )
+ {
+ bFocusChanged = TRUE;
+ }
+
+ if( bSelectionChanged )
+ mbSelectionChanged = TRUE;
+
+ if( bFocusChanged )
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(),
+ mpEntryList->GetEntryHeight( nSelect ) );
+ maFocusRect.SetSize( aSz );
+ if( HasFocus() )
+ ImplShowFocusRect();
+ }
+ ImplClearLayoutData();
+ }
+ return bSelectionChanged;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ Point aPoint;
+ Rectangle aRect( aPoint, GetOutputSizePixel() );
+ BOOL bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
+
+ if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
+ {
+ if ( bInside && !rTEvt.IsTrackingCanceled() )
+ {
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ }
+ else
+ {
+ maCancelHdl.Call( NULL );
+ if ( !mbMulti )
+ {
+ mbTrackingSelect = TRUE;
+ SelectEntry( mnTrackingSaveSelection, TRUE );
+ mbTrackingSelect = FALSE;
+ if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(),
+ mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ }
+ }
+ }
+
+ mbTrack = FALSE;
+ }
+ else
+ {
+ BOOL bTrackOrQuickClick = mbTrack;
+ if( !mbTrack )
+ {
+ if ( bInside )
+ {
+ mbTrack = TRUE;
+ }
+
+ // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
+ if( rTEvt.IsTrackingEnded() && mbTrack )
+ {
+ bTrackOrQuickClick = TRUE;
+ mbTrack = FALSE;
+ }
+ }
+
+ if( bTrackOrQuickClick )
+ {
+ MouseEvent aMEvt = rTEvt.GetMouseEvent();
+ Point aPt( aMEvt.GetPosPixel() );
+ BOOL bShift = aMEvt.IsShift();
+ BOOL bCtrl = aMEvt.IsMod1();
+
+ USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
+ if( aPt.Y() < 0 )
+ {
+ if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
+ if( nSelect < mnTop )
+ SetTopEntry( mnTop-1 );
+ }
+ }
+ else if( aPt.Y() > GetOutputSizePixel().Height() )
+ {
+ if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = Min( (USHORT)(mnCurrentPos+1), (USHORT)(mpEntryList->GetEntryCount()-1) );
+ if( nSelect >= GetLastVisibleEntry() )
+ SetTopEntry( mnTop+1 );
+ }
+ }
+ else
+ {
+ nSelect = (USHORT) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (USHORT) mnTop;
+ nSelect = Min( nSelect, GetLastVisibleEntry() );
+ nSelect = Min( nSelect, (USHORT) ( mpEntryList->GetEntryCount() - 1 ) );
+ }
+
+ if ( bInside )
+ {
+ if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
+ {
+ mbTrackingSelect = TRUE;
+ if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
+ {
+ if ( mbStackMode ) // #87734# (#87072#)
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ mbTrackingSelect = FALSE;
+ }
+ }
+ else
+ {
+ if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
+ {
+ mbTrackingSelect = TRUE;
+ SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), FALSE );
+ mbTrackingSelect = FALSE;
+ }
+ else if ( mbStackMode )
+ {
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 ) && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
+ {
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
+ {
+ BOOL bSelectionChanged = FALSE;
+ if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
+ && !mnCurrentPos )
+ {
+ if ( mpEntryList->IsEntryPosSelected( 0 ) )
+ {
+ SelectEntry( 0, FALSE );
+ bSelectionChanged = TRUE;
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ }
+ }
+ else
+ {
+ mbTrackingSelect = TRUE;
+ bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
+ mbTrackingSelect = FALSE;
+ }
+
+ if ( bSelectionChanged )
+ {
+ mbSelectionChanged = TRUE;
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+ }
+ }
+ }
+ mnCurrentPos = nSelect;
+ if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ ImplHideFocusRect();
+ }
+ else
+ {
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ }
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ if( !ProcessKeyInput( rKEvt ) )
+ Control::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+#define IMPL_SELECT_NODIRECTION 0
+#define IMPL_SELECT_UP 1
+#define IMPL_SELECT_DOWN 2
+
+BOOL ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
+{
+ // zu selektierender Eintrag
+ USHORT nSelect = LISTBOX_ENTRY_NOTFOUND;
+ LB_EVENT_TYPE eLET = LET_KEYMOVE;
+
+ KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ BOOL bShift = aKeyCode.IsShift();
+ BOOL bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
+ BOOL bMod2 = aKeyCode.IsMod2();
+ BOOL bDone = FALSE;
+
+ switch( aKeyCode.GetCode() )
+ {
+ case KEY_UP:
+ {
+ if ( IsReadOnly() )
+ {
+ if ( GetTopEntry() )
+ SetTopEntry( GetTopEntry()-1 );
+ }
+ else if ( !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( mnCurrentPos )
+ {
+ // search first selectable above the current position
+ nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
+ }
+
+ if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
+ SetTopEntry( mnTop-1 );
+
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_DOWN:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( GetTopEntry()+1 );
+ }
+ else if ( !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ // search first selectable below the current position
+ nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
+ }
+
+ if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
+ SetTopEntry( mnTop+1 );
+
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_PAGEUP:
+ {
+ if ( IsReadOnly() )
+ {
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
+ SetTopEntry( ( mnTop > nCurVis ) ?
+ (mnTop-nCurVis) : 0 );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( mnCurrentPos )
+ {
+ if( mnCurrentPos == mnTop )
+ {
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop +1;
+ SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
+ }
+
+ // find first selectable starting from mnTop looking foreward
+ nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_PAGEDOWN:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( GetLastVisibleEntry() );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ USHORT nCount = mpEntryList->GetEntryCount();
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop;
+ USHORT nTmp = Min( nCurVis, nCount );
+ nTmp += mnTop - 1;
+ if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
+ {
+ long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
+ nTmp2 = Max( (long)0 , nTmp2 );
+ nTmp = (USHORT)(nTmp2+(nCurVis-1) );
+ SetTopEntry( (USHORT)nTmp2 );
+ }
+ // find first selectable starting from nTmp looking backwards
+ nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( 0 );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if ( mnCurrentPos )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
+ if( mnTop != 0 )
+ SetTopEntry( 0 );
+
+ bDone = TRUE;
+ }
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_END:
+ {
+ if ( IsReadOnly() )
+ {
+ SetTopEntry( 0xFFFF );
+ }
+ else if ( !bCtrl && !bMod2 )
+ {
+ if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
+ {
+ nSelect = mpEntryList->FindFirstSelectable( 0, true );
+ }
+ else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
+ {
+ USHORT nCount = mpEntryList->GetEntryCount();
+ nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
+ USHORT nCurVis = GetLastVisibleEntry() - mnTop + 1;
+ if( nCount > nCurVis )
+ SetTopEntry( nCount - nCurVis );
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_LEFT:
+ {
+ if ( !bCtrl && !bMod2 )
+ {
+ ScrollHorz( -HORZ_SCROLL );
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_RIGHT:
+ {
+ if ( !bCtrl && !bMod2 )
+ {
+ ScrollHorz( HORZ_SCROLL );
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_RETURN:
+ {
+ if ( !bMod2 && !IsReadOnly() )
+ {
+ mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
+ ImplCallSelect();
+ bDone = FALSE; // RETURN nicht abfangen.
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_SPACE:
+ {
+ if ( !bMod2 && !IsReadOnly() )
+ {
+ if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
+ {
+ nSelect = mnCurrentPos;
+ eLET = LET_KEYSPACE;
+ }
+ bDone = TRUE;
+ }
+ maSearchStr.Erase();
+ }
+ break;
+
+ case KEY_A:
+ {
+ if( bCtrl && mbMulti )
+ {
+ // paint only once
+ BOOL bUpdates = IsUpdateMode();
+ SetUpdateMode( FALSE );
+
+ USHORT nEntryCount = mpEntryList->GetEntryCount();
+ for( USHORT i = 0; i < nEntryCount; i++ )
+ SelectEntry( i, TRUE );
+
+ // restore update mode
+ SetUpdateMode( bUpdates );
+ Invalidate();
+
+ maSearchStr.Erase();
+
+ bDone = TRUE;
+ break;
+ }
+ }
+ // fall through intentional
+ default:
+ {
+ xub_Unicode c = rKEvt.GetCharCode();
+
+ if ( !IsReadOnly() && (c >= 32) && (c != 127) && !rKEvt.GetKeyCode().IsMod2() )
+ {
+ maSearchStr += c;
+ XubString aTmpSearch( maSearchStr );
+
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos );
+ if ( (nSelect == LISTBOX_ENTRY_NOTFOUND) && (aTmpSearch.Len() > 1) )
+ {
+ // Wenn alles die gleichen Buchstaben, dann anderer Such-Modus
+ BOOL bAllEqual = TRUE;
+ for ( USHORT n = aTmpSearch.Len(); n && bAllEqual; )
+ bAllEqual = aTmpSearch.GetChar( --n ) == c;
+ if ( bAllEqual )
+ {
+ aTmpSearch = c;
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, mnCurrentPos+1 );
+ }
+ }
+ if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
+ nSelect = mpEntryList->FindMatchingEntry( aTmpSearch, 0 );
+
+ if ( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ {
+ ShowProminentEntry( nSelect );
+
+ if ( mpEntryList->IsEntryPosSelected( nSelect ) )
+ nSelect = LISTBOX_ENTRY_NOTFOUND;
+
+ maSearchTimeout.Start();
+ }
+ else
+ maSearchStr.Erase();
+ bDone = TRUE;
+ }
+ }
+ }
+
+ if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND )
+ && ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
+ || ( eLET == LET_KEYSPACE )
+ )
+ )
+ {
+ DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
+ if( nSelect >= mpEntryList->GetEntryCount() )
+ nSelect = mpEntryList->GetEntryCount()-1;
+ mnCurrentPos = nSelect;
+ if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
+ {
+ mbTravelSelect = TRUE;
+ mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
+ ImplCallSelect();
+ mbTravelSelect = FALSE;
+ }
+ }
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplPaint( USHORT nPos, BOOL bErase, bool bLayout )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
+ if( ! pEntry )
+ return;
+
+ long nWidth = GetOutputSizePixel().Width();
+ long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
+ Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
+
+ if( ! bLayout )
+ {
+ if( mpEntryList->IsEntryPosSelected( nPos ) )
+ {
+ SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
+ SetFillColor( rStyleSettings.GetHighlightColor() );
+ SetTextFillColor( rStyleSettings.GetHighlightColor() );
+ DrawRect( aRect );
+ }
+ else
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ if( !IsEnabled() )
+ SetTextColor( rStyleSettings.GetDisableColor() );
+ SetTextFillColor();
+ if( bErase )
+ Erase( aRect );
+ }
+ }
+
+ if ( IsUserDrawEnabled() )
+ {
+ mbInUserDraw = TRUE;
+ mnUserDrawEntry = nPos;
+ aRect.Left() -= mnLeft;
+ if ( nPos < GetEntryList()->GetMRUCount() )
+ nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
+ nPos = sal::static_int_cast<USHORT>(nPos - GetEntryList()->GetMRUCount());
+ UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
+ maUserDrawHdl.Call( &aUDEvt );
+ mbInUserDraw = FALSE;
+ }
+ else
+ {
+ DrawEntry( nPos, TRUE, TRUE, FALSE, bLayout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DrawEntry( USHORT nPos, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
+{
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
+ if( ! pEntry )
+ return;
+
+ // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
+
+ if ( mbInUserDraw )
+ nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
+
+ long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
+ Size aImgSz;
+
+ if( bDrawImage && mpEntryList->HasImages() && !bLayout )
+ {
+ Image aImage = mpEntryList->GetEntryImage( nPos );
+ if( !!aImage )
+ {
+ aImgSz = aImage.GetSizePixel();
+ Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
+
+ // pb: #106948# explicit mirroring for calc
+ if ( mbMirroring )
+ // right aligned
+ aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
+
+ if ( !IsZoom() )
+ {
+ DrawImage( aPtImg, aImage );
+ }
+ else
+ {
+ aImgSz.Width() = CalcZoom( aImgSz.Width() );
+ aImgSz.Height() = CalcZoom( aImgSz.Height() );
+ DrawImage( aPtImg, aImgSz, aImage );
+ }
+ }
+ }
+
+ if( bDrawText )
+ {
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ XubString aStr( mpEntryList->GetEntryText( nPos ) );
+ if ( aStr.Len() )
+ {
+ long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
+ GetOutputSizePixel().Width() - 2*mnBorder );
+ // a multiline entry should only be as wide a the window
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
+
+ Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
+ Size( nMaxWidth, pEntry->mnHeight ) );
+
+ if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
+ {
+ long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
+ aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
+ }
+
+ if( bLayout )
+ mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
+
+ // pb: #106948# explicit mirroring for calc
+ if ( mbMirroring )
+ {
+ // right aligned
+ aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
+ if ( aImgSz.Width() > 0 )
+ aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
+ }
+
+ USHORT nDrawStyle = ImplGetTextStyle();
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
+ nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
+ if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
+ nDrawStyle |= TEXT_DRAW_DISABLE;
+
+ DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
+ }
+ }
+
+ if( !bLayout )
+ {
+ if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
+ ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
+ {
+ Color aOldLineColor( GetLineColor() );
+ SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
+ Point aStartPos( 0, nY );
+ if ( nPos == mnSeparatorPos )
+ aStartPos.Y() += pEntry->mnHeight-1;
+ Point aEndPos( aStartPos );
+ aEndPos.X() = GetOutputSizePixel().Width();
+ DrawLine( aStartPos, aEndPos );
+ SetLineColor( aOldLineColor );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<ImplListBoxWindow*>(this)->
+ ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
+{
+ USHORT nCount = mpEntryList->GetEntryCount();
+
+ BOOL bShowFocusRect = mbHasFocusRect;
+ if ( mbHasFocusRect && ! bLayout )
+ ImplHideFocusRect();
+
+ long nY = 0; // + mnBorder;
+ long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
+
+ for( USHORT i = (USHORT)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
+ {
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
+ if( nY + pEntry->mnHeight >= rRect.Top() &&
+ nY <= rRect.Bottom() + mnMaxHeight )
+ {
+ ImplPaint( i, FALSE, bLayout );
+ }
+ nY += pEntry->mnHeight;
+ }
+
+ long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ if( HasFocus() && bShowFocusRect && !bLayout )
+ ImplShowFocusRect();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Paint( const Rectangle& rRect )
+{
+ ImplDoPaint( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::GetDisplayLineCount() const
+{
+ // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
+
+ USHORT nCount = mpEntryList->GetEntryCount();
+ long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
+ USHORT nEntries = static_cast< USHORT >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
+ if( nEntries > nCount-mnTop )
+ nEntries = nCount-mnTop;
+
+ return nEntries;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::Resize()
+{
+ Control::Resize();
+
+ BOOL bShowFocusRect = mbHasFocusRect;
+ if ( bShowFocusRect )
+ ImplHideFocusRect();
+
+ if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
+ {
+ Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
+ maFocusRect.SetSize( aSz );
+ }
+
+ if ( bShowFocusRect )
+ ImplShowFocusRect();
+
+ ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::GetFocus()
+{
+ USHORT nPos = mnCurrentPos;
+ if ( nPos == LISTBOX_ENTRY_NOTFOUND )
+ nPos = 0;
+ long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
+ maFocusRect.SetPos( Point( 0, nHeightDiff ) );
+ Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
+ maFocusRect.SetSize( aSz );
+ ImplShowFocusRect();
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::LoseFocus()
+{
+ ImplHideFocusRect();
+ Control::LoseFocus();
+}
+
+// -----------------------------------------------------------------------
+
+/*
+void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ if ( rHEvt.GetMode() & HELPMODE_BALLOON )
+ Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
+
+ Window::RequestHelp( rHEvt );
+}
+*/
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetTopEntry( USHORT nTop )
+{
+ if( mpEntryList->GetEntryCount() == 0 )
+ return;
+
+ long nWHeight = PixelToLogic( GetSizePixel() ).Height();
+
+ USHORT nLastEntry = mpEntryList->GetEntryCount()-1;
+ if( nTop > nLastEntry )
+ nTop = nLastEntry;
+ const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
+ while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
+ nTop--;
+
+ if ( nTop != mnTop )
+ {
+ ImplClearLayoutData();
+ long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
+ Update();
+ ImplHideFocusRect();
+ mnTop = nTop;
+ Scroll( 0, nDiff );
+ Update();
+ maFocusRect.Top() += nDiff;
+ maFocusRect.Bottom() += nDiff;
+ if( HasFocus() )
+ ImplShowFocusRect();
+ maScrollHdl.Call( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ShowProminentEntry( USHORT nEntryPos )
+{
+ if( meProminentType == PROMINENT_MIDDLE )
+ {
+ USHORT nPos = nEntryPos;
+ long nWHeight = PixelToLogic( GetSizePixel() ).Height();
+ while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
+ nEntryPos--;
+ }
+ SetTopEntry( nEntryPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::SetLeftIndent( long n )
+{
+ ScrollHorz( n - mnLeft );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::ScrollHorz( long n )
+{
+ long nDiff = 0;
+ if ( n > 0 )
+ {
+ long nWidth = GetOutputSizePixel().Width();
+ if( ( mnMaxWidth - mnLeft + n ) > nWidth )
+ nDiff = n;
+ }
+ else if ( n < 0 )
+ {
+ if( mnLeft )
+ {
+ long nAbs = -n;
+ nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
+ }
+ }
+
+ if ( nDiff )
+ {
+ ImplClearLayoutData();
+ mnLeft = sal::static_int_cast<USHORT>(mnLeft + nDiff);
+ Update();
+ ImplHideFocusRect();
+ Scroll( -nDiff, 0 );
+ Update();
+ if( HasFocus() )
+ ImplShowFocusRect();
+ maScrollHdl.Call( this );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplListBoxWindow::CalcSize( USHORT nMaxLines ) const
+{
+ // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
+
+ Size aSz;
+// USHORT nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
+ aSz.Height() = nMaxLines * mnMaxHeight;
+ aSz.Width() = mnMaxWidth + 2*mnBorder;
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle ImplListBoxWindow::GetBoundingRectangle( USHORT nItem ) const
+{
+ const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
+ Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
+ long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
+ Rectangle aRect( Point( 0, nY ), aSz );
+ return aRect;
+}
+
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::StateChanged( StateChangedType nType )
+{
+ Control::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_ZOOM )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_UPDATEMODE )
+ {
+ if ( IsUpdateMode() && IsReallyVisible() )
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ ImplClearLayoutData();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Control::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
+ (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
+ {
+ ImplClearLayoutData();
+ ImplInitSettings( TRUE, TRUE, TRUE );
+ ImplCalcMetrics();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBoxWindow::ImplGetTextStyle() const
+{
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+
+ if ( mpEntryList->HasImages() )
+ nTextStyle |= TEXT_DRAW_LEFT;
+ else if ( mbCenter )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( mbRight )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ return nTextStyle;
+}
+
+// =======================================================================
+
+ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
+ Control( pParent, nWinStyle ),
+ maLBWindow( this, nWinStyle&(~WB_BORDER) )
+{
+ // for native widget rendering we must be able to detect this window type
+ SetType( WINDOW_LISTBOXWINDOW );
+
+ mpVScrollBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
+ mpHScrollBar = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
+ mpScrollBarBox = new ScrollBarBox( this );
+
+ Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
+ mpVScrollBar->SetScrollHdl( aLink );
+ mpHScrollBar->SetScrollHdl( aLink );
+
+ mbVScroll = FALSE;
+ mbHScroll = FALSE;
+ mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL ) ? TRUE : FALSE;
+
+ maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
+ maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
+ maLBWindow.Show();
+}
+
+// -----------------------------------------------------------------------
+
+ImplListBox::~ImplListBox()
+{
+ delete mpHScrollBar;
+ delete mpVScrollBar;
+ delete mpScrollBarBox;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::Clear()
+{
+ maLBWindow.Clear();
+ if ( GetEntryList()->GetMRUCount() )
+ {
+ maLBWindow.GetEntryList()->SetMRUCount( 0 );
+ maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
+ }
+ mpVScrollBar->SetThumbPos( 0 );
+ mpHScrollBar->SetThumbPos( 0 );
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rStr );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const Image& rImage )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rImage );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT ImplListBox::InsertEntry( USHORT nPos, const XubString& rStr, const Image& rImage )
+{
+ ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
+ USHORT nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
+ StateChanged( STATE_CHANGE_DATA );
+ return nNewPos;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::RemoveEntry( USHORT nPos )
+{
+ maLBWindow.RemoveEntry( nPos );
+ StateChanged( STATE_CHANGE_DATA );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetEntryFlags( USHORT nPos, long nFlags )
+{
+ maLBWindow.SetEntryFlags( nPos, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBox::GetEntryFlags( USHORT nPos ) const
+{
+ return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SelectEntry( USHORT nPos, BOOL bSelect )
+{
+ maLBWindow.SelectEntry( nPos, bSelect );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetNoSelection()
+{
+ maLBWindow.DeselectAll();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::GetFocus()
+{
+ maLBWindow.GrabFocus();
+}
+
+// -----------------------------------------------------------------------
+
+Window* ImplListBox::GetPreferredKeyInputWindow()
+{
+ return &maLBWindow;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::Resize()
+{
+ Control::Resize();
+ ImplResizeControls();
+ ImplCheckScrollBars();
+}
+
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
+{
+ StateChanged( STATE_CHANGE_DATA );
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
+{
+ mpVScrollBar->SetThumbPos( GetTopEntry() );
+ mpHScrollBar->SetThumbPos( GetLeftIndent() );
+
+ maScrollHdl.Call( this );
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
+{
+ USHORT nPos = (USHORT) pSB->GetThumbPos();
+ if( pSB == mpVScrollBar )
+ SetTopEntry( nPos );
+ else if( pSB == mpHScrollBar )
+ SetLeftIndent( nPos );
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplCheckScrollBars()
+{
+ BOOL bArrange = FALSE;
+
+ Size aOutSz = GetOutputSizePixel();
+ USHORT nEntries = GetEntryList()->GetEntryCount();
+ USHORT nMaxVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
+
+ // vert. ScrollBar
+ if( nEntries > nMaxVisEntries )
+ {
+ if( !mbVScroll )
+ bArrange = TRUE;
+ mbVScroll = TRUE;
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
+ }
+ else
+ {
+ if( mbVScroll )
+ bArrange = TRUE;
+ mbVScroll = FALSE;
+ SetTopEntry( 0 );
+ }
+
+ // horz. ScrollBar
+ if( mbAutoHScroll )
+ {
+ long nWidth = (USHORT) aOutSz.Width();
+ if ( mbVScroll )
+ nWidth -= mpVScrollBar->GetSizePixel().Width();
+
+ long nMaxWidth = GetMaxEntryWidth();
+ if( nWidth < nMaxWidth )
+ {
+ if( !mbHScroll )
+ bArrange = TRUE;
+ mbHScroll = TRUE;
+
+ if ( !mbVScroll ) // ggf. brauchen wir jetzt doch einen
+ {
+ nMaxVisEntries = (USHORT) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
+ if( nEntries > nMaxVisEntries )
+ {
+ bArrange = TRUE;
+ mbVScroll = TRUE;
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ SetTopEntry( GetTopEntry() ); // MaxTop wird geprueft...
+ }
+ }
+
+ // Ueberpruefung des rausgescrollten Bereichs
+ USHORT nMaxLI = (USHORT) (nMaxWidth - nWidth);
+ if ( nMaxLI < GetLeftIndent() )
+ SetLeftIndent( nMaxLI );
+ }
+ else
+ {
+ if( mbHScroll )
+ bArrange = TRUE;
+ mbHScroll = FALSE;
+ SetLeftIndent( 0 );
+ }
+ }
+
+ if( bArrange )
+ ImplResizeControls();
+
+ ImplInitScrollBars();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplInitScrollBars()
+{
+ Size aOutSz = maLBWindow.GetOutputSizePixel();
+
+ if ( mbVScroll )
+ {
+ USHORT nEntries = GetEntryList()->GetEntryCount();
+ USHORT nVisEntries = (USHORT) (aOutSz.Height() / GetEntryHeight());
+ mpVScrollBar->SetRangeMax( nEntries );
+ mpVScrollBar->SetVisibleSize( nVisEntries );
+ mpVScrollBar->SetPageSize( nVisEntries - 1 );
+ }
+
+ if ( mbHScroll )
+ {
+ mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
+ mpHScrollBar->SetVisibleSize( (USHORT)aOutSz.Width() );
+ mpHScrollBar->SetLineSize( HORZ_SCROLL );
+ mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::ImplResizeControls()
+{
+ // Hier werden die Controls nur angeordnet, ob die Scrollbars
+ // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
+
+ Size aOutSz = GetOutputSizePixel();
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ nSBWidth = CalcZoom( nSBWidth );
+
+ Size aInnerSz( aOutSz );
+ if ( mbVScroll )
+ aInnerSz.Width() -= nSBWidth;
+ if ( mbHScroll )
+ aInnerSz.Height() -= nSBWidth;
+
+ // pb: #106948# explicit mirroring for calc
+ // Scrollbar on left or right side?
+ BOOL bMirroring = maLBWindow.IsMirroring();
+ Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
+ maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
+
+ // ScrollBarBox
+ if( mbVScroll && mbHScroll )
+ {
+ Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
+ mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
+ mpScrollBarBox->Show();
+ }
+ else
+ {
+ mpScrollBarBox->Hide();
+ }
+
+ // vert. ScrollBar
+ if( mbVScroll )
+ {
+ // Scrollbar on left or right side?
+ Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
+ mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
+ mpVScrollBar->Show();
+ }
+ else
+ {
+ mpVScrollBar->Hide();
+ // #107254# Don't reset top entry after resize, but check for max top entry
+ SetTopEntry( GetTopEntry() );
+ }
+
+ // horz. ScrollBar
+ if( mbHScroll )
+ {
+ Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
+ mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
+ mpHScrollBar->Show();
+ }
+ else
+ {
+ mpHScrollBar->Hide();
+ SetLeftIndent( 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::StateChanged( StateChangedType nType )
+{
+ if ( nType == STATE_CHANGE_INITSHOW )
+ {
+ ImplCheckScrollBars();
+ }
+ else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
+ {
+ BOOL bUpdate = IsUpdateMode();
+ maLBWindow.SetUpdateMode( bUpdate );
+// mpHScrollBar->SetUpdateMode( bUpdate );
+// mpVScrollBar->SetUpdateMode( bUpdate );
+ if ( bUpdate && IsReallyVisible() )
+ ImplCheckScrollBars();
+ }
+ else if( nType == STATE_CHANGE_ENABLE )
+ {
+ mpHScrollBar->Enable( IsEnabled() );
+ mpVScrollBar->Enable( IsEnabled() );
+ mpScrollBarBox->Enable( IsEnabled() );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ maLBWindow.SetZoom( GetZoom() );
+ Resize();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ maLBWindow.SetControlFont( GetControlFont() );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ maLBWindow.SetControlForeground( GetControlForeground() );
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ maLBWindow.SetControlBackground( GetControlBackground() );
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ maLBWindow.EnableRTL( IsRTLEnabled() );
+ mpHScrollBar->EnableRTL( IsRTLEnabled() );
+ mpVScrollBar->EnableRTL( IsRTLEnabled() );
+ ImplResizeControls();
+ }
+
+ Control::StateChanged( nType );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
+{
+// if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+// (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+// {
+// maLBWindow.SetSettings( GetSettings() );
+// Resize();
+// }
+// else
+ Control::DataChanged( rDCEvt );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBox::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+ nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
+ }
+ }
+ }
+
+ return nDone ? nDone : Window::Notify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+const Wallpaper& ImplListBox::GetDisplayBackground() const
+{
+ return maLBWindow.GetDisplayBackground();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
+{
+ BOOL bDone = FALSE;
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+ USHORT nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
+ KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
+ bDone = ProcessKeyInput( aKeyEvent );
+ }
+ }
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
+{
+ BOOL bChanges = GetEntryList()->GetMRUCount() ? TRUE : FALSE;
+
+ // Remove old MRU entries
+ for ( USHORT n = GetEntryList()->GetMRUCount();n; )
+ maLBWindow.RemoveEntry( --n );
+
+ USHORT nMRUCount = 0;
+ USHORT nEntries = rEntries.GetTokenCount( cSep );
+ for ( USHORT nEntry = 0; nEntry < nEntries; nEntry++ )
+ {
+ XubString aEntry = rEntries.GetToken( nEntry, cSep );
+ // Accept only existing entries
+ if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
+ {
+ ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
+ maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, FALSE );
+ bChanges = TRUE;
+ }
+ }
+
+ if ( bChanges )
+ {
+ maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
+ SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
+ StateChanged( STATE_CHANGE_DATA );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
+{
+ String aEntries;
+ for ( USHORT n = 0; n < GetEntryList()->GetMRUCount(); n++ )
+ {
+ aEntries += GetEntryList()->GetEntryText( n );
+ if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
+ aEntries += cSep;
+ }
+ return aEntries;
+}
+
+// =======================================================================
+
+ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
+ Control ( pParent, nWinStyle )
+{
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ SetBackground();
+ else
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
+
+ mbInUserDraw = FALSE;
+ mbUserDrawEnabled = FALSE;
+ mnItemPos = LISTBOX_ENTRY_NOTFOUND;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
+{
+ if( eMode == BMP_COLOR_NORMAL )
+ SetImage( rImage );
+ else if( eMode == BMP_COLOR_HIGHCONTRAST )
+ maImageHC = rImage;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
+{
+ if( eMode == BMP_COLOR_HIGHCONTRAST )
+ return maImageHC;
+ else
+ return maImage;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::MBDown()
+{
+ if( IsEnabled() )
+ maMBDownHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::MouseButtonDown( const MouseEvent& )
+{
+ if( IsEnabled() )
+ {
+// Control::MouseButtonDown( rMEvt );
+ MBDown();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::FillLayoutData() const
+{
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ const_cast<ImplWin*>(this)->ImplDraw( true );
+}
+
+// -----------------------------------------------------------------------
+
+long ImplWin::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
+ {
+ // trigger redraw as mouse over state has changed
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
+ {
+ GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
+ GetParent()->GetWindow( WINDOW_BORDER )->Update();
+ }
+ }
+ }
+
+ return nDone ? nDone : Control::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::ImplDraw( bool bLayout )
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ BOOL bNativeOK = FALSE;
+
+ if( ! bLayout )
+ {
+ ControlState nState = CTRL_STATE_ENABLED;
+ if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
+ && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
+ {
+ // Repaint the (focused) area similarly to
+ // ImplSmallBorderWindowView::DrawWindow() in
+ // vcl/source/window/brdwin.cxx
+ Window *pWin = GetParent();
+
+ ImplControlValue aControlValue;
+ if ( !pWin->IsEnabled() )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+
+ // The listbox is painted over the entire control including the
+ // border, but ImplWin does not contain the border => correction
+ // needed.
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ pWin->GetBorder( nLeft, nTop, nRight, nBottom );
+ Point aPoint( -nLeft, -nTop );
+ Region aCtrlRegion( Rectangle( aPoint - GetPosPixel(), pWin->GetSizePixel() ) );
+
+ BOOL bMouseOver = FALSE;
+ if( GetParent() )
+ {
+ Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
+ while( pChild && (bMouseOver = pChild->IsMouseOver()) == FALSE )
+ pChild = pChild->GetWindow( WINDOW_NEXT );
+ }
+
+ if( bMouseOver )
+ nState |= CTRL_STATE_ROLLOVER;
+
+ // if parent has no border, then nobody has drawn the background
+ // since no border window exists. so draw it here.
+ WinBits nParentStyle = pWin->GetStyle();
+ if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
+ {
+ Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
+ Region aParentReg( aParentRect );
+ pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentReg,
+ nState, aControlValue, rtl::OUString() );
+ }
+
+ bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+
+ if( IsEnabled() )
+ {
+ if( HasFocus() )
+ {
+ SetTextColor( rStyleSettings.GetHighlightTextColor() );
+ SetFillColor( rStyleSettings.GetHighlightColor() );
+ DrawRect( maFocusRect );
+ }
+ else
+ {
+ Color aColor;
+ if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
+ aColor = rStyleSettings.GetFieldRolloverTextColor();
+ else
+ aColor = rStyleSettings.GetFieldTextColor();
+ if( IsControlForeground() )
+ aColor = GetControlForeground();
+ SetTextColor( aColor );
+ if ( !bNativeOK )
+ Erase( maFocusRect );
+ }
+ }
+ else // Disabled
+ {
+ SetTextColor( rStyleSettings.GetDisableColor() );
+ if ( !bNativeOK )
+ Erase( maFocusRect );
+ }
+ }
+
+ if ( IsUserDrawEnabled() )
+ {
+ mbInUserDraw = TRUE;
+ UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
+ maUserDrawHdl.Call( &aUDEvt );
+ mbInUserDraw = FALSE;
+ }
+ else
+ {
+ DrawEntry( TRUE, TRUE, FALSE, bLayout );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::Paint( const Rectangle& )
+{
+ ImplDraw();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::DrawEntry( BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos, bool bLayout )
+{
+ long nBorder = 1;
+ Size aOutSz = GetOutputSizePixel();
+
+ BOOL bImage = !!maImage;
+ if( bDrawImage && bImage && !bLayout )
+ {
+ USHORT nStyle = 0;
+ Size aImgSz = maImage.GetSizePixel();
+ Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
+
+ // check for HC mode
+ Image *pImage = &maImage;
+
+ if( !!maImageHC )
+ {
+ if( GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pImage = &maImageHC;
+ }
+
+ if ( !IsZoom() )
+ {
+ DrawImage( aPtImg, *pImage, nStyle );
+ }
+ else
+ {
+ aImgSz.Width() = CalcZoom( aImgSz.Width() );
+ aImgSz.Height() = CalcZoom( aImgSz.Height() );
+ DrawImage( aPtImg, aImgSz, *pImage, nStyle );
+ }
+ }
+
+ if( bDrawText && maString.Len() )
+ {
+ USHORT nTextStyle = TEXT_DRAW_VCENTER;
+
+ if ( bDrawImage && bImage && !bLayout )
+ nTextStyle |= TEXT_DRAW_LEFT;
+ else if ( GetStyle() & WB_CENTER )
+ nTextStyle |= TEXT_DRAW_CENTER;
+ else if ( GetStyle() & WB_RIGHT )
+ nTextStyle |= TEXT_DRAW_RIGHT;
+ else
+ nTextStyle |= TEXT_DRAW_LEFT;
+
+ Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
+
+ if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
+ {
+ long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
+ aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
+ }
+
+ MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
+ String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
+ DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
+ }
+
+ if( HasFocus() && !bLayout )
+ ShowFocus( maFocusRect );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::Resize()
+{
+ Control::Resize();
+ maFocusRect.SetSize( GetOutputSizePixel() );
+ Invalidate();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::GetFocus()
+{
+ ShowFocus( maFocusRect );
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
+ {
+ Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
+ if( ! pWin )
+ pWin = GetParent();
+ pWin->Invalidate();
+ }
+ else
+ Invalidate();
+ Control::GetFocus();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWin::LoseFocus()
+{
+ HideFocus();
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
+ {
+ Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
+ if( ! pWin )
+ pWin = GetParent();
+ pWin->Invalidate();
+ }
+ else
+ Invalidate();
+ Control::LoseFocus();
+}
+
+// =======================================================================
+
+ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
+ PushButton( pParent, nWinStyle ),
+ mbDown ( FALSE )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBtn::MBDown()
+{
+ if( IsEnabled() )
+ maMBDownHdl.Call( this );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplBtn::MouseButtonDown( const MouseEvent& )
+{
+ //PushButton::MouseButtonDown( rMEvt );
+ if( IsEnabled() )
+ {
+ MBDown();
+ mbDown = TRUE;
+ }
+}
+
+// =======================================================================
+
+ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
+ FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
+{
+ mpImplLB = NULL;
+ mnDDLineCount = 0;
+ mbAutoWidth = FALSE;
+
+ mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
+
+ EnableSaveBackground();
+
+ Window * pBorderWindow = ImplGetBorderWindow();
+ if( pBorderWindow )
+ {
+ SetAccessibleRole(accessibility::AccessibleRole::PANEL);
+ pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
+ }
+ else
+ {
+ SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ if( rNEvt.GetType() == EVENT_LOSEFOCUS )
+ {
+ if( !GetParent()->HasChildPathFocus( TRUE ) )
+ EndPopupMode();
+ }
+
+ return FloatingWindow::PreNotify( rNEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
+
+ // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
+ // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
+ if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
+ {
+ Point aPos = GetParent()->GetPosPixel();
+ aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
+
+ if ( nFlags & WINDOW_POSSIZE_X )
+ aPos.X() = nX;
+
+ if ( nFlags & WINDOW_POSSIZE_Y )
+ aPos.Y() = nY;
+
+ USHORT nIndex;
+ SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
+ }
+
+// if( !IsReallyVisible() )
+ {
+ // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
+ // Die Fenster muessen aber ein Resize() erhalten, damit die
+ // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
+ // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
+ // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
+ // beruecksichtigt werden muss.
+ mpImplLB->SetSizePixel( GetOutputSizePixel() );
+ ((Window*)mpImplLB)->Resize();
+ ((Window*)mpImplLB->GetMainWindow())->Resize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::Resize()
+{
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ FloatingWindow::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+Size ImplListBoxFloatingWindow::CalcFloatSize()
+{
+ Size aFloatSz( maPrefSz );
+
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ GetBorder( nLeft, nTop, nRight, nBottom );
+
+ USHORT nLines = mpImplLB->GetEntryList()->GetEntryCount();
+ if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
+ nLines = mnDDLineCount;
+
+ Size aSz = mpImplLB->CalcSize( nLines );
+ long nMaxHeight = aSz.Height() + nTop + nBottom;
+
+ if ( mnDDLineCount )
+ aFloatSz.Height() = nMaxHeight;
+
+ if( mbAutoWidth )
+ {
+ // AutoSize erstmal nur fuer die Breite...
+
+ aFloatSz.Width() = aSz.Width() + nLeft + nRight;
+ aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
+
+ if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
+ {
+ // dann wird noch der vertikale Scrollbar benoetigt
+ long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
+ aFloatSz.Width() += nSBWidth;
+ }
+ }
+
+ if ( aFloatSz.Height() > nMaxHeight )
+ aFloatSz.Height() = nMaxHeight;
+
+ // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
+ // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
+ Size aParentSz = GetParent()->GetSizePixel();
+ if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
+ aFloatSz.Height() = aParentSz.Height();
+
+ // Nicht schmaler als der Parent werden...
+ if( aFloatSz.Width() < aParentSz.Width() )
+ aFloatSz.Width() = aParentSz.Width();
+
+ // Hoehe auf Entries alignen...
+ long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
+ long nEntryHeight = mpImplLB->GetEntryHeight();
+ if ( nInnerHeight % nEntryHeight )
+ {
+ nInnerHeight /= nEntryHeight;
+ nInnerHeight++;
+ nInnerHeight *= nEntryHeight;
+ aFloatSz.Height() = nInnerHeight + nTop + nBottom;
+ }
+
+ return aFloatSz;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplListBoxFloatingWindow::StartFloat( BOOL bStartTracking )
+{
+ if( !IsInPopupMode() )
+ {
+ Size aFloatSz = CalcFloatSize();
+
+ SetSizePixel( aFloatSz );
+ mpImplLB->SetSizePixel( GetOutputSizePixel() );
+
+ USHORT nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
+ mnPopupModeStartSaveSelection = nPos;
+
+ Size aSz = GetParent()->GetSizePixel();
+ Point aPos = GetParent()->GetPosPixel();
+ aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
+ // FIXME: this ugly hack is for Mac/Aqua
+ // should be replaced by a real mechanism to place the float rectangle
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ GetParent()->IsNativeWidgetEnabled() )
+ {
+ sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
+ aPos.X() += nLeft;
+ aPos.Y() += nTop;
+ aSz.Width() -= nLeft + nRight;
+ aSz.Height() -= nTop + nBottom;
+ }
+ Rectangle aRect( aPos, aSz );
+
+ // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
+ // where the document is unmirrored
+ // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
+ if( GetParent()->GetParent()->ImplIsAntiparallel() )
+ GetParent()->GetParent()->ImplReMirror( aRect );
+
+ StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
+
+ if( nPos != LISTBOX_ENTRY_NOTFOUND )
+ mpImplLB->ShowProminentEntry( nPos );
+
+ if( bStartTracking )
+ mpImplLB->GetMainWindow()->EnableMouseMoveSelect( TRUE );
+
+ if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
+ mpImplLB->GetMainWindow()->GrabFocus();
+
+ mpImplLB->GetMainWindow()->ImplClearLayoutData();
+ }
+}