xref: /trunk/main/vcl/source/control/ilstbox.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <tools/debug.hxx>
32 
33 #include <vcl/svapp.hxx>
34 #include <vcl/settings.hxx>
35 #include <vcl/event.hxx>
36 #include <vcl/scrbar.hxx>
37 #include <vcl/help.hxx>
38 #include <vcl/lstbox.h>
39 #include <vcl/unohelp.hxx>
40 #include <vcl/i18nhelp.hxx>
41 
42 #include <ilstbox.hxx>
43 #include <controldata.hxx>
44 #include <svdata.hxx>
45 
46 #include <com/sun/star/i18n/XCollator.hpp>
47 #include <com/sun/star/accessibility/XAccessible.hpp>
48 #include <com/sun/star/accessibility/AccessibleRole.hpp>
49 
50 #define MULTILINE_ENTRY_DRAW_FLAGS ( TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_VCENTER )
51 
52 using namespace ::com::sun::star;
53 
54 // =======================================================================
55 
56 void ImplInitFieldSettings( Window* pWin, sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
57 {
58     const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
59 
60     if ( bFont )
61     {
62         Font aFont = rStyleSettings.GetFieldFont();
63         if ( pWin->IsControlFont() )
64             aFont.Merge( pWin->GetControlFont() );
65         pWin->SetZoomedPointFont( aFont );
66     }
67 
68     if ( bFont || bForeground )
69     {
70         Color aTextColor = rStyleSettings.GetFieldTextColor();
71         if ( pWin->IsControlForeground() )
72             aTextColor = pWin->GetControlForeground();
73         pWin->SetTextColor( aTextColor );
74     }
75 
76     if ( bBackground )
77     {
78         if( pWin->IsControlBackground() )
79             pWin->SetBackground( pWin->GetControlBackground() );
80         else
81             pWin->SetBackground( rStyleSettings.GetFieldColor() );
82     }
83 }
84 
85 // -----------------------------------------------------------------------
86 
87 void ImplInitDropDownButton( PushButton* pButton )
88 {
89     if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
90         pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
91     else
92         pButton->SetSymbol( SYMBOL_SPIN_DOWN );
93 
94     if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
95             && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
96         pButton->SetBackground();
97 }
98 
99 // =======================================================================
100 
101 ImplEntryList::ImplEntryList( Window* pWindow )
102 {
103     mpWindow = pWindow;
104     mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
105     mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
106     mnImages = 0;
107     mbCallSelectionChangedHdl = sal_True;
108 
109     mnMRUCount = 0;
110     mnMaxMRUCount = 0;
111 }
112 
113 // -----------------------------------------------------------------------
114 
115 ImplEntryList::~ImplEntryList()
116 {
117     Clear();
118 }
119 
120 // -----------------------------------------------------------------------
121 
122 void ImplEntryList::Clear()
123 {
124     mnImages = 0;
125     for ( sal_uInt16 n = GetEntryCount(); n; )
126     {
127         ImplEntryType* pImplEntry = GetEntry( --n );
128         delete pImplEntry;
129     }
130     List::Clear();
131 }
132 
133 // -----------------------------------------------------------------------
134 
135 void ImplEntryList::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
136 {
137     ImplEntryType* pImplEntry = GetEntry( nPos );
138     if ( pImplEntry &&
139        ( pImplEntry->mbIsSelected != bSelect ) &&
140        ( (pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0  ) )
141     {
142         pImplEntry->mbIsSelected = bSelect;
143         if ( mbCallSelectionChangedHdl )
144             maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
145     }
146 }
147 
148 // -----------------------------------------------------------------------
149 
150 uno::Reference< i18n::XCollator > ImplGetCollator (lang::Locale &rLocale)
151 {
152     static uno::Reference< i18n::XCollator > xCollator;
153     if ( !xCollator.is() )
154         xCollator = vcl::unohelper::CreateCollator();
155     if( xCollator.is() )
156         xCollator->loadDefaultCollator (rLocale, 0);
157 
158     return xCollator;
159 }
160 
161 sal_uInt16 ImplEntryList::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry, sal_Bool bSort )
162 {
163     if ( !!pNewEntry->maImage )
164         mnImages++;
165 
166     if ( !bSort || !Count() )
167     {
168         Insert( pNewEntry, nPos );
169     }
170     else
171     {
172         lang::Locale aLocale = Application::GetSettings().GetLocale();
173         uno::Reference< i18n::XCollator > xCollator = ImplGetCollator(aLocale);
174 
175         const XubString& rStr = pNewEntry->maStr;
176         sal_uLong nLow, nHigh, nMid;
177 
178         nHigh = Count();
179 
180         ImplEntryType* pTemp = GetEntry( (sal_uInt16)(nHigh-1) );
181 
182         try
183         {
184             // XXX even though XCollator::compareString returns a sal_Int32 the only
185             // defined values are {-1, 0, 1} which is compatible with StringCompare
186             StringCompare eComp = xCollator.is() ?
187                 (StringCompare)xCollator->compareString (rStr, pTemp->maStr)
188                 : COMPARE_EQUAL;
189 
190             // Schnelles Einfuegen bei sortierten Daten
191             if ( eComp != COMPARE_LESS )
192             {
193                 Insert( pNewEntry, LIST_APPEND );
194             }
195             else
196             {
197                 nLow  = mnMRUCount;
198                 pTemp = (ImplEntryType*)GetEntry( (sal_uInt16)nLow );
199 
200                 eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
201                 if ( eComp != COMPARE_GREATER )
202                 {
203                     Insert( pNewEntry, (sal_uLong)0 );
204                 }
205                 else
206                 {
207                     // Binaeres Suchen
208                     nHigh--;
209                     do
210                     {
211                         nMid = (nLow + nHigh) / 2;
212                         pTemp = (ImplEntryType*)GetObject( nMid );
213 
214                         eComp = (StringCompare)xCollator->compareString (rStr, pTemp->maStr);
215 
216                         if ( eComp == COMPARE_LESS )
217                             nHigh = nMid-1;
218                         else
219                         {
220                             if ( eComp == COMPARE_GREATER )
221                                 nLow = nMid + 1;
222                             else
223                                 break;
224                         }
225                     }
226                     while ( nLow <= nHigh );
227 
228                     if ( eComp != COMPARE_LESS )
229                         nMid++;
230 
231                     Insert( pNewEntry, nMid );
232                 }
233             }
234         }
235         catch (uno::RuntimeException& )
236         {
237             // XXX this is arguable, if the exception occured because pNewEntry is
238             // garbage you wouldn't insert it. If the exception occured because the
239             // Collator implementation is garbage then give the user a chance to see
240             // his stuff
241             Insert( pNewEntry, (sal_uLong)0 );
242         }
243 
244     }
245 
246     return (sal_uInt16)GetPos( pNewEntry );
247 }
248 
249 // -----------------------------------------------------------------------
250 
251 void ImplEntryList::RemoveEntry( sal_uInt16 nPos )
252 {
253     ImplEntryType* pImplEntry = (ImplEntryType*)List::Remove( nPos );
254     if ( pImplEntry )
255     {
256         if ( !!pImplEntry->maImage )
257             mnImages--;
258 
259         delete pImplEntry;
260     }
261 }
262 
263 // -----------------------------------------------------------------------
264 
265 sal_uInt16 ImplEntryList::FindEntry( const XubString& rString, sal_Bool bSearchMRUArea ) const
266 {
267     sal_uInt16 nEntries = GetEntryCount();
268     for ( sal_uInt16 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
269     {
270         ImplEntryType* pImplEntry = GetEntry( n );
271         String aComp( vcl::I18nHelper::filterFormattingChars( pImplEntry->maStr ) );
272         if ( aComp == rString )
273             return n;
274     }
275     return LISTBOX_ENTRY_NOTFOUND;
276 }
277 
278     // -----------------------------------------------------------------------
279 
280 sal_uInt16 ImplEntryList::FindMatchingEntry( const XubString& rStr, sal_uInt16 nStart, sal_Bool bForward, sal_Bool bLazy ) const
281 {
282     sal_uInt16  nPos = LISTBOX_ENTRY_NOTFOUND;
283     sal_uInt16  nEntryCount = GetEntryCount();
284     if ( !bForward )
285         nStart++;   // wird sofort dekrementiert
286 
287     const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
288     for ( sal_uInt16 n = nStart; bForward ? ( n < nEntryCount ) : n; )
289     {
290         if ( !bForward )
291             n--;
292 
293         ImplEntryType* pImplEntry = GetEntry( n );
294         sal_Bool bMatch = bLazy ? rI18nHelper.MatchString( rStr, pImplEntry->maStr ) != 0 : ( rStr.Match( pImplEntry->maStr ) == STRING_MATCH );
295         if ( bMatch )
296         {
297             nPos = n;
298             break;
299         }
300 
301         if ( bForward )
302             n++;
303     }
304 
305     return nPos;
306 }
307 
308 // -----------------------------------------------------------------------
309 
310 sal_uInt16 ImplEntryList::FindEntry( const void* pData ) const
311 {
312     sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
313     for ( sal_uInt16 n = GetEntryCount(); n; )
314     {
315         ImplEntryType* pImplEntry = GetEntry( --n );
316         if ( pImplEntry->mpUserData == pData )
317         {
318             nPos = n;
319             break;
320         }
321     }
322     return nPos;
323 }
324 
325 // -----------------------------------------------------------------------
326 
327 long ImplEntryList::GetAddedHeight( sal_uInt16 i_nEndIndex, sal_uInt16 i_nBeginIndex, long i_nBeginHeight ) const
328 {
329     long nHeight = i_nBeginHeight;
330     sal_uInt16 nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
331     sal_uInt16 nStop  = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
332     sal_uInt16 nEntryCount = GetEntryCount();
333     if( nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
334     {
335         // sanity check
336         if( nStop > nEntryCount-1 )
337             nStop = nEntryCount-1;
338         if( nStart > nEntryCount-1 )
339             nStart = nEntryCount-1;
340 
341         sal_uInt16 nIndex = nStart;
342         while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
343         {
344             nHeight += GetEntryPtr( nIndex )-> mnHeight;
345             nIndex++;
346         }
347     }
348     else
349         nHeight = 0;
350     return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
351 }
352 
353 // -----------------------------------------------------------------------
354 
355 long ImplEntryList::GetEntryHeight( sal_uInt16 nPos ) const
356 {
357     ImplEntryType* pImplEntry = GetEntry( nPos );
358     return pImplEntry ? pImplEntry->mnHeight : 0;
359 }
360 
361 // -----------------------------------------------------------------------
362 
363 XubString ImplEntryList::GetEntryText( sal_uInt16 nPos ) const
364 {
365     XubString aEntryText;
366     ImplEntryType* pImplEntry = GetEntry( nPos );
367     if ( pImplEntry )
368         aEntryText = pImplEntry->maStr;
369     return aEntryText;
370 }
371 
372 // -----------------------------------------------------------------------
373 
374 sal_Bool ImplEntryList::HasEntryImage( sal_uInt16 nPos ) const
375 {
376     sal_Bool bImage = sal_False;
377     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
378     if ( pImplEntry )
379         bImage = !!pImplEntry->maImage;
380     return bImage;
381 }
382 
383 // -----------------------------------------------------------------------
384 
385 Image ImplEntryList::GetEntryImage( sal_uInt16 nPos ) const
386 {
387     Image aImage;
388     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
389     if ( pImplEntry )
390         aImage = pImplEntry->maImage;
391     return aImage;
392 }
393 
394 // -----------------------------------------------------------------------
395 
396 void ImplEntryList::SetEntryData( sal_uInt16 nPos, void* pNewData )
397 {
398     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
399     if ( pImplEntry )
400         pImplEntry->mpUserData = pNewData;
401 }
402 
403 // -----------------------------------------------------------------------
404 
405 void* ImplEntryList::GetEntryData( sal_uInt16 nPos ) const
406 {
407     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
408     return pImplEntry ? pImplEntry->mpUserData : NULL;
409 }
410 
411 // -----------------------------------------------------------------------
412 
413 void ImplEntryList::SetEntryFlags( sal_uInt16 nPos, long nFlags )
414 {
415     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
416     if ( pImplEntry )
417         pImplEntry->mnFlags = nFlags;
418 }
419 
420 // -----------------------------------------------------------------------
421 
422 long ImplEntryList::GetEntryFlags( sal_uInt16 nPos ) const
423 {
424     ImplEntryType* pImplEntry = (ImplEntryType*)List::GetObject( nPos );
425     return pImplEntry ? pImplEntry->mnFlags : 0;
426 }
427 
428 // -----------------------------------------------------------------------
429 
430 sal_uInt16 ImplEntryList::GetSelectEntryCount() const
431 {
432     sal_uInt16 nSelCount = 0;
433     for ( sal_uInt16 n = GetEntryCount(); n; )
434     {
435         ImplEntryType* pImplEntry = GetEntry( --n );
436         if ( pImplEntry->mbIsSelected )
437             nSelCount++;
438     }
439     return nSelCount;
440 }
441 
442 // -----------------------------------------------------------------------
443 
444 XubString ImplEntryList::GetSelectEntry( sal_uInt16 nIndex ) const
445 {
446     return GetEntryText( GetSelectEntryPos( nIndex ) );
447 }
448 
449 // -----------------------------------------------------------------------
450 
451 sal_uInt16 ImplEntryList::GetSelectEntryPos( sal_uInt16 nIndex ) const
452 {
453     sal_uInt16 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
454     sal_uInt16 nSel = 0;
455     sal_uInt16 nEntryCount = GetEntryCount();
456 
457     for ( sal_uInt16 n = 0; n < nEntryCount; n++ )
458     {
459         ImplEntryType* pImplEntry = GetEntry( n );
460         if ( pImplEntry->mbIsSelected )
461         {
462             if ( nSel == nIndex )
463             {
464                 nSelEntryPos = n;
465                 break;
466             }
467             nSel++;
468         }
469     }
470 
471     return nSelEntryPos;
472 }
473 
474 // -----------------------------------------------------------------------
475 
476 sal_Bool ImplEntryList::IsEntrySelected( const XubString& rStr ) const
477 {
478     return IsEntryPosSelected( FindEntry( rStr ) );
479 }
480 
481 // -----------------------------------------------------------------------
482 
483 sal_Bool ImplEntryList::IsEntryPosSelected( sal_uInt16 nIndex ) const
484 {
485     ImplEntryType* pImplEntry = GetEntry( nIndex );
486     return pImplEntry ? pImplEntry->mbIsSelected : sal_False;
487 }
488 
489 // -----------------------------------------------------------------------
490 
491 bool ImplEntryList::IsEntrySelectable( sal_uInt16 nPos ) const
492 {
493     ImplEntryType* pImplEntry = GetEntry( nPos );
494     return pImplEntry ? ((pImplEntry->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0) : true;
495 }
496 
497 // -----------------------------------------------------------------------
498 
499 sal_uInt16 ImplEntryList::FindFirstSelectable( sal_uInt16 nPos, bool bForward /* = true */ )
500 {
501     if( IsEntrySelectable( nPos ) )
502         return nPos;
503 
504     if( bForward )
505     {
506         for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
507         {
508             if( IsEntrySelectable( nPos ) )
509                 return nPos;
510         }
511     }
512     else
513     {
514         while( nPos )
515         {
516             nPos--;
517             if( IsEntrySelectable( nPos ) )
518                 return nPos;
519         }
520     }
521 
522     return LISTBOX_ENTRY_NOTFOUND;
523 }
524 
525 // =======================================================================
526 
527 ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
528     Control( pParent, 0 ),
529     maQuickSelectionEngine( *this )
530 {
531     mpEntryList         = new ImplEntryList( this );
532 
533     mnTop               = 0;
534     mnLeft              = 0;
535     mnBorder            = 1;
536     mnSelectModifier    = 0;
537     mnUserDrawEntry     = LISTBOX_ENTRY_NOTFOUND;
538     mbTrack             = sal_False;
539     mbImgsDiffSz        = sal_False;
540     mbTravelSelect      = sal_False;
541     mbTrackingSelect    = sal_False;
542     mbSelectionChanged  = sal_False;
543     mbMouseMoveSelect   = sal_False;
544     mbMulti             = sal_False;
545     mbStackMode         = sal_False;
546     mbGrabFocus         = sal_False;
547     mbUserDrawEnabled   = sal_False;
548     mbInUserDraw        = sal_False;
549     mbReadOnly          = sal_False;
550     mbHasFocusRect      = sal_False;
551     mbRight             = ( nWinStyle & WB_RIGHT )      ? sal_True : sal_False;
552     mbCenter            = ( nWinStyle & WB_CENTER )     ? sal_True : sal_False;
553     mbSimpleMode        = ( nWinStyle & WB_SIMPLEMODE ) ? sal_True : sal_False;
554     mbSort              = ( nWinStyle & WB_SORT )       ? sal_True : sal_False;
555 
556     // pb: #106948# explicit mirroring for calc
557     mbMirroring         = sal_False;
558 
559     mnCurrentPos            = LISTBOX_ENTRY_NOTFOUND;
560     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
561     mnSeparatorPos          = LISTBOX_ENTRY_NOTFOUND;
562     meProminentType         = PROMINENT_TOP;
563 
564     SetLineColor();
565     SetTextFillColor();
566     SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
567 
568     ImplInitSettings( sal_True, sal_True, sal_True );
569     ImplCalcMetrics();
570 }
571 
572 // -----------------------------------------------------------------------
573 
574 ImplListBoxWindow::~ImplListBoxWindow()
575 {
576     delete mpEntryList;
577 }
578 
579 // -----------------------------------------------------------------------
580 
581 void ImplListBoxWindow::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
582 {
583     ImplInitFieldSettings( this, bFont, bForeground, bBackground );
584 }
585 
586 // -----------------------------------------------------------------------
587 
588 void ImplListBoxWindow::ImplCalcMetrics()
589 {
590     mnMaxWidth      = 0;
591     mnMaxTxtWidth   = 0;
592     mnMaxImgWidth   = 0;
593     mnMaxImgTxtWidth= 0;
594     mnMaxImgHeight  = 0;
595 
596     mnTextHeight = (sal_uInt16)GetTextHeight();
597     mnMaxTxtHeight = mnTextHeight + mnBorder;
598     mnMaxHeight = mnMaxTxtHeight;
599 
600     if ( maUserItemSize.Height() > mnMaxHeight )
601         mnMaxHeight = (sal_uInt16) maUserItemSize.Height();
602     if ( maUserItemSize.Width() > mnMaxWidth )
603         mnMaxWidth= (sal_uInt16) maUserItemSize.Width();
604 
605     for ( sal_uInt16 n = mpEntryList->GetEntryCount(); n; )
606     {
607         ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
608         ImplUpdateEntryMetrics( *pEntry );
609     }
610 
611     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
612     {
613         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
614         maFocusRect.SetSize( aSz );
615     }
616 }
617 
618 // -----------------------------------------------------------------------
619 
620 void ImplListBoxWindow::Clear()
621 {
622     mpEntryList->Clear();
623 
624     mnMaxHeight     = mnMaxTxtHeight;
625     mnMaxWidth      = 0;
626     mnMaxTxtWidth   = 0;
627     mnMaxImgTxtWidth= 0;
628     mnMaxImgWidth   = 0;
629     mnMaxImgHeight  = 0;
630     mnTop           = 0;
631     mnLeft          = 0;
632     mbImgsDiffSz    = sal_False;
633     ImplClearLayoutData();
634 
635     mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
636     maQuickSelectionEngine.Reset();
637 
638     Invalidate();
639 }
640 
641 void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
642 {
643     ImplClearLayoutData();
644     maUserItemSize = rSz;
645     ImplCalcMetrics();
646 }
647 
648 // -----------------------------------------------------------------------
649 
650 struct ImplEntryMetrics
651 {
652     sal_Bool    bText;
653     sal_Bool    bImage;
654     long    nEntryWidth;
655     long    nEntryHeight;
656     long    nTextWidth;
657     long    nImgWidth;
658     long    nImgHeight;
659 };
660 
661 // -----------------------------------------------------------------------
662 
663 void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
664 {
665     ImplEntryMetrics aMetrics;
666     aMetrics.bText = rEntry.maStr.Len() ? sal_True : sal_False;
667     aMetrics.bImage = !!rEntry.maImage;
668     aMetrics.nEntryWidth = 0;
669     aMetrics.nEntryHeight = 0;
670     aMetrics.nTextWidth = 0;
671     aMetrics.nImgWidth = 0;
672     aMetrics.nImgHeight = 0;
673 
674     if ( aMetrics.bText )
675     {
676         if( (rEntry.mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
677         {
678             // multiline case
679             Size aCurSize( PixelToLogic( GetSizePixel() ) );
680             // set the current size to a large number
681             // GetTextRect should shrink it to the actual size
682             aCurSize.Height() = 0x7fffff;
683             Rectangle aTextRect( Point( 0, 0 ), aCurSize );
684             aTextRect = GetTextRect( aTextRect, rEntry.maStr, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
685             aMetrics.nTextWidth = aTextRect.GetWidth();
686             if( aMetrics.nTextWidth > mnMaxTxtWidth )
687                 mnMaxTxtWidth = aMetrics.nTextWidth;
688             aMetrics.nEntryWidth = mnMaxTxtWidth;
689             aMetrics.nEntryHeight = aTextRect.GetHeight() + mnBorder;
690         }
691         else
692         {
693             // normal single line case
694             aMetrics.nTextWidth = (sal_uInt16)GetTextWidth( rEntry.maStr );
695             if( aMetrics.nTextWidth > mnMaxTxtWidth )
696                 mnMaxTxtWidth = aMetrics.nTextWidth;
697             aMetrics.nEntryWidth = mnMaxTxtWidth;
698             aMetrics.nEntryHeight = mnTextHeight + mnBorder;
699         }
700     }
701     if ( aMetrics.bImage )
702     {
703         Size aImgSz = rEntry.maImage.GetSizePixel();
704         aMetrics.nImgWidth  = (sal_uInt16) CalcZoom( aImgSz.Width() );
705         aMetrics.nImgHeight = (sal_uInt16) CalcZoom( aImgSz.Height() );
706 
707         if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
708             mbImgsDiffSz = sal_True;
709         else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
710             mbImgsDiffSz = sal_True;
711 
712         if( aMetrics.nImgWidth > mnMaxImgWidth )
713             mnMaxImgWidth = aMetrics.nImgWidth;
714         if( aMetrics.nImgHeight > mnMaxImgHeight )
715             mnMaxImgHeight = aMetrics.nImgHeight;
716 
717         mnMaxImgTxtWidth = Max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
718         aMetrics.nEntryHeight = Max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
719 
720     }
721     if ( IsUserDrawEnabled() || aMetrics.bImage )
722     {
723         aMetrics.nEntryWidth = Max( aMetrics.nImgWidth, maUserItemSize.Width() );
724         if ( aMetrics.bText )
725             aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
726         aMetrics.nEntryHeight = Max( Max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
727                                      aMetrics.nEntryHeight );
728     }
729 
730     if ( !aMetrics.bText && !aMetrics.bImage && !IsUserDrawEnabled() )
731     {
732         // entries which have no (aka an empty) text, and no image, and are not user-drawn, should be
733         // shown nonetheless
734         aMetrics.nEntryHeight = mnTextHeight + mnBorder;
735     }
736 
737     if ( aMetrics.nEntryWidth > mnMaxWidth )
738         mnMaxWidth = aMetrics.nEntryWidth;
739     if ( aMetrics.nEntryHeight > mnMaxHeight )
740         mnMaxHeight = aMetrics.nEntryHeight;
741 
742     rEntry.mnHeight = aMetrics.nEntryHeight;
743 }
744 
745 // -----------------------------------------------------------------------
746 
747 void ImplListBoxWindow::ImplCallSelect()
748 {
749     if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
750     {
751         // Insert the selected entry as MRU, if not allready first MRU
752         sal_uInt16 nSelected = GetEntryList()->GetSelectEntryPos( 0 );
753         sal_uInt16 nMRUCount = GetEntryList()->GetMRUCount();
754         String aSelected = GetEntryList()->GetEntryText( nSelected );
755         sal_uInt16 nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, sal_True );
756         if ( nFirstMatchingEntryPos || !nMRUCount )
757         {
758             sal_Bool bSelectNewEntry = sal_False;
759             if ( nFirstMatchingEntryPos < nMRUCount )
760             {
761                 RemoveEntry( nFirstMatchingEntryPos );
762                 nMRUCount--;
763                 if ( nFirstMatchingEntryPos == nSelected )
764                     bSelectNewEntry = sal_True;
765             }
766             else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
767             {
768                 RemoveEntry( nMRUCount - 1 );
769                 nMRUCount--;
770             }
771 
772             ImplClearLayoutData();
773 
774             ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
775             pNewEntry->mbIsSelected = bSelectNewEntry;
776             GetEntryList()->InsertEntry( 0, pNewEntry, sal_False );
777             ImplUpdateEntryMetrics( *pNewEntry );
778             GetEntryList()->SetMRUCount( ++nMRUCount );
779             SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
780             maMRUChangedHdl.Call( NULL );
781         }
782     }
783 
784     maSelectHdl.Call( NULL );
785     mbSelectionChanged = sal_False;
786 }
787 
788 // -----------------------------------------------------------------------
789 
790 sal_uInt16 ImplListBoxWindow::InsertEntry( sal_uInt16 nPos, ImplEntryType* pNewEntry )
791 {
792     ImplClearLayoutData();
793     sal_uInt16 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
794 
795     if( (GetStyle() & WB_WORDBREAK) )
796         pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
797 
798     ImplUpdateEntryMetrics( *pNewEntry );
799     return nNewPos;
800 }
801 
802 // -----------------------------------------------------------------------
803 
804 void ImplListBoxWindow::RemoveEntry( sal_uInt16 nPos )
805 {
806     ImplClearLayoutData();
807     mpEntryList->RemoveEntry( nPos );
808     if( mnCurrentPos >= mpEntryList->GetEntryCount() )
809         mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
810     ImplCalcMetrics();
811 }
812 
813 // -----------------------------------------------------------------------
814 
815 void ImplListBoxWindow::SetEntryFlags( sal_uInt16 nPos, long nFlags )
816 {
817     mpEntryList->SetEntryFlags( nPos, nFlags );
818     ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
819     if( pEntry )
820         ImplUpdateEntryMetrics( *pEntry );
821 }
822 
823 // -----------------------------------------------------------------------
824 
825 void ImplListBoxWindow::ImplShowFocusRect()
826 {
827     if ( mbHasFocusRect )
828         HideFocus();
829     ShowFocus( maFocusRect );
830     mbHasFocusRect = sal_True;
831 }
832 
833 // -----------------------------------------------------------------------
834 
835 void ImplListBoxWindow::ImplHideFocusRect()
836 {
837     if ( mbHasFocusRect )
838     {
839         HideFocus();
840         mbHasFocusRect = sal_False;
841     }
842 }
843 
844 
845 // -----------------------------------------------------------------------
846 
847 sal_uInt16 ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
848 {
849     long nY = mnBorder;
850 
851     sal_uInt16 nSelect = mnTop;
852     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
853     while( pEntry && rPoint.Y() > pEntry->mnHeight + nY )
854     {
855         nY += pEntry->mnHeight;
856         pEntry = mpEntryList->GetEntryPtr( ++nSelect );
857     }
858     if( pEntry == NULL )
859         nSelect = LISTBOX_ENTRY_NOTFOUND;
860 
861     return nSelect;
862 }
863 
864 // -----------------------------------------------------------------------
865 
866 sal_Bool ImplListBoxWindow::IsVisible( sal_uInt16 i_nEntry ) const
867 {
868     sal_Bool bRet = sal_False;
869 
870     if( i_nEntry >= mnTop )
871     {
872         if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
873             PixelToLogic( GetSizePixel() ).Height() )
874         {
875             bRet = sal_True;
876         }
877     }
878 
879     return bRet;
880 }
881 
882 // -----------------------------------------------------------------------
883 
884 sal_uInt16 ImplListBoxWindow::GetLastVisibleEntry() const
885 {
886     sal_uInt16 nPos = mnTop;
887     long nWindowHeight = GetSizePixel().Height();
888     sal_uInt16 nCount = mpEntryList->GetEntryCount();
889     long nDiff;
890     for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
891         nPos++;
892 
893     if( nDiff > nWindowHeight && nPos > mnTop )
894         nPos--;
895 
896     if( nPos >= nCount )
897         nPos = nCount-1;
898 
899     return nPos;
900 }
901 
902 // -----------------------------------------------------------------------
903 
904 void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
905 {
906     mbMouseMoveSelect = sal_False;  // Nur bis zum ersten MouseButtonDown
907     maQuickSelectionEngine.Reset();
908 
909     if ( !IsReadOnly() )
910     {
911         if( rMEvt.GetClicks() == 1 )
912         {
913             sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
914             if( nSelect != LISTBOX_ENTRY_NOTFOUND )
915             {
916                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
917                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
918                 else
919                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
920 
921                 mnCurrentPos = nSelect;
922                 mbTrackingSelect = sal_True;
923                 SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
924                 mbTrackingSelect = sal_False;
925                 if ( mbGrabFocus )
926                     GrabFocus();
927 
928                 StartTracking( STARTTRACK_SCROLLREPEAT );
929             }
930         }
931         if( rMEvt.GetClicks() == 2 )
932         {
933             maDoubleClickHdl.Call( this );
934         }
935     }
936     else // if ( mbGrabFocus )
937     {
938         GrabFocus();
939     }
940 }
941 
942 // -----------------------------------------------------------------------
943 
944 void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
945 {
946     if ( rMEvt.IsLeaveWindow() )
947     {
948         if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
949         {
950             if ( rMEvt.GetPosPixel().Y() < 0 )
951             {
952                 DeselectAll();
953                 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
954                 SetTopEntry( 0 );
955                 if ( mbStackMode ) // #87072#, #92323#
956                 {
957                     mbTravelSelect = sal_True;
958                     mnSelectModifier = rMEvt.GetModifier();
959                     ImplCallSelect();
960                     mbTravelSelect = sal_False;
961                 }
962 
963             }
964         }
965     }
966     else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
967     {
968         Point aPoint;
969         Rectangle aRect( aPoint, GetOutputSizePixel() );
970         if( aRect.IsInside( rMEvt.GetPosPixel() ) )
971         {
972             if ( IsMouseMoveSelect() )
973             {
974                 sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
975                 if( nSelect == LISTBOX_ENTRY_NOTFOUND )
976                     nSelect = mpEntryList->GetEntryCount() - 1;
977                 nSelect = Min( nSelect, GetLastVisibleEntry() );
978                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
979                 // Select only visible Entries with MouseMove, otherwise Tracking...
980                 if ( IsVisible( nSelect ) &&
981                     mpEntryList->IsEntrySelectable( nSelect ) &&
982                     ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
983                 {
984                     mbTrackingSelect = sal_True;
985                     if ( SelectEntries( nSelect, LET_TRACKING, sal_False, sal_False ) )
986                     {
987                         if ( mbStackMode ) // #87072#
988                         {
989                             mbTravelSelect = sal_True;
990                             mnSelectModifier = rMEvt.GetModifier();
991                             ImplCallSelect();
992                             mbTravelSelect = sal_False;
993                         }
994                     }
995                     mbTrackingSelect = sal_False;
996                 }
997             }
998 
999             // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
1000             // Maustaste in die ListBox faehrt...
1001             if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
1002             {
1003                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1004                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
1005                 else
1006                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
1007 
1008                 if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
1009                     mpEntryList->SetSelectionAnchor( 0 );
1010 
1011                 StartTracking( STARTTRACK_SCROLLREPEAT );
1012             }
1013         }
1014     }
1015 }
1016 
1017 // -----------------------------------------------------------------------
1018 
1019 void ImplListBoxWindow::DeselectAll()
1020 {
1021     while ( GetEntryList()->GetSelectEntryCount() )
1022     {
1023         sal_uInt16 nS = GetEntryList()->GetSelectEntryPos( 0 );
1024         SelectEntry( nS, sal_False );
1025     }
1026 }
1027 
1028 // -----------------------------------------------------------------------
1029 
1030 void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
1031 {
1032     if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
1033     {
1034         ImplHideFocusRect();
1035         if( bSelect )
1036         {
1037             if( !mbMulti )
1038             {
1039                 // Selektierten Eintrag deselektieren
1040                 sal_uInt16 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
1041                 if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
1042                 {
1043                     //SelectEntryPos( nDeselect, sal_False );
1044                     GetEntryList()->SelectEntry( nDeselect, sal_False );
1045                     if ( IsUpdateMode() && IsReallyVisible() )
1046                         ImplPaint( nDeselect, sal_True );
1047                 }
1048             }
1049             mpEntryList->SelectEntry( nPos, sal_True );
1050             mnCurrentPos = nPos;
1051             if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
1052             {
1053                 ImplPaint( nPos );
1054                 if ( !IsVisible( nPos ) )
1055                 {
1056                     ImplClearLayoutData();
1057                     sal_uInt16 nVisibleEntries = GetLastVisibleEntry()-mnTop;
1058                     if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1059                     {
1060                         Resize();
1061                         ShowProminentEntry( nPos );
1062                     }
1063                     else
1064                     {
1065                         ShowProminentEntry( nPos );
1066                     }
1067                 }
1068             }
1069         }
1070         else
1071         {
1072             mpEntryList->SelectEntry( nPos, sal_False );
1073             ImplPaint( nPos, sal_True );
1074         }
1075         mbSelectionChanged = sal_True;
1076     }
1077 }
1078 
1079 // -----------------------------------------------------------------------
1080 
1081 sal_Bool ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect, LB_EVENT_TYPE eLET, sal_Bool bShift, sal_Bool bCtrl )
1082 {
1083     sal_Bool bFocusChanged = sal_False;
1084     sal_Bool bSelectionChanged = sal_False;
1085 
1086     if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1087     {
1088         // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
1089         if( !mbMulti )
1090         {
1091             sal_uInt16 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1092             if( nSelect != nDeselect )
1093             {
1094                 SelectEntry( nSelect, sal_True );
1095                 mpEntryList->SetLastSelected( nSelect );
1096                 bFocusChanged = sal_True;
1097                 bSelectionChanged = sal_True;
1098             }
1099         }
1100         // MultiListBox ohne Modifier
1101         else if( mbSimpleMode && !bCtrl && !bShift )
1102         {
1103             sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1104             for ( sal_uInt16 nPos = 0; nPos < nEntryCount; nPos++ )
1105             {
1106                 sal_Bool bSelect = nPos == nSelect;
1107                 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1108                 {
1109                     SelectEntry( nPos, bSelect );
1110                     bFocusChanged = sal_True;
1111                     bSelectionChanged = sal_True;
1112                 }
1113             }
1114             mpEntryList->SetLastSelected( nSelect );
1115             mpEntryList->SetSelectionAnchor( nSelect );
1116         }
1117         // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
1118         else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1119         {
1120             // Space fuer Selektionswechsel
1121             if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1122             {
1123                 sal_Bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? sal_True : !mpEntryList->IsEntryPosSelected( nSelect );
1124                 if ( mbStackMode )
1125                 {
1126                     sal_uInt16 n;
1127                     if ( bSelect )
1128                     {
1129                         // All entries before nSelect must be selected...
1130                         for ( n = 0; n < nSelect; n++ )
1131                             SelectEntry( n, sal_True );
1132                     }
1133                     if ( !bSelect )
1134                     {
1135                         for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1136                             SelectEntry( n, sal_False );
1137                     }
1138                 }
1139                 SelectEntry( nSelect, bSelect );
1140                 mpEntryList->SetLastSelected( nSelect );
1141                 mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
1142                 if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1143                     mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
1144                 bFocusChanged = sal_True;
1145                 bSelectionChanged = sal_True;
1146             }
1147             else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1148                      ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1149             {
1150                 mnCurrentPos = nSelect;
1151                 bFocusChanged = sal_True;
1152 
1153                 sal_uInt16 nAnchor = mpEntryList->GetSelectionAnchor();
1154                 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1155                 {
1156                     nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1157                 }
1158                 if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1159                 {
1160                     // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
1161                     sal_uInt16 nStart = Min( nSelect, nAnchor );
1162                     sal_uInt16 nEnd = Max( nSelect, nAnchor );
1163                     for ( sal_uInt16 n = nStart; n <= nEnd; n++ )
1164                     {
1165                         if ( !mpEntryList->IsEntryPosSelected( n ) )
1166                         {
1167                             SelectEntry( n, sal_True );
1168                             bSelectionChanged = sal_True;
1169                         }
1170                     }
1171 
1172                     // Ggf. muss noch was deselektiert werden...
1173                     sal_uInt16 nLast = mpEntryList->GetLastSelected();
1174                     if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1175                     {
1176                         if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1177                         {
1178                             for ( sal_uInt16 n = nSelect+1; n <= nLast; n++ )
1179                             {
1180                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1181                                 {
1182                                     SelectEntry( n, sal_False );
1183                                     bSelectionChanged = sal_True;
1184                                 }
1185                             }
1186                         }
1187                         else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1188                         {
1189                             for ( sal_uInt16 n = nLast; n < nSelect; n++ )
1190                             {
1191                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1192                                 {
1193                                     SelectEntry( n, sal_False );
1194                                     bSelectionChanged = sal_True;
1195                                 }
1196                             }
1197                         }
1198                     }
1199                     mpEntryList->SetLastSelected( nSelect );
1200                 }
1201             }
1202             else if( eLET != LET_TRACKING )
1203             {
1204                 ImplHideFocusRect();
1205                 ImplPaint( nSelect, sal_True );
1206                 bFocusChanged = sal_True;
1207             }
1208         }
1209         else if( bShift )
1210         {
1211             bFocusChanged = sal_True;
1212         }
1213 
1214         if( bSelectionChanged )
1215             mbSelectionChanged = sal_True;
1216 
1217         if( bFocusChanged )
1218         {
1219             long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
1220             maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1221             Size aSz( maFocusRect.GetWidth(),
1222                       mpEntryList->GetEntryHeight( nSelect ) );
1223             maFocusRect.SetSize( aSz );
1224             if( HasFocus() )
1225                 ImplShowFocusRect();
1226         }
1227         ImplClearLayoutData();
1228     }
1229     return bSelectionChanged;
1230 }
1231 
1232 // -----------------------------------------------------------------------
1233 
1234 void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1235 {
1236     Point aPoint;
1237     Rectangle aRect( aPoint, GetOutputSizePixel() );
1238     sal_Bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1239 
1240     if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1241     {
1242         if ( bInside && !rTEvt.IsTrackingCanceled() )
1243         {
1244             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1245             ImplCallSelect();
1246         }
1247         else
1248         {
1249             maCancelHdl.Call( NULL );
1250             if ( !mbMulti )
1251             {
1252                 mbTrackingSelect = sal_True;
1253                 SelectEntry( mnTrackingSaveSelection, sal_True );
1254                 mbTrackingSelect = sal_False;
1255                 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1256                 {
1257                     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1258                     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1259                     Size aSz( maFocusRect.GetWidth(),
1260                               mpEntryList->GetEntryHeight( mnCurrentPos ) );
1261                     maFocusRect.SetSize( aSz );
1262                     ImplShowFocusRect();
1263                 }
1264             }
1265         }
1266 
1267         mbTrack = sal_False;
1268     }
1269     else
1270     {
1271         sal_Bool bTrackOrQuickClick = mbTrack;
1272         if( !mbTrack )
1273         {
1274             if ( bInside )
1275             {
1276                 mbTrack = sal_True;
1277             }
1278 
1279             // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
1280             if( rTEvt.IsTrackingEnded() && mbTrack )
1281             {
1282                 bTrackOrQuickClick = sal_True;
1283                 mbTrack = sal_False;
1284             }
1285         }
1286 
1287         if( bTrackOrQuickClick )
1288         {
1289             MouseEvent aMEvt = rTEvt.GetMouseEvent();
1290             Point aPt( aMEvt.GetPosPixel() );
1291             sal_Bool bShift = aMEvt.IsShift();
1292             sal_Bool bCtrl  = aMEvt.IsMod1();
1293 
1294             sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1295             if( aPt.Y() < 0 )
1296             {
1297                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1298                 {
1299                     nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1300                     if( nSelect < mnTop )
1301                         SetTopEntry( mnTop-1 );
1302                 }
1303             }
1304             else if( aPt.Y() > GetOutputSizePixel().Height() )
1305             {
1306                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1307                 {
1308                     nSelect = Min(  (sal_uInt16)(mnCurrentPos+1), (sal_uInt16)(mpEntryList->GetEntryCount()-1) );
1309                     if( nSelect >= GetLastVisibleEntry() )
1310                         SetTopEntry( mnTop+1 );
1311                 }
1312             }
1313             else
1314             {
1315                 nSelect = (sal_uInt16) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_uInt16) mnTop;
1316                 nSelect = Min( nSelect, GetLastVisibleEntry() );
1317                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
1318             }
1319 
1320             if ( bInside )
1321             {
1322                 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1323                 {
1324                     mbTrackingSelect = sal_True;
1325                     if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1326                     {
1327                         if ( mbStackMode ) // #87734# (#87072#)
1328                         {
1329                             mbTravelSelect = sal_True;
1330                             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1331                             ImplCallSelect();
1332                             mbTravelSelect = sal_False;
1333                         }
1334                     }
1335                     mbTrackingSelect = sal_False;
1336                 }
1337             }
1338             else
1339             {
1340                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1341                 {
1342                     mbTrackingSelect = sal_True;
1343                     SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False );
1344                     mbTrackingSelect = sal_False;
1345                 }
1346                 else if ( mbStackMode )
1347                 {
1348                     if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 )  && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1349                     {
1350                         if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1351                         {
1352                             sal_Bool bSelectionChanged = sal_False;
1353                             if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1354                                    && !mnCurrentPos )
1355                             {
1356                                 if ( mpEntryList->IsEntryPosSelected( 0 ) )
1357                                 {
1358                                     SelectEntry( 0, sal_False );
1359                                     bSelectionChanged = sal_True;
1360                                     nSelect = LISTBOX_ENTRY_NOTFOUND;
1361 
1362                                 }
1363                             }
1364                             else
1365                             {
1366                                 mbTrackingSelect = sal_True;
1367                                 bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1368                                 mbTrackingSelect = sal_False;
1369                             }
1370 
1371                             if ( bSelectionChanged )
1372                             {
1373                                 mbSelectionChanged = sal_True;
1374                                 mbTravelSelect = sal_True;
1375                                 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1376                                 ImplCallSelect();
1377                                 mbTravelSelect = sal_False;
1378                             }
1379                         }
1380                     }
1381                 }
1382             }
1383             mnCurrentPos = nSelect;
1384             if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1385             {
1386                 ImplHideFocusRect();
1387             }
1388             else
1389             {
1390                 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1391                 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1392                 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1393                 maFocusRect.SetSize( aSz );
1394                 ImplShowFocusRect();
1395             }
1396         }
1397     }
1398 }
1399 
1400 
1401 // -----------------------------------------------------------------------
1402 
1403 void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1404 {
1405     if( !ProcessKeyInput( rKEvt ) )
1406         Control::KeyInput( rKEvt );
1407 }
1408 
1409 // -----------------------------------------------------------------------
1410 
1411 #define IMPL_SELECT_NODIRECTION 0
1412 #define IMPL_SELECT_UP          1
1413 #define IMPL_SELECT_DOWN        2
1414 
1415 sal_Bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1416 {
1417     // zu selektierender Eintrag
1418     sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1419     LB_EVENT_TYPE eLET = LET_KEYMOVE;
1420 
1421     KeyCode aKeyCode = rKEvt.GetKeyCode();
1422 
1423     sal_Bool bShift = aKeyCode.IsShift();
1424     sal_Bool bCtrl  = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1425     sal_Bool bMod2 = aKeyCode.IsMod2();
1426     sal_Bool bDone = sal_False;
1427 
1428     switch( aKeyCode.GetCode() )
1429     {
1430         case KEY_UP:
1431         {
1432             if ( IsReadOnly() )
1433             {
1434                 if ( GetTopEntry() )
1435                     SetTopEntry( GetTopEntry()-1 );
1436             }
1437             else if ( !bMod2 )
1438             {
1439                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1440                 {
1441                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1442                 }
1443                 else if ( mnCurrentPos )
1444                 {
1445                     // search first selectable above the current position
1446                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1447                 }
1448 
1449                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1450                     SetTopEntry( mnTop-1 );
1451 
1452                 bDone = sal_True;
1453             }
1454             maQuickSelectionEngine.Reset();
1455         }
1456         break;
1457 
1458         case KEY_DOWN:
1459         {
1460             if ( IsReadOnly() )
1461             {
1462                 SetTopEntry( GetTopEntry()+1 );
1463             }
1464             else if ( !bMod2 )
1465             {
1466                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1467                 {
1468                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1469                 }
1470                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1471                 {
1472                     // search first selectable below the current position
1473                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1474                 }
1475 
1476                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1477                     SetTopEntry( mnTop+1 );
1478 
1479                 bDone = sal_True;
1480             }
1481             maQuickSelectionEngine.Reset();
1482         }
1483         break;
1484 
1485         case KEY_PAGEUP:
1486         {
1487             if ( IsReadOnly() )
1488             {
1489                 sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1490                 SetTopEntry( ( mnTop > nCurVis ) ?
1491                                 (mnTop-nCurVis) : 0 );
1492             }
1493             else if ( !bCtrl && !bMod2 )
1494             {
1495                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1496                 {
1497                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1498                 }
1499                 else if ( mnCurrentPos )
1500                 {
1501                     if( mnCurrentPos == mnTop )
1502                     {
1503                         sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1504                         SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1505                     }
1506 
1507                     // find first selectable starting from mnTop looking foreward
1508                     nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1509                 }
1510                 bDone = sal_True;
1511             }
1512             maQuickSelectionEngine.Reset();
1513         }
1514         break;
1515 
1516         case KEY_PAGEDOWN:
1517         {
1518             if ( IsReadOnly() )
1519             {
1520                 SetTopEntry( GetLastVisibleEntry() );
1521             }
1522             else if ( !bCtrl && !bMod2 )
1523             {
1524                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1525                 {
1526                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1527                 }
1528                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1529                 {
1530                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1531                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop;
1532                     sal_uInt16 nTmp = Min( nCurVis, nCount );
1533                     nTmp += mnTop - 1;
1534                     if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1535                     {
1536                         long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1537                         nTmp2 = Max( (long)0 , nTmp2 );
1538                         nTmp = (sal_uInt16)(nTmp2+(nCurVis-1) );
1539                         SetTopEntry( (sal_uInt16)nTmp2 );
1540                     }
1541                     // find first selectable starting from nTmp looking backwards
1542                     nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1543                 }
1544                 bDone = sal_True;
1545             }
1546             maQuickSelectionEngine.Reset();
1547         }
1548         break;
1549 
1550         case KEY_HOME:
1551         {
1552             if ( IsReadOnly() )
1553             {
1554                 SetTopEntry( 0 );
1555             }
1556             else if ( !bCtrl && !bMod2 )
1557             {
1558                 if ( mnCurrentPos )
1559                 {
1560                     nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1561                     if( mnTop != 0 )
1562                         SetTopEntry( 0 );
1563 
1564                     bDone = sal_True;
1565                 }
1566             }
1567             maQuickSelectionEngine.Reset();
1568         }
1569         break;
1570 
1571         case KEY_END:
1572         {
1573             if ( IsReadOnly() )
1574             {
1575                 SetTopEntry( 0xFFFF );
1576             }
1577             else if ( !bCtrl && !bMod2 )
1578             {
1579                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1580                 {
1581                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1582                 }
1583                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1584                 {
1585                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1586                     nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1587                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1588                     if( nCount > nCurVis )
1589                         SetTopEntry( nCount - nCurVis );
1590                 }
1591                 bDone = sal_True;
1592             }
1593             maQuickSelectionEngine.Reset();
1594         }
1595         break;
1596 
1597         case KEY_LEFT:
1598         {
1599             if ( !bCtrl && !bMod2 )
1600             {
1601                 ScrollHorz( -HORZ_SCROLL );
1602                 bDone = sal_True;
1603             }
1604             maQuickSelectionEngine.Reset();
1605         }
1606         break;
1607 
1608         case KEY_RIGHT:
1609         {
1610             if ( !bCtrl && !bMod2 )
1611             {
1612                 ScrollHorz( HORZ_SCROLL );
1613                 bDone = sal_True;
1614             }
1615             maQuickSelectionEngine.Reset();
1616         }
1617         break;
1618 
1619         case KEY_RETURN:
1620         {
1621             if ( !bMod2 && !IsReadOnly() )
1622             {
1623                 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1624                 ImplCallSelect();
1625                 bDone = sal_False;  // RETURN nicht abfangen.
1626             }
1627             maQuickSelectionEngine.Reset();
1628         }
1629         break;
1630 
1631         case KEY_SPACE:
1632         {
1633             if ( !bMod2 && !IsReadOnly() )
1634             {
1635                 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1636                 {
1637                     nSelect = mnCurrentPos;
1638                     eLET = LET_KEYSPACE;
1639                 }
1640                 bDone = sal_True;
1641             }
1642             maQuickSelectionEngine.Reset();
1643         }
1644         break;
1645 
1646         case KEY_A:
1647         {
1648             if( bCtrl && mbMulti )
1649             {
1650                 // paint only once
1651                 sal_Bool bUpdates = IsUpdateMode();
1652                 SetUpdateMode( sal_False );
1653 
1654                 sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1655                 for( sal_uInt16 i = 0; i < nEntryCount; i++ )
1656                     SelectEntry( i, sal_True );
1657 
1658                 // restore update mode
1659                 SetUpdateMode( bUpdates );
1660                 Invalidate();
1661 
1662                 maQuickSelectionEngine.Reset();
1663 
1664                 bDone = sal_True;
1665                 break;
1666             }
1667         }
1668         // fall through intentional
1669         default:
1670         {
1671             if ( !IsReadOnly() )
1672             {
1673                 bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1674             }
1675         }
1676         break;
1677     }
1678 
1679     if  (   ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1680         &&  (   ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1681             ||  ( eLET == LET_KEYSPACE )
1682             )
1683         )
1684     {
1685         DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1686         if( nSelect >= mpEntryList->GetEntryCount() )
1687             nSelect = mpEntryList->GetEntryCount()-1;
1688         mnCurrentPos = nSelect;
1689         if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
1690         {
1691             mbTravelSelect = sal_True;
1692             mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1693             ImplCallSelect();
1694             mbTravelSelect = sal_False;
1695         }
1696     }
1697 
1698     return bDone;
1699 }
1700 
1701 // -----------------------------------------------------------------------
1702 namespace
1703 {
1704     static ::vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_uInt16 _nPos, String& _out_entryText )
1705     {
1706         OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
1707         sal_uInt16 nEntryCount( _rList.GetEntryCount() );
1708         if ( _nPos >= nEntryCount )
1709             _nPos = 0;
1710         _out_entryText = _rList.GetEntryText( _nPos );
1711 
1712         // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1713         // => normalize
1714         return reinterpret_cast< ::vcl::StringEntryIdentifier >( _nPos + 1 );
1715     }
1716 
1717     static sal_uInt16 lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry )
1718     {
1719         // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1720         return static_cast< sal_uInt16 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1721     }
1722 }
1723 
1724 // -----------------------------------------------------------------------
1725 ::vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( String& _out_entryText ) const
1726 {
1727     return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos + 1, _out_entryText );
1728 }
1729 
1730 // -----------------------------------------------------------------------
1731 ::vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
1732 {
1733     sal_uInt16 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1734     return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1735 }
1736 
1737 // -----------------------------------------------------------------------
1738 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1739 {
1740     sal_uInt16 nSelect = lcl_getEntryPos( _entry );
1741     if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1742     {
1743         // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1744         // to select the given entry by typing its starting letters. No need to act.
1745         return;
1746     }
1747 
1748     // normalize
1749     OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1750     if( nSelect >= mpEntryList->GetEntryCount() )
1751         nSelect = mpEntryList->GetEntryCount()-1;
1752 
1753     // make visible
1754     ShowProminentEntry( nSelect );
1755 
1756     // actually select
1757     mnCurrentPos = nSelect;
1758     if ( SelectEntries( nSelect, LET_KEYMOVE, sal_False, sal_False ) )
1759     {
1760         mbTravelSelect = sal_True;
1761         mnSelectModifier = 0;
1762         ImplCallSelect();
1763         mbTravelSelect = sal_False;
1764     }
1765 }
1766 
1767 // -----------------------------------------------------------------------
1768 
1769 void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos, sal_Bool bErase, bool bLayout )
1770 {
1771     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1772 
1773     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1774     if( ! pEntry )
1775         return;
1776 
1777     long nWidth  = GetOutputSizePixel().Width();
1778     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1779     Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1780 
1781     if( ! bLayout )
1782     {
1783         if( mpEntryList->IsEntryPosSelected( nPos ) )
1784         {
1785             SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1786             SetFillColor( rStyleSettings.GetHighlightColor() );
1787             SetTextFillColor( rStyleSettings.GetHighlightColor() );
1788             DrawRect( aRect );
1789         }
1790         else
1791         {
1792             ImplInitSettings( sal_False, sal_True, sal_False );
1793             if( !IsEnabled() )
1794                 SetTextColor( rStyleSettings.GetDisableColor() );
1795             SetTextFillColor();
1796             if( bErase )
1797                 Erase( aRect );
1798         }
1799     }
1800 
1801     if ( IsUserDrawEnabled() )
1802     {
1803         mbInUserDraw = sal_True;
1804         mnUserDrawEntry = nPos;
1805         aRect.Left() -= mnLeft;
1806         if ( nPos < GetEntryList()->GetMRUCount() )
1807             nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1808         nPos = sal::static_int_cast<sal_uInt16>(nPos - GetEntryList()->GetMRUCount());
1809         UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
1810         maUserDrawHdl.Call( &aUDEvt );
1811         mbInUserDraw = sal_False;
1812     }
1813     else
1814     {
1815         DrawEntry( nPos, sal_True, sal_True, sal_False, bLayout );
1816     }
1817 }
1818 
1819 // -----------------------------------------------------------------------
1820 
1821 void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
1822 {
1823     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1824     if( ! pEntry )
1825         return;
1826 
1827     // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
1828 
1829     if ( mbInUserDraw )
1830         nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1831 
1832     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1833     Size aImgSz;
1834 
1835     if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1836     {
1837         Image aImage = mpEntryList->GetEntryImage( nPos );
1838         if( !!aImage )
1839         {
1840             aImgSz = aImage.GetSizePixel();
1841             Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1842 
1843             // pb: #106948# explicit mirroring for calc
1844             if ( mbMirroring )
1845                 // right aligned
1846                 aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1847 
1848             if ( !IsZoom() )
1849             {
1850                 DrawImage( aPtImg, aImage );
1851             }
1852             else
1853             {
1854                 aImgSz.Width() = CalcZoom( aImgSz.Width() );
1855                 aImgSz.Height() = CalcZoom( aImgSz.Height() );
1856                 DrawImage( aPtImg, aImgSz, aImage );
1857             }
1858         }
1859     }
1860 
1861     if( bDrawText )
1862     {
1863         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1864         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1865         XubString aStr( mpEntryList->GetEntryText( nPos ) );
1866         if ( aStr.Len() )
1867         {
1868             long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
1869                                   GetOutputSizePixel().Width() - 2*mnBorder );
1870             // a multiline entry should only be as wide a the window
1871             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1872                 nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1873 
1874             Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1875                                  Size( nMaxWidth, pEntry->mnHeight ) );
1876 
1877             if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1878             {
1879                 long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
1880                 aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1881             }
1882 
1883             if( bLayout )
1884                 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
1885 
1886             // pb: #106948# explicit mirroring for calc
1887             if ( mbMirroring )
1888             {
1889                 // right aligned
1890                 aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
1891                 if ( aImgSz.Width() > 0 )
1892                     aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
1893             }
1894 
1895             sal_uInt16 nDrawStyle = ImplGetTextStyle();
1896             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1897                 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1898             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
1899                 nDrawStyle |= TEXT_DRAW_DISABLE;
1900 
1901             DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1902         }
1903     }
1904 
1905     if( !bLayout )
1906     {
1907         if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1908              ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1909         {
1910             Color aOldLineColor( GetLineColor() );
1911             SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1912             Point aStartPos( 0, nY );
1913             if ( nPos == mnSeparatorPos )
1914                 aStartPos.Y() += pEntry->mnHeight-1;
1915             Point aEndPos( aStartPos );
1916             aEndPos.X() = GetOutputSizePixel().Width();
1917             DrawLine( aStartPos, aEndPos );
1918             SetLineColor( aOldLineColor );
1919         }
1920     }
1921 }
1922 
1923 // -----------------------------------------------------------------------
1924 
1925 void ImplListBoxWindow::FillLayoutData() const
1926 {
1927     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1928     const_cast<ImplListBoxWindow*>(this)->
1929         ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1930 }
1931 
1932 // -----------------------------------------------------------------------
1933 
1934 void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1935 {
1936     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1937 
1938     sal_Bool bShowFocusRect = mbHasFocusRect;
1939     if ( mbHasFocusRect && ! bLayout )
1940         ImplHideFocusRect();
1941 
1942     long nY = 0; // + mnBorder;
1943     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1944 
1945     for( sal_uInt16 i = (sal_uInt16)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1946     {
1947         const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1948         if( nY + pEntry->mnHeight >= rRect.Top() &&
1949             nY <= rRect.Bottom() + mnMaxHeight )
1950         {
1951             ImplPaint( i, sal_False, bLayout );
1952         }
1953         nY += pEntry->mnHeight;
1954     }
1955 
1956     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1957     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1958     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1959     maFocusRect.SetSize( aSz );
1960     if( HasFocus() && bShowFocusRect && !bLayout )
1961         ImplShowFocusRect();
1962 }
1963 
1964 // -----------------------------------------------------------------------
1965 
1966 void ImplListBoxWindow::Paint( const Rectangle& rRect )
1967 {
1968     ImplDoPaint( rRect );
1969 }
1970 
1971 // -----------------------------------------------------------------------
1972 
1973 sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1974 {
1975     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1976 
1977     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1978     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1979     sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1980     if( nEntries > nCount-mnTop )
1981         nEntries = nCount-mnTop;
1982 
1983     return nEntries;
1984 }
1985 
1986 // -----------------------------------------------------------------------
1987 
1988 void ImplListBoxWindow::Resize()
1989 {
1990     Control::Resize();
1991 
1992     sal_Bool bShowFocusRect = mbHasFocusRect;
1993     if ( bShowFocusRect )
1994         ImplHideFocusRect();
1995 
1996     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1997     {
1998         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1999         maFocusRect.SetSize( aSz );
2000     }
2001 
2002     if ( bShowFocusRect )
2003         ImplShowFocusRect();
2004 
2005     ImplClearLayoutData();
2006 }
2007 
2008 // -----------------------------------------------------------------------
2009 
2010 void ImplListBoxWindow::GetFocus()
2011 {
2012     sal_uInt16 nPos = mnCurrentPos;
2013     if ( nPos == LISTBOX_ENTRY_NOTFOUND )
2014         nPos = 0;
2015     long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
2016     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
2017     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
2018     maFocusRect.SetSize( aSz );
2019     ImplShowFocusRect();
2020     Control::GetFocus();
2021 }
2022 
2023 // -----------------------------------------------------------------------
2024 
2025 void ImplListBoxWindow::LoseFocus()
2026 {
2027     ImplHideFocusRect();
2028     Control::LoseFocus();
2029 }
2030 
2031 // -----------------------------------------------------------------------
2032 
2033 /*
2034 void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
2035 {
2036     if ( rHEvt.GetMode() & HELPMODE_BALLOON )
2037         Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
2038 
2039     Window::RequestHelp( rHEvt );
2040 }
2041 */
2042 
2043 // -----------------------------------------------------------------------
2044 
2045 void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop )
2046 {
2047     if( mpEntryList->GetEntryCount() == 0 )
2048         return;
2049 
2050     long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2051 
2052     sal_uInt16 nLastEntry = mpEntryList->GetEntryCount()-1;
2053     if( nTop > nLastEntry )
2054         nTop = nLastEntry;
2055     const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
2056     while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
2057         nTop--;
2058 
2059     if ( nTop != mnTop )
2060     {
2061         ImplClearLayoutData();
2062         long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
2063         Update();
2064         ImplHideFocusRect();
2065         mnTop = nTop;
2066         Scroll( 0, nDiff );
2067         Update();
2068         if( HasFocus() )
2069             ImplShowFocusRect();
2070         maScrollHdl.Call( this );
2071     }
2072 }
2073 
2074 // -----------------------------------------------------------------------
2075 
2076 void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos )
2077 {
2078     if( meProminentType == PROMINENT_MIDDLE )
2079     {
2080         sal_uInt16 nPos = nEntryPos;
2081         long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2082         while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
2083             nEntryPos--;
2084     }
2085     SetTopEntry( nEntryPos );
2086 }
2087 
2088 // -----------------------------------------------------------------------
2089 
2090 void ImplListBoxWindow::SetLeftIndent( long n )
2091 {
2092     ScrollHorz( n - mnLeft );
2093 }
2094 
2095 // -----------------------------------------------------------------------
2096 
2097 void ImplListBoxWindow::ScrollHorz( long n )
2098 {
2099     long nDiff = 0;
2100     if ( n > 0 )
2101     {
2102         long nWidth = GetOutputSizePixel().Width();
2103         if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2104             nDiff = n;
2105     }
2106     else if ( n < 0 )
2107     {
2108         if( mnLeft )
2109         {
2110             long nAbs = -n;
2111             nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2112         }
2113     }
2114 
2115     if ( nDiff )
2116     {
2117         ImplClearLayoutData();
2118         mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
2119         Update();
2120         ImplHideFocusRect();
2121         Scroll( -nDiff, 0 );
2122         Update();
2123         if( HasFocus() )
2124             ImplShowFocusRect();
2125         maScrollHdl.Call( this );
2126     }
2127 }
2128 
2129 // -----------------------------------------------------------------------
2130 
2131 Size ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines ) const
2132 {
2133     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2134 
2135     Size aSz;
2136 //  sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2137     aSz.Height() =  nMaxLines * mnMaxHeight;
2138     aSz.Width() = mnMaxWidth + 2*mnBorder;
2139     return aSz;
2140 }
2141 
2142 // -----------------------------------------------------------------------
2143 
2144 Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem ) const
2145 {
2146     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2147     Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2148     long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
2149     Rectangle aRect( Point( 0, nY ), aSz );
2150     return aRect;
2151 }
2152 
2153 
2154 // -----------------------------------------------------------------------
2155 
2156 void ImplListBoxWindow::StateChanged( StateChangedType nType )
2157 {
2158     Control::StateChanged( nType );
2159 
2160     if ( nType == STATE_CHANGE_ZOOM )
2161     {
2162         ImplInitSettings( sal_True, sal_False, sal_False );
2163         ImplCalcMetrics();
2164         Invalidate();
2165     }
2166     else if ( nType == STATE_CHANGE_UPDATEMODE )
2167     {
2168         if ( IsUpdateMode() && IsReallyVisible() )
2169             Invalidate();
2170     }
2171     else if ( nType == STATE_CHANGE_CONTROLFONT )
2172     {
2173         ImplInitSettings( sal_True, sal_False, sal_False );
2174         ImplCalcMetrics();
2175         Invalidate();
2176     }
2177     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2178     {
2179         ImplInitSettings( sal_False, sal_True, sal_False );
2180         Invalidate();
2181     }
2182     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2183     {
2184         ImplInitSettings( sal_False, sal_False, sal_True );
2185         Invalidate();
2186     }
2187     ImplClearLayoutData();
2188 }
2189 
2190 // -----------------------------------------------------------------------
2191 
2192 void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2193 {
2194     Control::DataChanged( rDCEvt );
2195 
2196     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2197          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2198          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2199           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2200     {
2201         ImplClearLayoutData();
2202         ImplInitSettings( sal_True, sal_True, sal_True );
2203         ImplCalcMetrics();
2204         Invalidate();
2205     }
2206 }
2207 
2208 // -----------------------------------------------------------------------
2209 
2210 sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
2211 {
2212     sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2213 
2214     if ( mpEntryList->HasImages() )
2215         nTextStyle |= TEXT_DRAW_LEFT;
2216     else if ( mbCenter )
2217         nTextStyle |= TEXT_DRAW_CENTER;
2218     else if ( mbRight )
2219         nTextStyle |= TEXT_DRAW_RIGHT;
2220     else
2221         nTextStyle |= TEXT_DRAW_LEFT;
2222 
2223     return nTextStyle;
2224 }
2225 
2226 // =======================================================================
2227 
2228 ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2229     Control( pParent, nWinStyle ),
2230     maLBWindow( this, nWinStyle&(~WB_BORDER) )
2231 {
2232     // for native widget rendering we must be able to detect this window type
2233     SetType( WINDOW_LISTBOXWINDOW );
2234 
2235     mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2236     mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2237     mpScrollBarBox  = new ScrollBarBox( this );
2238 
2239     Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2240     mpVScrollBar->SetScrollHdl( aLink );
2241     mpHScrollBar->SetScrollHdl( aLink );
2242 
2243     mbVScroll       = sal_False;
2244     mbHScroll       = sal_False;
2245     mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL ) ? sal_True : sal_False;
2246 
2247     maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2248     maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2249     maLBWindow.Show();
2250 }
2251 
2252 // -----------------------------------------------------------------------
2253 
2254 ImplListBox::~ImplListBox()
2255 {
2256     delete mpHScrollBar;
2257     delete mpVScrollBar;
2258     delete mpScrollBarBox;
2259 }
2260 
2261 // -----------------------------------------------------------------------
2262 
2263 void ImplListBox::Clear()
2264 {
2265     maLBWindow.Clear();
2266     if ( GetEntryList()->GetMRUCount() )
2267     {
2268         maLBWindow.GetEntryList()->SetMRUCount( 0 );
2269         maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2270     }
2271     mpVScrollBar->SetThumbPos( 0 );
2272     mpHScrollBar->SetThumbPos( 0 );
2273     StateChanged( STATE_CHANGE_DATA );
2274 }
2275 
2276 // -----------------------------------------------------------------------
2277 
2278 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr )
2279 {
2280     ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2281     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2282     StateChanged( STATE_CHANGE_DATA );
2283     return nNewPos;
2284 }
2285 
2286 // -----------------------------------------------------------------------
2287 
2288 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const Image& rImage )
2289 {
2290     ImplEntryType* pNewEntry = new ImplEntryType( rImage );
2291     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2292     StateChanged( STATE_CHANGE_DATA );
2293     return nNewPos;
2294 }
2295 
2296 // -----------------------------------------------------------------------
2297 
2298 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr, const Image& rImage )
2299 {
2300     ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2301     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2302     StateChanged( STATE_CHANGE_DATA );
2303     return nNewPos;
2304 }
2305 
2306 // -----------------------------------------------------------------------
2307 
2308 void ImplListBox::RemoveEntry( sal_uInt16 nPos )
2309 {
2310     maLBWindow.RemoveEntry( nPos );
2311     StateChanged( STATE_CHANGE_DATA );
2312 }
2313 
2314 // -----------------------------------------------------------------------
2315 
2316 void ImplListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
2317 {
2318     maLBWindow.SetEntryFlags( nPos, nFlags );
2319 }
2320 
2321 // -----------------------------------------------------------------------
2322 
2323 long ImplListBox::GetEntryFlags( sal_uInt16 nPos ) const
2324 {
2325     return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
2326 }
2327 
2328 // -----------------------------------------------------------------------
2329 
2330 void ImplListBox::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
2331 {
2332     maLBWindow.SelectEntry( nPos, bSelect );
2333 }
2334 
2335 // -----------------------------------------------------------------------
2336 
2337 void ImplListBox::SetNoSelection()
2338 {
2339     maLBWindow.DeselectAll();
2340 }
2341 
2342 // -----------------------------------------------------------------------
2343 
2344 void ImplListBox::GetFocus()
2345 {
2346     maLBWindow.GrabFocus();
2347 }
2348 
2349 // -----------------------------------------------------------------------
2350 
2351 Window* ImplListBox::GetPreferredKeyInputWindow()
2352 {
2353     return &maLBWindow;
2354 }
2355 
2356 // -----------------------------------------------------------------------
2357 
2358 void ImplListBox::Resize()
2359 {
2360     Control::Resize();
2361     ImplResizeControls();
2362     ImplCheckScrollBars();
2363 }
2364 
2365 
2366 // -----------------------------------------------------------------------
2367 
2368 IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
2369 {
2370     StateChanged( STATE_CHANGE_DATA );
2371     return 1;
2372 }
2373 
2374 // -----------------------------------------------------------------------
2375 
2376 IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
2377 {
2378     long nSet = GetTopEntry();
2379     if( nSet > mpVScrollBar->GetRangeMax() )
2380         mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2381     mpVScrollBar->SetThumbPos( GetTopEntry() );
2382 
2383     mpHScrollBar->SetThumbPos( GetLeftIndent() );
2384 
2385     maScrollHdl.Call( this );
2386 
2387     return 1;
2388 }
2389 
2390 // -----------------------------------------------------------------------
2391 
2392 IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2393 {
2394     sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2395     if( pSB == mpVScrollBar )
2396         SetTopEntry( nPos );
2397     else if( pSB == mpHScrollBar )
2398         SetLeftIndent( nPos );
2399 
2400     return 1;
2401 }
2402 
2403 // -----------------------------------------------------------------------
2404 
2405 void ImplListBox::ImplCheckScrollBars()
2406 {
2407     sal_Bool bArrange = sal_False;
2408 
2409     Size aOutSz = GetOutputSizePixel();
2410     sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2411     sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2412 
2413     // vert. ScrollBar
2414     if( nEntries > nMaxVisEntries )
2415     {
2416         if( !mbVScroll )
2417             bArrange = sal_True;
2418         mbVScroll = sal_True;
2419 
2420         // Ueberpruefung des rausgescrollten Bereichs
2421         if( GetEntryList()->GetSelectEntryCount() == 1 &&
2422             GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2423             ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2424         else
2425             SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2426     }
2427     else
2428     {
2429         if( mbVScroll )
2430             bArrange = sal_True;
2431         mbVScroll = sal_False;
2432         SetTopEntry( 0 );
2433     }
2434 
2435     // horz. ScrollBar
2436     if( mbAutoHScroll )
2437     {
2438         long nWidth = (sal_uInt16) aOutSz.Width();
2439         if ( mbVScroll )
2440             nWidth -= mpVScrollBar->GetSizePixel().Width();
2441 
2442         long nMaxWidth = GetMaxEntryWidth();
2443         if( nWidth < nMaxWidth )
2444         {
2445             if( !mbHScroll )
2446                 bArrange = sal_True;
2447             mbHScroll = sal_True;
2448 
2449             if ( !mbVScroll )   // ggf. brauchen wir jetzt doch einen
2450             {
2451                 nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2452                 if( nEntries > nMaxVisEntries )
2453                 {
2454                     bArrange = sal_True;
2455                     mbVScroll = sal_True;
2456 
2457                     // Ueberpruefung des rausgescrollten Bereichs
2458                     if( GetEntryList()->GetSelectEntryCount() == 1 &&
2459                         GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2460                         ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2461                     else
2462                         SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2463                 }
2464             }
2465 
2466             // Ueberpruefung des rausgescrollten Bereichs
2467             sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2468             if ( nMaxLI < GetLeftIndent() )
2469                 SetLeftIndent( nMaxLI );
2470         }
2471         else
2472         {
2473             if( mbHScroll )
2474                 bArrange = sal_True;
2475             mbHScroll = sal_False;
2476             SetLeftIndent( 0 );
2477         }
2478     }
2479 
2480     if( bArrange )
2481         ImplResizeControls();
2482 
2483     ImplInitScrollBars();
2484 }
2485 
2486 // -----------------------------------------------------------------------
2487 
2488 void ImplListBox::ImplInitScrollBars()
2489 {
2490     Size aOutSz = maLBWindow.GetOutputSizePixel();
2491 
2492     if ( mbVScroll )
2493     {
2494         sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2495         sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2496         mpVScrollBar->SetRangeMax( nEntries );
2497         mpVScrollBar->SetVisibleSize( nVisEntries );
2498         mpVScrollBar->SetPageSize( nVisEntries - 1 );
2499     }
2500 
2501     if ( mbHScroll )
2502     {
2503         mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2504         mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2505         mpHScrollBar->SetLineSize( HORZ_SCROLL );
2506         mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2507     }
2508 }
2509 
2510 // -----------------------------------------------------------------------
2511 
2512 void ImplListBox::ImplResizeControls()
2513 {
2514     // Hier werden die Controls nur angeordnet, ob die Scrollbars
2515     // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
2516 
2517     Size aOutSz = GetOutputSizePixel();
2518     long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2519     nSBWidth = CalcZoom( nSBWidth );
2520 
2521     Size aInnerSz( aOutSz );
2522     if ( mbVScroll )
2523         aInnerSz.Width() -= nSBWidth;
2524     if ( mbHScroll )
2525         aInnerSz.Height() -= nSBWidth;
2526 
2527     // pb: #106948# explicit mirroring for calc
2528     // Scrollbar on left or right side?
2529     sal_Bool bMirroring = maLBWindow.IsMirroring();
2530     Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2531     maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2532 
2533     // ScrollBarBox
2534     if( mbVScroll && mbHScroll )
2535     {
2536         Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2537         mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2538         mpScrollBarBox->Show();
2539     }
2540     else
2541     {
2542         mpScrollBarBox->Hide();
2543     }
2544 
2545     // vert. ScrollBar
2546     if( mbVScroll )
2547     {
2548         // Scrollbar on left or right side?
2549         Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2550         mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2551         mpVScrollBar->Show();
2552     }
2553     else
2554     {
2555         mpVScrollBar->Hide();
2556         // #107254# Don't reset top entry after resize, but check for max top entry
2557         SetTopEntry( GetTopEntry() );
2558     }
2559 
2560     // horz. ScrollBar
2561     if( mbHScroll )
2562     {
2563         Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2564         mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2565         mpHScrollBar->Show();
2566     }
2567     else
2568     {
2569         mpHScrollBar->Hide();
2570         SetLeftIndent( 0 );
2571     }
2572 }
2573 
2574 // -----------------------------------------------------------------------
2575 
2576 void ImplListBox::StateChanged( StateChangedType nType )
2577 {
2578     if ( nType == STATE_CHANGE_INITSHOW )
2579     {
2580         ImplCheckScrollBars();
2581     }
2582     else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2583     {
2584         sal_Bool bUpdate = IsUpdateMode();
2585         maLBWindow.SetUpdateMode( bUpdate );
2586 //      mpHScrollBar->SetUpdateMode( bUpdate );
2587 //      mpVScrollBar->SetUpdateMode( bUpdate );
2588         if ( bUpdate && IsReallyVisible() )
2589             ImplCheckScrollBars();
2590     }
2591     else if( nType == STATE_CHANGE_ENABLE )
2592     {
2593         mpHScrollBar->Enable( IsEnabled() );
2594         mpVScrollBar->Enable( IsEnabled() );
2595         mpScrollBarBox->Enable( IsEnabled() );
2596         Invalidate();
2597     }
2598     else if ( nType == STATE_CHANGE_ZOOM )
2599     {
2600         maLBWindow.SetZoom( GetZoom() );
2601         Resize();
2602     }
2603     else if ( nType == STATE_CHANGE_CONTROLFONT )
2604     {
2605         maLBWindow.SetControlFont( GetControlFont() );
2606     }
2607     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2608     {
2609         maLBWindow.SetControlForeground( GetControlForeground() );
2610     }
2611     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2612     {
2613         maLBWindow.SetControlBackground( GetControlBackground() );
2614     }
2615     else if( nType == STATE_CHANGE_MIRRORING )
2616     {
2617         maLBWindow.EnableRTL( IsRTLEnabled() );
2618         mpHScrollBar->EnableRTL( IsRTLEnabled() );
2619         mpVScrollBar->EnableRTL( IsRTLEnabled() );
2620         ImplResizeControls();
2621     }
2622 
2623     Control::StateChanged( nType );
2624 }
2625 
2626 // -----------------------------------------------------------------------
2627 
2628 void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2629 {
2630 //  if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2631 //       (rDCEvt.GetFlags() & SETTINGS_STYLE) )
2632 //  {
2633 //      maLBWindow.SetSettings( GetSettings() );
2634 //      Resize();
2635 //  }
2636 //  else
2637         Control::DataChanged( rDCEvt );
2638 }
2639 
2640 // -----------------------------------------------------------------------
2641 
2642 long ImplListBox::Notify( NotifyEvent& rNEvt )
2643 {
2644     long nDone = 0;
2645     if ( rNEvt.GetType() == EVENT_COMMAND )
2646     {
2647         const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2648         if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2649         {
2650             const CommandWheelData* pData = rCEvt.GetWheelData();
2651             if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2652             {
2653                 nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2654             }
2655         }
2656     }
2657 
2658     return nDone ? nDone : Window::Notify( rNEvt );
2659 }
2660 
2661 // -----------------------------------------------------------------------
2662 
2663 const Wallpaper& ImplListBox::GetDisplayBackground() const
2664 {
2665     return maLBWindow.GetDisplayBackground();
2666 }
2667 
2668 // -----------------------------------------------------------------------
2669 
2670 sal_Bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2671 {
2672     sal_Bool bDone = sal_False;
2673     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2674     {
2675         const CommandWheelData* pData = rCEvt.GetWheelData();
2676         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2677         {
2678             sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2679             KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2680             bDone = ProcessKeyInput( aKeyEvent );
2681         }
2682     }
2683     return bDone;
2684 }
2685 
2686 // -----------------------------------------------------------------------
2687 
2688 void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
2689 {
2690     sal_Bool bChanges = GetEntryList()->GetMRUCount() ? sal_True : sal_False;
2691 
2692     // Remove old MRU entries
2693     for ( sal_uInt16 n = GetEntryList()->GetMRUCount();n; )
2694         maLBWindow.RemoveEntry( --n );
2695 
2696     sal_uInt16 nMRUCount = 0;
2697     sal_uInt16 nEntries = rEntries.GetTokenCount( cSep );
2698     for ( sal_uInt16 nEntry = 0; nEntry < nEntries; nEntry++ )
2699     {
2700         XubString aEntry = rEntries.GetToken( nEntry, cSep );
2701         // Accept only existing entries
2702         if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2703         {
2704             ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2705             maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, sal_False );
2706             bChanges = sal_True;
2707         }
2708     }
2709 
2710     if ( bChanges )
2711     {
2712         maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2713         SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2714         StateChanged( STATE_CHANGE_DATA );
2715     }
2716 }
2717 
2718 // -----------------------------------------------------------------------
2719 
2720 XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
2721 {
2722     String aEntries;
2723     for ( sal_uInt16 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2724     {
2725         aEntries += GetEntryList()->GetEntryText( n );
2726         if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2727             aEntries += cSep;
2728     }
2729     return aEntries;
2730 }
2731 
2732 // =======================================================================
2733 
2734 ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2735     Control ( pParent, nWinStyle )
2736 {
2737     if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2738             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2739         SetBackground();
2740     else
2741         SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2742 
2743     mbInUserDraw = sal_False;
2744     mbUserDrawEnabled = sal_False;
2745     mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2746 }
2747 
2748 // -----------------------------------------------------------------------
2749 
2750 sal_Bool ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
2751 {
2752     if( eMode == BMP_COLOR_NORMAL )
2753         SetImage( rImage );
2754     else if( eMode == BMP_COLOR_HIGHCONTRAST )
2755         maImageHC = rImage;
2756     else
2757         return sal_False;
2758     return sal_True;
2759 }
2760 
2761 // -----------------------------------------------------------------------
2762 
2763 const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
2764 {
2765     if( eMode == BMP_COLOR_HIGHCONTRAST )
2766         return maImageHC;
2767     else
2768         return maImage;
2769 }
2770 
2771 // -----------------------------------------------------------------------
2772 
2773 void ImplWin::MBDown()
2774 {
2775     if( IsEnabled() )
2776         maMBDownHdl.Call( this );
2777 }
2778 
2779 // -----------------------------------------------------------------------
2780 
2781 void ImplWin::MouseButtonDown( const MouseEvent& )
2782 {
2783     if( IsEnabled() )
2784     {
2785 //      Control::MouseButtonDown( rMEvt );
2786         MBDown();
2787     }
2788 }
2789 
2790 // -----------------------------------------------------------------------
2791 
2792 void ImplWin::FillLayoutData() const
2793 {
2794     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2795     const_cast<ImplWin*>(this)->ImplDraw( true );
2796 }
2797 
2798 // -----------------------------------------------------------------------
2799 
2800 long ImplWin::PreNotify( NotifyEvent& rNEvt )
2801 {
2802     long nDone = 0;
2803     const MouseEvent* pMouseEvt = NULL;
2804 
2805     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2806     {
2807         if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2808         {
2809             // trigger redraw as mouse over state has changed
2810             if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2811             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2812             {
2813                 GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2814                 GetParent()->GetWindow( WINDOW_BORDER )->Update();
2815             }
2816         }
2817     }
2818 
2819     return nDone ? nDone : Control::PreNotify(rNEvt);
2820 }
2821 
2822 // -----------------------------------------------------------------------
2823 
2824 void ImplWin::ImplDraw( bool bLayout )
2825 {
2826     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2827 
2828     sal_Bool bNativeOK = sal_False;
2829 
2830     if( ! bLayout )
2831     {
2832         ControlState nState = CTRL_STATE_ENABLED;
2833         if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2834             && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2835         {
2836             // Repaint the (focused) area similarly to
2837             // ImplSmallBorderWindowView::DrawWindow() in
2838             // vcl/source/window/brdwin.cxx
2839             Window *pWin = GetParent();
2840 
2841             ImplControlValue aControlValue;
2842             if ( !pWin->IsEnabled() )
2843             nState &= ~CTRL_STATE_ENABLED;
2844             if ( pWin->HasFocus() )
2845             nState |= CTRL_STATE_FOCUSED;
2846 
2847             // The listbox is painted over the entire control including the
2848             // border, but ImplWin does not contain the border => correction
2849             // needed.
2850             sal_Int32 nLeft, nTop, nRight, nBottom;
2851             pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2852             Point aPoint( -nLeft, -nTop );
2853             Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2854 
2855             sal_Bool bMouseOver = sal_False;
2856             if( GetParent() )
2857             {
2858                 Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2859                 while( pChild && (bMouseOver = pChild->IsMouseOver()) == sal_False )
2860                     pChild = pChild->GetWindow( WINDOW_NEXT );
2861             }
2862 
2863             if( bMouseOver )
2864                 nState |= CTRL_STATE_ROLLOVER;
2865 
2866             // if parent has no border, then nobody has drawn the background
2867             // since no border window exists. so draw it here.
2868             WinBits nParentStyle = pWin->GetStyle();
2869             if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2870             {
2871                 Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2872                 pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2873                                          nState, aControlValue, rtl::OUString() );
2874             }
2875 
2876             bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2877                 aControlValue, rtl::OUString() );
2878         }
2879 
2880         if( IsEnabled() )
2881         {
2882             if( HasFocus() )
2883             {
2884                 SetTextColor( rStyleSettings.GetHighlightTextColor() );
2885                 SetFillColor( rStyleSettings.GetHighlightColor() );
2886                 DrawRect( maFocusRect );
2887             }
2888             else
2889             {
2890                 Color aColor;
2891                 if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2892                     aColor = rStyleSettings.GetFieldRolloverTextColor();
2893                 else
2894                     aColor = rStyleSettings.GetFieldTextColor();
2895                 if( IsControlForeground() )
2896                     aColor = GetControlForeground();
2897                 SetTextColor( aColor );
2898                 if ( !bNativeOK )
2899                     Erase( maFocusRect );
2900             }
2901         }
2902         else // Disabled
2903         {
2904             SetTextColor( rStyleSettings.GetDisableColor() );
2905             if ( !bNativeOK )
2906                 Erase( maFocusRect );
2907         }
2908     }
2909 
2910     if ( IsUserDrawEnabled() )
2911     {
2912         mbInUserDraw = sal_True;
2913         UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2914         maUserDrawHdl.Call( &aUDEvt );
2915         mbInUserDraw = sal_False;
2916     }
2917     else
2918     {
2919         DrawEntry( sal_True, sal_True, sal_False, bLayout );
2920     }
2921 }
2922 
2923 // -----------------------------------------------------------------------
2924 
2925 void ImplWin::Paint( const Rectangle& )
2926 {
2927     ImplDraw();
2928 }
2929 
2930 // -----------------------------------------------------------------------
2931 
2932 void ImplWin::DrawEntry( sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
2933 {
2934     long nBorder = 1;
2935     Size aOutSz = GetOutputSizePixel();
2936 
2937     sal_Bool bImage = !!maImage;
2938     if( bDrawImage && bImage && !bLayout )
2939     {
2940         sal_uInt16 nStyle = 0;
2941         Size aImgSz = maImage.GetSizePixel();
2942         Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2943 
2944         // check for HC mode
2945         Image *pImage = &maImage;
2946 
2947         if( !!maImageHC )
2948         {
2949             if( GetSettings().GetStyleSettings().GetHighContrastMode() )
2950                 pImage = &maImageHC;
2951         }
2952 
2953         if ( !IsZoom() )
2954         {
2955             DrawImage( aPtImg, *pImage, nStyle );
2956         }
2957         else
2958         {
2959             aImgSz.Width() = CalcZoom( aImgSz.Width() );
2960             aImgSz.Height() = CalcZoom( aImgSz.Height() );
2961             DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2962         }
2963     }
2964 
2965     if( bDrawText && maString.Len() )
2966     {
2967         sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2968 
2969         if ( bDrawImage && bImage && !bLayout )
2970             nTextStyle |= TEXT_DRAW_LEFT;
2971         else if ( GetStyle() & WB_CENTER )
2972             nTextStyle |= TEXT_DRAW_CENTER;
2973         else if ( GetStyle() & WB_RIGHT )
2974             nTextStyle |= TEXT_DRAW_RIGHT;
2975         else
2976             nTextStyle |= TEXT_DRAW_LEFT;
2977 
2978         Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
2979 
2980         if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
2981         {
2982             long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
2983             aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
2984         }
2985 
2986         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
2987         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
2988         DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
2989     }
2990 
2991     if( HasFocus() && !bLayout )
2992         ShowFocus( maFocusRect );
2993 }
2994 
2995 // -----------------------------------------------------------------------
2996 
2997 void ImplWin::Resize()
2998 {
2999     Control::Resize();
3000     maFocusRect.SetSize( GetOutputSizePixel() );
3001     Invalidate();
3002 }
3003 
3004 // -----------------------------------------------------------------------
3005 
3006 void ImplWin::GetFocus()
3007 {
3008     ShowFocus( maFocusRect );
3009     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3010         IsNativeWidgetEnabled() &&
3011         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3012     {
3013         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3014         if( ! pWin )
3015             pWin = GetParent();
3016         pWin->Invalidate();
3017     }
3018     else
3019         Invalidate();
3020     Control::GetFocus();
3021 }
3022 
3023 // -----------------------------------------------------------------------
3024 
3025 void ImplWin::LoseFocus()
3026 {
3027     HideFocus();
3028     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3029         IsNativeWidgetEnabled() &&
3030         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3031     {
3032         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3033         if( ! pWin )
3034             pWin = GetParent();
3035         pWin->Invalidate();
3036     }
3037     else
3038         Invalidate();
3039     Control::LoseFocus();
3040 }
3041 
3042 // =======================================================================
3043 
3044 ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
3045     PushButton(  pParent, nWinStyle ),
3046     mbDown  ( sal_False )
3047 {
3048 }
3049 
3050 // -----------------------------------------------------------------------
3051 
3052 void ImplBtn::MBDown()
3053 {
3054     if( IsEnabled() )
3055        maMBDownHdl.Call( this );
3056 }
3057 
3058 // -----------------------------------------------------------------------
3059 
3060 void ImplBtn::MouseButtonDown( const MouseEvent& )
3061 {
3062     //PushButton::MouseButtonDown( rMEvt );
3063     if( IsEnabled() )
3064     {
3065         MBDown();
3066         mbDown = sal_True;
3067     }
3068 }
3069 
3070 // =======================================================================
3071 
3072 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
3073     FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW )    // no drop shadow for list boxes
3074 {
3075     mpImplLB = NULL;
3076     mnDDLineCount = 0;
3077     mbAutoWidth = sal_False;
3078 
3079     mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
3080 
3081     EnableSaveBackground();
3082 
3083     Window * pBorderWindow = ImplGetBorderWindow();
3084     if( pBorderWindow )
3085     {
3086         SetAccessibleRole(accessibility::AccessibleRole::PANEL);
3087         pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3088     }
3089     else
3090     {
3091         SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3092     }
3093 
3094 }
3095 
3096 // -----------------------------------------------------------------------
3097 
3098 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
3099 {
3100     if( rNEvt.GetType() == EVENT_LOSEFOCUS )
3101     {
3102         if( !GetParent()->HasChildPathFocus( sal_True ) )
3103             EndPopupMode();
3104     }
3105 
3106     return FloatingWindow::PreNotify( rNEvt );
3107 }
3108 
3109 // -----------------------------------------------------------------------
3110 
3111 void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
3112 {
3113     FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
3114 
3115     // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
3116     // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
3117     if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
3118     {
3119         Point aPos = GetParent()->GetPosPixel();
3120         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3121 
3122         if ( nFlags & WINDOW_POSSIZE_X )
3123             aPos.X() = nX;
3124 
3125         if ( nFlags & WINDOW_POSSIZE_Y )
3126             aPos.Y() = nY;
3127 
3128         sal_uInt16 nIndex;
3129         SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
3130     }
3131 
3132 //  if( !IsReallyVisible() )
3133     {
3134         // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
3135         // Die Fenster muessen aber ein Resize() erhalten, damit die
3136         // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
3137         // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
3138         // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
3139         // beruecksichtigt werden muss.
3140         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3141         ((Window*)mpImplLB)->Resize();
3142         ((Window*)mpImplLB->GetMainWindow())->Resize();
3143     }
3144 }
3145 
3146 // -----------------------------------------------------------------------
3147 
3148 void ImplListBoxFloatingWindow::Resize()
3149 {
3150     mpImplLB->GetMainWindow()->ImplClearLayoutData();
3151     FloatingWindow::Resize();
3152 }
3153 
3154 // -----------------------------------------------------------------------
3155 
3156 Size ImplListBoxFloatingWindow::CalcFloatSize()
3157 {
3158     Size aFloatSz( maPrefSz );
3159 
3160     sal_Int32 nLeft, nTop, nRight, nBottom;
3161     GetBorder( nLeft, nTop, nRight, nBottom );
3162 
3163     sal_uInt16 nLines = mpImplLB->GetEntryList()->GetEntryCount();
3164     if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3165         nLines = mnDDLineCount;
3166 
3167     Size aSz = mpImplLB->CalcSize( nLines );
3168     long nMaxHeight = aSz.Height() + nTop + nBottom;
3169 
3170     if ( mnDDLineCount )
3171         aFloatSz.Height() = nMaxHeight;
3172 
3173     if( mbAutoWidth )
3174     {
3175         // AutoSize erstmal nur fuer die Breite...
3176 
3177         aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3178         aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
3179 
3180         if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3181         {
3182             // dann wird noch der vertikale Scrollbar benoetigt
3183             long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3184             aFloatSz.Width() += nSBWidth;
3185         }
3186     }
3187 
3188     if ( aFloatSz.Height() > nMaxHeight )
3189         aFloatSz.Height() = nMaxHeight;
3190 
3191     // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
3192     // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
3193     Size aParentSz = GetParent()->GetSizePixel();
3194     if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
3195         aFloatSz.Height() = aParentSz.Height();
3196 
3197     // Nicht schmaler als der Parent werden...
3198     if( aFloatSz.Width() < aParentSz.Width() )
3199         aFloatSz.Width() = aParentSz.Width();
3200 
3201     // Hoehe auf Entries alignen...
3202     long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3203     long nEntryHeight = mpImplLB->GetEntryHeight();
3204     if ( nInnerHeight % nEntryHeight )
3205     {
3206         nInnerHeight /= nEntryHeight;
3207         nInnerHeight++;
3208         nInnerHeight *= nEntryHeight;
3209         aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3210     }
3211 
3212     return aFloatSz;
3213 }
3214 
3215 // -----------------------------------------------------------------------
3216 
3217 void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking )
3218 {
3219     if( !IsInPopupMode() )
3220     {
3221         Size aFloatSz = CalcFloatSize();
3222 
3223         SetSizePixel( aFloatSz );
3224         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3225 
3226         sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3227         mnPopupModeStartSaveSelection = nPos;
3228 
3229         Size aSz = GetParent()->GetSizePixel();
3230         Point aPos = GetParent()->GetPosPixel();
3231         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3232         // FIXME: this ugly hack is for Mac/Aqua
3233         // should be replaced by a real mechanism to place the float rectangle
3234         if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3235             GetParent()->IsNativeWidgetEnabled() )
3236         {
3237             sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3238             aPos.X() += nLeft;
3239             aPos.Y() += nTop;
3240             aSz.Width() -= nLeft + nRight;
3241             aSz.Height() -= nTop + nBottom;
3242         }
3243         Rectangle aRect( aPos, aSz );
3244 
3245         // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3246         // where the document is unmirrored
3247         // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3248         if( GetParent()->GetParent()->ImplIsAntiparallel() )
3249             GetParent()->GetParent()->ImplReMirror( aRect );
3250 
3251         StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3252 
3253         if( nPos != LISTBOX_ENTRY_NOTFOUND )
3254             mpImplLB->ShowProminentEntry( nPos );
3255 
3256         if( bStartTracking )
3257             mpImplLB->GetMainWindow()->EnableMouseMoveSelect( sal_True );
3258 
3259         if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3260             mpImplLB->GetMainWindow()->GrabFocus();
3261 
3262         mpImplLB->GetMainWindow()->ImplClearLayoutData();
3263     }
3264 }
3265