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