xref: /trunk/main/vcl/source/control/ilstbox.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
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                 //IAccessibility2 Impplementaton 2009-----
920                 sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
921                 //SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() );
922                 SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() ,bCurPosChange);
923                 //-----IAccessibility2 Impplementaton 2009
924                 mbTrackingSelect = sal_False;
925                 if ( mbGrabFocus )
926                     GrabFocus();
927 
928                 StartTracking( STARTTRACK_SCROLLREPEAT );
929             }
930         }
931         if( rMEvt.GetClicks() == 2 )
932         {
933             maDoubleClickHdl.Call( this );
934         }
935     }
936     else // if ( mbGrabFocus )
937     {
938         GrabFocus();
939     }
940 }
941 
942 // -----------------------------------------------------------------------
943 
944 void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
945 {
946     if ( rMEvt.IsLeaveWindow() )
947     {
948         if ( mbStackMode && IsMouseMoveSelect() && IsReallyVisible() )
949         {
950             if ( rMEvt.GetPosPixel().Y() < 0 )
951             {
952                 DeselectAll();
953                 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
954                 SetTopEntry( 0 );
955                 if ( mbStackMode ) // #87072#, #92323#
956                 {
957                     mbTravelSelect = sal_True;
958                     mnSelectModifier = rMEvt.GetModifier();
959                     ImplCallSelect();
960                     mbTravelSelect = sal_False;
961                 }
962 
963             }
964         }
965     }
966     else if ( ( ( !mbMulti && IsMouseMoveSelect() ) || mbStackMode ) && mpEntryList->GetEntryCount() )
967     {
968         Point aPoint;
969         Rectangle aRect( aPoint, GetOutputSizePixel() );
970         if( aRect.IsInside( rMEvt.GetPosPixel() ) )
971         {
972             if ( IsMouseMoveSelect() )
973             {
974                 sal_uInt16 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
975                 if( nSelect == LISTBOX_ENTRY_NOTFOUND )
976                     nSelect = mpEntryList->GetEntryCount() - 1;
977                 nSelect = Min( nSelect, GetLastVisibleEntry() );
978                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
979                 // Select only visible Entries with MouseMove, otherwise Tracking...
980                 if ( IsVisible( nSelect ) &&
981                     mpEntryList->IsEntrySelectable( nSelect ) &&
982                     ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() || ( nSelect != GetEntryList()->GetSelectEntryPos( 0 ) ) ) )
983                 {
984                     mbTrackingSelect = sal_True;
985                     if ( SelectEntries( nSelect, LET_TRACKING, sal_False, sal_False ) )
986                     {
987                         if ( mbStackMode ) // #87072#
988                         {
989                             mbTravelSelect = sal_True;
990                             mnSelectModifier = rMEvt.GetModifier();
991                             ImplCallSelect();
992                             mbTravelSelect = sal_False;
993                         }
994 //IAccessibility2 Implementation 2009----
995                         // When list box selection change by mouse move, notity
996                         // VCLEVENT_LISTBOX_SELECT vcl event.
997                         else
998                         {
999                             maListItemSelectHdl.Call(NULL);
1000                         }
1001 //----IAccessibility2 Implementation 2009
1002                     }
1003                     mbTrackingSelect = sal_False;
1004                 }
1005             }
1006 
1007             // Falls der DD-Button gedrueckt wurde und jemand mit gedrueckter
1008             // Maustaste in die ListBox faehrt...
1009             if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
1010             {
1011                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1012                     mnTrackingSaveSelection = GetEntryList()->GetSelectEntryPos( 0 );
1013                 else
1014                     mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
1015 
1016                 if ( mbStackMode && ( mpEntryList->GetSelectionAnchor() == LISTBOX_ENTRY_NOTFOUND ) )
1017                     mpEntryList->SetSelectionAnchor( 0 );
1018 
1019                 StartTracking( STARTTRACK_SCROLLREPEAT );
1020             }
1021         }
1022     }
1023 }
1024 
1025 // -----------------------------------------------------------------------
1026 
1027 void ImplListBoxWindow::DeselectAll()
1028 {
1029     while ( GetEntryList()->GetSelectEntryCount() )
1030     {
1031         sal_uInt16 nS = GetEntryList()->GetSelectEntryPos( 0 );
1032         SelectEntry( nS, sal_False );
1033     }
1034 }
1035 
1036 // -----------------------------------------------------------------------
1037 
1038 void ImplListBoxWindow::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
1039 {
1040     if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
1041     {
1042         ImplHideFocusRect();
1043         if( bSelect )
1044         {
1045             if( !mbMulti )
1046             {
1047                 // Selektierten Eintrag deselektieren
1048                 sal_uInt16 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
1049                 if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
1050                 {
1051                     //SelectEntryPos( nDeselect, sal_False );
1052                     GetEntryList()->SelectEntry( nDeselect, sal_False );
1053                     if ( IsUpdateMode() && IsReallyVisible() )
1054                         ImplPaint( nDeselect, sal_True );
1055                 }
1056             }
1057             mpEntryList->SelectEntry( nPos, sal_True );
1058             mnCurrentPos = nPos;
1059             if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
1060             {
1061                 ImplPaint( nPos );
1062                 if ( !IsVisible( nPos ) )
1063                 {
1064                     ImplClearLayoutData();
1065                     sal_uInt16 nVisibleEntries = GetLastVisibleEntry()-mnTop;
1066                     if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1067                     {
1068                         Resize();
1069                         ShowProminentEntry( nPos );
1070                     }
1071                     else
1072                     {
1073                         ShowProminentEntry( nPos );
1074                     }
1075                 }
1076             }
1077         }
1078         else
1079         {
1080             mpEntryList->SelectEntry( nPos, sal_False );
1081             ImplPaint( nPos, sal_True );
1082         }
1083         mbSelectionChanged = sal_True;
1084     }
1085 }
1086 
1087 // -----------------------------------------------------------------------
1088 
1089 sal_Bool ImplListBoxWindow::SelectEntries( sal_uInt16 nSelect, LB_EVENT_TYPE eLET, sal_Bool bShift, sal_Bool bCtrl, sal_Bool bSelectPosChange /*=FALSE*/ )
1090 {
1091     sal_Bool bFocusChanged = sal_False;
1092     sal_Bool bSelectionChanged = sal_False;
1093 
1094     if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
1095     {
1096         // Hier (Single-ListBox) kann nur ein Eintrag deselektiert werden
1097         if( !mbMulti )
1098         {
1099             sal_uInt16 nDeselect = mpEntryList->GetSelectEntryPos( 0 );
1100             if( nSelect != nDeselect )
1101             {
1102                 SelectEntry( nSelect, sal_True );
1103                 mpEntryList->SetLastSelected( nSelect );
1104                 bFocusChanged = sal_True;
1105                 bSelectionChanged = sal_True;
1106             }
1107         }
1108         // MultiListBox ohne Modifier
1109         else if( mbSimpleMode && !bCtrl && !bShift )
1110         {
1111             sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1112             for ( sal_uInt16 nPos = 0; nPos < nEntryCount; nPos++ )
1113             {
1114                 sal_Bool bSelect = nPos == nSelect;
1115                 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1116                 {
1117                     SelectEntry( nPos, bSelect );
1118                     bFocusChanged = sal_True;
1119                     bSelectionChanged = sal_True;
1120                 }
1121             }
1122             mpEntryList->SetLastSelected( nSelect );
1123             mpEntryList->SetSelectionAnchor( nSelect );
1124         }
1125         // MultiListBox nur mit CTRL/SHIFT oder nicht im SimpleMode
1126         else if( ( !mbSimpleMode /* && !bShift */ ) || ( (mbSimpleMode && ( bCtrl || bShift )) || mbStackMode ) )
1127         {
1128             // Space fuer Selektionswechsel
1129             if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1130             {
1131                 sal_Bool bSelect = ( mbStackMode && IsMouseMoveSelect() ) ? sal_True : !mpEntryList->IsEntryPosSelected( nSelect );
1132                 if ( mbStackMode )
1133                 {
1134                     sal_uInt16 n;
1135                     if ( bSelect )
1136                     {
1137                         // All entries before nSelect must be selected...
1138                         for ( n = 0; n < nSelect; n++ )
1139                             SelectEntry( n, sal_True );
1140                     }
1141                     if ( !bSelect )
1142                     {
1143                         for ( n = nSelect+1; n < mpEntryList->GetEntryCount(); n++ )
1144                             SelectEntry( n, sal_False );
1145                     }
1146                 }
1147                 SelectEntry( nSelect, bSelect );
1148                 mpEntryList->SetLastSelected( nSelect );
1149                 mpEntryList->SetSelectionAnchor( mbStackMode ? 0 : nSelect );
1150                 if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1151                     mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND );
1152                 bFocusChanged = sal_True;
1153                 bSelectionChanged = sal_True;
1154             }
1155             else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1156                      ( (bShift||mbStackMode) && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1157             {
1158                 mnCurrentPos = nSelect;
1159                 bFocusChanged = sal_True;
1160 
1161                 sal_uInt16 nAnchor = mpEntryList->GetSelectionAnchor();
1162                 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND ) && ( mpEntryList->GetSelectEntryCount() || mbStackMode ) )
1163                 {
1164                     nAnchor = mbStackMode ? 0 : mpEntryList->GetSelectEntryPos( mpEntryList->GetSelectEntryCount() - 1 );
1165                 }
1166                 if( nAnchor != LISTBOX_ENTRY_NOTFOUND )
1167                 {
1168                     // Alle Eintraege vom Anchor bis nSelect muessen selektiert sein
1169                     sal_uInt16 nStart = Min( nSelect, nAnchor );
1170                     sal_uInt16 nEnd = Max( nSelect, nAnchor );
1171                     for ( sal_uInt16 n = nStart; n <= nEnd; n++ )
1172                     {
1173                         if ( !mpEntryList->IsEntryPosSelected( n ) )
1174                         {
1175                             SelectEntry( n, sal_True );
1176                             bSelectionChanged = sal_True;
1177                         }
1178                     }
1179 
1180                     // Ggf. muss noch was deselektiert werden...
1181                     sal_uInt16 nLast = mpEntryList->GetLastSelected();
1182                     if ( nLast != LISTBOX_ENTRY_NOTFOUND )
1183                     {
1184                         if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1185                         {
1186                             for ( sal_uInt16 n = nSelect+1; n <= nLast; n++ )
1187                             {
1188                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1189                                 {
1190                                     SelectEntry( n, sal_False );
1191                                     bSelectionChanged = sal_True;
1192                                 }
1193                             }
1194                         }
1195                         else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1196                         {
1197                             for ( sal_uInt16 n = nLast; n < nSelect; n++ )
1198                             {
1199                                 if ( mpEntryList->IsEntryPosSelected( n ) )
1200                                 {
1201                                     SelectEntry( n, sal_False );
1202                                     bSelectionChanged = sal_True;
1203                                 }
1204                             }
1205                         }
1206                     }
1207                     mpEntryList->SetLastSelected( nSelect );
1208                 }
1209             }
1210             else if( eLET != LET_TRACKING )
1211             {
1212                 ImplHideFocusRect();
1213                 ImplPaint( nSelect, sal_True );
1214                 bFocusChanged = sal_True;
1215             }
1216         }
1217         else if( bShift )
1218         {
1219             bFocusChanged = sal_True;
1220         }
1221 
1222         if( bSelectionChanged )
1223             mbSelectionChanged = sal_True;
1224 
1225         if( bFocusChanged )
1226         {
1227             long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop, 0 );
1228             maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1229             Size aSz( maFocusRect.GetWidth(),
1230                       mpEntryList->GetEntryHeight( nSelect ) );
1231             maFocusRect.SetSize( aSz );
1232             if( HasFocus() )
1233                 ImplShowFocusRect();
1234 //IAccessibility2 Implementation 2009----
1235             if (bSelectPosChange)
1236             {
1237                 maFocusHdl.Call(reinterpret_cast<void*>(nSelect));
1238             }
1239 //----IAccessibility2 Implementation 2009
1240         }
1241         ImplClearLayoutData();
1242     }
1243     return bSelectionChanged;
1244 }
1245 
1246 // -----------------------------------------------------------------------
1247 
1248 void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1249 {
1250     Point aPoint;
1251     Rectangle aRect( aPoint, GetOutputSizePixel() );
1252     sal_Bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1253 
1254     if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1255     {
1256         if ( bInside && !rTEvt.IsTrackingCanceled() )
1257         {
1258             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1259             ImplCallSelect();
1260         }
1261         else
1262         {
1263             maCancelHdl.Call( NULL );
1264             if ( !mbMulti )
1265             {
1266                 mbTrackingSelect = sal_True;
1267                 SelectEntry( mnTrackingSaveSelection, sal_True );
1268                 mbTrackingSelect = sal_False;
1269                 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND )
1270                 {
1271                     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1272                     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1273                     Size aSz( maFocusRect.GetWidth(),
1274                               mpEntryList->GetEntryHeight( mnCurrentPos ) );
1275                     maFocusRect.SetSize( aSz );
1276                     ImplShowFocusRect();
1277                 }
1278             }
1279         }
1280 
1281         mbTrack = sal_False;
1282     }
1283     else
1284     {
1285         sal_Bool bTrackOrQuickClick = mbTrack;
1286         if( !mbTrack )
1287         {
1288             if ( bInside )
1289             {
1290                 mbTrack = sal_True;
1291             }
1292 
1293             // Folgender Fall tritt nur auf, wenn man ganz kurz die Maustaste drueckt
1294             if( rTEvt.IsTrackingEnded() && mbTrack )
1295             {
1296                 bTrackOrQuickClick = sal_True;
1297                 mbTrack = sal_False;
1298             }
1299         }
1300 
1301         if( bTrackOrQuickClick )
1302         {
1303             MouseEvent aMEvt = rTEvt.GetMouseEvent();
1304             Point aPt( aMEvt.GetPosPixel() );
1305             sal_Bool bShift = aMEvt.IsShift();
1306             sal_Bool bCtrl  = aMEvt.IsMod1();
1307 
1308             sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1309             if( aPt.Y() < 0 )
1310             {
1311                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1312                 {
1313                     nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1314                     if( nSelect < mnTop )
1315                         SetTopEntry( mnTop-1 );
1316                 }
1317             }
1318             else if( aPt.Y() > GetOutputSizePixel().Height() )
1319             {
1320                 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1321                 {
1322                     nSelect = Min(  (sal_uInt16)(mnCurrentPos+1), (sal_uInt16)(mpEntryList->GetEntryCount()-1) );
1323                     if( nSelect >= GetLastVisibleEntry() )
1324                         SetTopEntry( mnTop+1 );
1325                 }
1326             }
1327             else
1328             {
1329                 nSelect = (sal_uInt16) ( ( aPt.Y() + mnBorder ) / mnMaxHeight ) + (sal_uInt16) mnTop;
1330                 nSelect = Min( nSelect, GetLastVisibleEntry() );
1331                 nSelect = Min( nSelect, (sal_uInt16) ( mpEntryList->GetEntryCount() - 1 ) );
1332             }
1333 
1334             if ( bInside )
1335             {
1336                 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectEntryCount() )
1337                 {
1338                     mbTrackingSelect = sal_True;
1339                     if ( SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl ) )
1340                     {
1341                         if ( mbStackMode ) // #87734# (#87072#)
1342                         {
1343                             mbTravelSelect = sal_True;
1344                             mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1345                             ImplCallSelect();
1346                             mbTravelSelect = sal_False;
1347                         }
1348                     }
1349                     mbTrackingSelect = sal_False;
1350                 }
1351             }
1352             else
1353             {
1354                 if ( !mbMulti && GetEntryList()->GetSelectEntryCount() )
1355                 {
1356                     mbTrackingSelect = sal_True;
1357                     SelectEntry( GetEntryList()->GetSelectEntryPos( 0 ), sal_False );
1358                     mbTrackingSelect = sal_False;
1359                 }
1360                 else if ( mbStackMode )
1361                 {
1362                     if ( ( rTEvt.GetMouseEvent().GetPosPixel().X() > 0 )  && ( rTEvt.GetMouseEvent().GetPosPixel().X() < aRect.Right() ) )
1363                     {
1364                         if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 ) || ( rTEvt.GetMouseEvent().GetPosPixel().Y() > GetOutputSizePixel().Height() ) )
1365                         {
1366                             sal_Bool bSelectionChanged = sal_False;
1367                             if ( ( rTEvt.GetMouseEvent().GetPosPixel().Y() < 0 )
1368                                    && !mnCurrentPos )
1369                             {
1370                                 if ( mpEntryList->IsEntryPosSelected( 0 ) )
1371                                 {
1372                                     SelectEntry( 0, sal_False );
1373                                     bSelectionChanged = sal_True;
1374                                     nSelect = LISTBOX_ENTRY_NOTFOUND;
1375 
1376                                 }
1377                             }
1378                             else
1379                             {
1380                                 mbTrackingSelect = sal_True;
1381                                 bSelectionChanged = SelectEntries( nSelect, LET_TRACKING, bShift, bCtrl );
1382                                 mbTrackingSelect = sal_False;
1383                             }
1384 
1385                             if ( bSelectionChanged )
1386                             {
1387                                 mbSelectionChanged = sal_True;
1388                                 mbTravelSelect = sal_True;
1389                                 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1390                                 ImplCallSelect();
1391                                 mbTravelSelect = sal_False;
1392                             }
1393                         }
1394                     }
1395                 }
1396             }
1397             mnCurrentPos = nSelect;
1398             if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1399             {
1400                 ImplHideFocusRect();
1401             }
1402             else
1403             {
1404                 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1405                 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1406                 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1407                 maFocusRect.SetSize( aSz );
1408                 ImplShowFocusRect();
1409             }
1410         }
1411     }
1412 }
1413 
1414 
1415 // -----------------------------------------------------------------------
1416 
1417 void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1418 {
1419     if( !ProcessKeyInput( rKEvt ) )
1420         Control::KeyInput( rKEvt );
1421 }
1422 
1423 // -----------------------------------------------------------------------
1424 
1425 #define IMPL_SELECT_NODIRECTION 0
1426 #define IMPL_SELECT_UP          1
1427 #define IMPL_SELECT_DOWN        2
1428 
1429 sal_Bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1430 {
1431     // zu selektierender Eintrag
1432     sal_uInt16 nSelect = LISTBOX_ENTRY_NOTFOUND;
1433     LB_EVENT_TYPE eLET = LET_KEYMOVE;
1434 
1435     KeyCode aKeyCode = rKEvt.GetKeyCode();
1436 
1437     sal_Bool bShift = aKeyCode.IsShift();
1438     sal_Bool bCtrl  = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1439     sal_Bool bMod2 = aKeyCode.IsMod2();
1440     sal_Bool bDone = sal_False;
1441 
1442     switch( aKeyCode.GetCode() )
1443     {
1444         case KEY_UP:
1445         {
1446             if ( IsReadOnly() )
1447             {
1448                 if ( GetTopEntry() )
1449                     SetTopEntry( GetTopEntry()-1 );
1450             }
1451             else if ( !bMod2 )
1452             {
1453                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1454                 {
1455                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1456                 }
1457                 else if ( mnCurrentPos )
1458                 {
1459                     // search first selectable above the current position
1460                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1461                 }
1462 
1463                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect < mnTop ) )
1464                     SetTopEntry( mnTop-1 );
1465 
1466                 bDone = sal_True;
1467             }
1468             maQuickSelectionEngine.Reset();
1469         }
1470         break;
1471 
1472         case KEY_DOWN:
1473         {
1474             if ( IsReadOnly() )
1475             {
1476                 SetTopEntry( GetTopEntry()+1 );
1477             }
1478             else if ( !bMod2 )
1479             {
1480                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1481                 {
1482                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1483                 }
1484                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1485                 {
1486                     // search first selectable below the current position
1487                     nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1, true );
1488                 }
1489 
1490                 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND ) && ( nSelect >= GetLastVisibleEntry() ) )
1491                     SetTopEntry( mnTop+1 );
1492 
1493                 bDone = sal_True;
1494             }
1495             maQuickSelectionEngine.Reset();
1496         }
1497         break;
1498 
1499         case KEY_PAGEUP:
1500         {
1501             if ( IsReadOnly() )
1502             {
1503                 sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1504                 SetTopEntry( ( mnTop > nCurVis ) ?
1505                                 (mnTop-nCurVis) : 0 );
1506             }
1507             else if ( !bCtrl && !bMod2 )
1508             {
1509                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1510                 {
1511                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1512                 }
1513                 else if ( mnCurrentPos )
1514                 {
1515                     if( mnCurrentPos == mnTop )
1516                     {
1517                         sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop +1;
1518                         SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1519                     }
1520 
1521                     // find first selectable starting from mnTop looking foreward
1522                     nSelect = mpEntryList->FindFirstSelectable( mnTop, true );
1523                 }
1524                 bDone = sal_True;
1525             }
1526             maQuickSelectionEngine.Reset();
1527         }
1528         break;
1529 
1530         case KEY_PAGEDOWN:
1531         {
1532             if ( IsReadOnly() )
1533             {
1534                 SetTopEntry( GetLastVisibleEntry() );
1535             }
1536             else if ( !bCtrl && !bMod2 )
1537             {
1538                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1539                 {
1540                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1541                 }
1542                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1543                 {
1544                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1545                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop;
1546                     sal_uInt16 nTmp = Min( nCurVis, nCount );
1547                     nTmp += mnTop - 1;
1548                     if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1549                     {
1550                         long nTmp2 = Min( (long)(nCount-nCurVis), (long)((long)mnTop+(long)nCurVis-1) );
1551                         nTmp2 = Max( (long)0 , nTmp2 );
1552                         nTmp = (sal_uInt16)(nTmp2+(nCurVis-1) );
1553                         SetTopEntry( (sal_uInt16)nTmp2 );
1554                     }
1555                     // find first selectable starting from nTmp looking backwards
1556                     nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1557                 }
1558                 bDone = sal_True;
1559             }
1560             maQuickSelectionEngine.Reset();
1561         }
1562         break;
1563 
1564         case KEY_HOME:
1565         {
1566             if ( IsReadOnly() )
1567             {
1568                 SetTopEntry( 0 );
1569             }
1570             else if ( !bCtrl && !bMod2 )
1571             {
1572                 if ( mnCurrentPos )
1573                 {
1574                     nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND, true );
1575                     if( mnTop != 0 )
1576                         SetTopEntry( 0 );
1577 
1578                     bDone = sal_True;
1579                 }
1580             }
1581             maQuickSelectionEngine.Reset();
1582         }
1583         break;
1584 
1585         case KEY_END:
1586         {
1587             if ( IsReadOnly() )
1588             {
1589                 SetTopEntry( 0xFFFF );
1590             }
1591             else if ( !bCtrl && !bMod2 )
1592             {
1593                 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND )
1594                 {
1595                     nSelect = mpEntryList->FindFirstSelectable( 0, true );
1596                 }
1597                 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1598                 {
1599                     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1600                     nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1601                     sal_uInt16 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1602                     if( nCount > nCurVis )
1603                         SetTopEntry( nCount - nCurVis );
1604                 }
1605                 bDone = sal_True;
1606             }
1607             maQuickSelectionEngine.Reset();
1608         }
1609         break;
1610 
1611         case KEY_LEFT:
1612         {
1613             if ( !bCtrl && !bMod2 )
1614             {
1615                 ScrollHorz( -HORZ_SCROLL );
1616                 bDone = sal_True;
1617             }
1618             maQuickSelectionEngine.Reset();
1619         }
1620         break;
1621 
1622         case KEY_RIGHT:
1623         {
1624             if ( !bCtrl && !bMod2 )
1625             {
1626                 ScrollHorz( HORZ_SCROLL );
1627                 bDone = sal_True;
1628             }
1629             maQuickSelectionEngine.Reset();
1630         }
1631         break;
1632 
1633         case KEY_RETURN:
1634         {
1635             if ( !bMod2 && !IsReadOnly() )
1636             {
1637                 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1638                 ImplCallSelect();
1639                 bDone = sal_False;  // RETURN nicht abfangen.
1640             }
1641             maQuickSelectionEngine.Reset();
1642         }
1643         break;
1644 
1645         case KEY_SPACE:
1646         {
1647             if ( !bMod2 && !IsReadOnly() )
1648             {
1649                 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) || mbStackMode ) )
1650                 {
1651                     nSelect = mnCurrentPos;
1652                     eLET = LET_KEYSPACE;
1653                 }
1654                 bDone = sal_True;
1655             }
1656             maQuickSelectionEngine.Reset();
1657         }
1658         break;
1659 
1660         case KEY_A:
1661         {
1662             if( bCtrl && mbMulti )
1663             {
1664                 // paint only once
1665                 sal_Bool bUpdates = IsUpdateMode();
1666                 SetUpdateMode( sal_False );
1667 
1668                 sal_uInt16 nEntryCount = mpEntryList->GetEntryCount();
1669                 for( sal_uInt16 i = 0; i < nEntryCount; i++ )
1670                     SelectEntry( i, sal_True );
1671 
1672                 // restore update mode
1673                 SetUpdateMode( bUpdates );
1674                 Invalidate();
1675 
1676                 maQuickSelectionEngine.Reset();
1677 
1678                 bDone = sal_True;
1679                 break;
1680             }
1681         }
1682         // fall through intentional
1683         default:
1684         {
1685             if ( !IsReadOnly() )
1686             {
1687                 bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1688             }
1689         }
1690         break;
1691     }
1692 
1693     if  (   ( nSelect != LISTBOX_ENTRY_NOTFOUND )
1694         &&  (   ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1695             ||  ( eLET == LET_KEYSPACE )
1696             )
1697         )
1698     {
1699         DBG_ASSERT( !mpEntryList->IsEntryPosSelected( nSelect ) || mbMulti, "ImplListBox: Selecting same Entry" );
1700         if( nSelect >= mpEntryList->GetEntryCount() )
1701             nSelect = mpEntryList->GetEntryCount()-1;
1702 //IAccessibility2 Implementation 2009-----
1703         sal_Bool bCurPosChange = (mnCurrentPos != nSelect);
1704         mnCurrentPos = nSelect;
1705         //if ( SelectEntries( nSelect, eLET, bShift, bCtrl ) )
1706         if(SelectEntries( nSelect, eLET, bShift, bCtrl ,bCurPosChange))
1707 //-----IAccessibility2 Implementation 2009
1708         {
1709             mbTravelSelect = sal_True;
1710             mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1711             ImplCallSelect();
1712             mbTravelSelect = sal_False;
1713         }
1714     }
1715 
1716     return bDone;
1717 }
1718 
1719 // -----------------------------------------------------------------------
1720 namespace
1721 {
1722     static ::vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_uInt16 _nPos, String& _out_entryText )
1723     {
1724         OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" );
1725         sal_uInt16 nEntryCount( _rList.GetEntryCount() );
1726         if ( _nPos >= nEntryCount )
1727             _nPos = 0;
1728         _out_entryText = _rList.GetEntryText( _nPos );
1729 
1730         // ::vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1731         // => normalize
1732         return reinterpret_cast< ::vcl::StringEntryIdentifier >( _nPos + 1 );
1733     }
1734 
1735     static sal_uInt16 lcl_getEntryPos( ::vcl::StringEntryIdentifier _entry )
1736     {
1737         // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1738         return static_cast< sal_uInt16 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1739     }
1740 }
1741 
1742 // -----------------------------------------------------------------------
1743 ::vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( String& _out_entryText ) const
1744 {
1745     return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND ) ? 0 : mnCurrentPos + 1, _out_entryText );
1746 }
1747 
1748 // -----------------------------------------------------------------------
1749 ::vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
1750 {
1751     sal_uInt16 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1752     return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1753 }
1754 
1755 // -----------------------------------------------------------------------
1756 void ImplListBoxWindow::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1757 {
1758     sal_uInt16 nSelect = lcl_getEntryPos( _entry );
1759     if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1760     {
1761         // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1762         // to select the given entry by typing its starting letters. No need to act.
1763         return;
1764     }
1765 
1766     // normalize
1767     OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" );
1768     if( nSelect >= mpEntryList->GetEntryCount() )
1769         nSelect = mpEntryList->GetEntryCount()-1;
1770 
1771     // make visible
1772     ShowProminentEntry( nSelect );
1773 
1774     // actually select
1775     mnCurrentPos = nSelect;
1776     if ( SelectEntries( nSelect, LET_KEYMOVE, sal_False, sal_False ) )
1777     {
1778         mbTravelSelect = sal_True;
1779         mnSelectModifier = 0;
1780         ImplCallSelect();
1781         mbTravelSelect = sal_False;
1782     }
1783 }
1784 
1785 // -----------------------------------------------------------------------
1786 
1787 void ImplListBoxWindow::ImplPaint( sal_uInt16 nPos, sal_Bool bErase, bool bLayout )
1788 {
1789     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1790 
1791     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1792     if( ! pEntry )
1793         return;
1794 
1795     long nWidth  = GetOutputSizePixel().Width();
1796     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1797     Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1798 
1799     if( ! bLayout )
1800     {
1801         if( mpEntryList->IsEntryPosSelected( nPos ) )
1802         {
1803             SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1804             SetFillColor( rStyleSettings.GetHighlightColor() );
1805             SetTextFillColor( rStyleSettings.GetHighlightColor() );
1806             DrawRect( aRect );
1807         }
1808         else
1809         {
1810             ImplInitSettings( sal_False, sal_True, sal_False );
1811             if( !IsEnabled() )
1812                 SetTextColor( rStyleSettings.GetDisableColor() );
1813             SetTextFillColor();
1814             if( bErase )
1815                 Erase( aRect );
1816         }
1817     }
1818 
1819     if ( IsUserDrawEnabled() )
1820     {
1821         mbInUserDraw = sal_True;
1822         mnUserDrawEntry = nPos;
1823         aRect.Left() -= mnLeft;
1824         if ( nPos < GetEntryList()->GetMRUCount() )
1825             nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1826         nPos = sal::static_int_cast<sal_uInt16>(nPos - GetEntryList()->GetMRUCount());
1827         UserDrawEvent aUDEvt( this, aRect, nPos, 0 );
1828         maUserDrawHdl.Call( &aUDEvt );
1829         mbInUserDraw = sal_False;
1830     }
1831     else
1832     {
1833         DrawEntry( nPos, sal_True, sal_True, sal_False, bLayout );
1834     }
1835 }
1836 
1837 // -----------------------------------------------------------------------
1838 
1839 void ImplListBoxWindow::DrawEntry( sal_uInt16 nPos, sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
1840 {
1841     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1842     if( ! pEntry )
1843         return;
1844 
1845     // Bei Aenderungen in dieser Methode ggf. auch ImplWin::DrawEntry() anpassen.
1846 
1847     if ( mbInUserDraw )
1848         nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1849 
1850     long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1851     Size aImgSz;
1852 
1853     if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1854     {
1855         Image aImage = mpEntryList->GetEntryImage( nPos );
1856         if( !!aImage )
1857         {
1858             aImgSz = aImage.GetSizePixel();
1859             Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1860 
1861             // pb: #106948# explicit mirroring for calc
1862             if ( mbMirroring )
1863                 // right aligned
1864                 aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1865 
1866             if ( !IsZoom() )
1867             {
1868                 DrawImage( aPtImg, aImage );
1869             }
1870             else
1871             {
1872                 aImgSz.Width() = CalcZoom( aImgSz.Width() );
1873                 aImgSz.Height() = CalcZoom( aImgSz.Height() );
1874                 DrawImage( aPtImg, aImgSz, aImage );
1875             }
1876         }
1877     }
1878 
1879     if( bDrawText )
1880     {
1881         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1882         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1883         XubString aStr( mpEntryList->GetEntryText( nPos ) );
1884         if ( aStr.Len() )
1885         {
1886             long nMaxWidth = Max( static_cast< long >( mnMaxWidth ),
1887                                   GetOutputSizePixel().Width() - 2*mnBorder );
1888             // a multiline entry should only be as wide a the window
1889             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1890                 nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1891 
1892             Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1893                                  Size( nMaxWidth, pEntry->mnHeight ) );
1894 
1895             if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1896             {
1897                 long nImageWidth = Max( mnMaxImgWidth, maUserItemSize.Width() );
1898                 aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1899             }
1900 
1901             if( bLayout )
1902                 mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.Len() );
1903 
1904             // pb: #106948# explicit mirroring for calc
1905             if ( mbMirroring )
1906             {
1907                 // right aligned
1908                 aTextRect.Left() = nMaxWidth + mnBorder - GetTextWidth( aStr ) - mnLeft;
1909                 if ( aImgSz.Width() > 0 )
1910                     aTextRect.Left() -= ( aImgSz.Width() + IMG_TXT_DISTANCE );
1911             }
1912 
1913             sal_uInt16 nDrawStyle = ImplGetTextStyle();
1914             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1915                 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1916             if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
1917                 nDrawStyle |= TEXT_DRAW_DISABLE;
1918 
1919             DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1920         }
1921     }
1922 
1923     if( !bLayout )
1924     {
1925         if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1926              ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1927         {
1928             Color aOldLineColor( GetLineColor() );
1929             SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1930             Point aStartPos( 0, nY );
1931             if ( nPos == mnSeparatorPos )
1932                 aStartPos.Y() += pEntry->mnHeight-1;
1933             Point aEndPos( aStartPos );
1934             aEndPos.X() = GetOutputSizePixel().Width();
1935             DrawLine( aStartPos, aEndPos );
1936             SetLineColor( aOldLineColor );
1937         }
1938     }
1939 }
1940 
1941 // -----------------------------------------------------------------------
1942 
1943 void ImplListBoxWindow::FillLayoutData() const
1944 {
1945     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1946     const_cast<ImplListBoxWindow*>(this)->
1947         ImplDoPaint( Rectangle( Point( 0, 0 ), GetOutputSize() ), true );
1948 }
1949 
1950 // -----------------------------------------------------------------------
1951 
1952 void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1953 {
1954     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1955 
1956     sal_Bool bShowFocusRect = mbHasFocusRect;
1957     if ( mbHasFocusRect && ! bLayout )
1958         ImplHideFocusRect();
1959 
1960     long nY = 0; // + mnBorder;
1961     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1962 
1963     for( sal_uInt16 i = (sal_uInt16)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1964     {
1965         const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1966         if( nY + pEntry->mnHeight >= rRect.Top() &&
1967             nY <= rRect.Bottom() + mnMaxHeight )
1968         {
1969             ImplPaint( i, sal_False, bLayout );
1970         }
1971         nY += pEntry->mnHeight;
1972     }
1973 
1974     long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1975     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1976     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1977     maFocusRect.SetSize( aSz );
1978     if( HasFocus() && bShowFocusRect && !bLayout )
1979         ImplShowFocusRect();
1980 }
1981 
1982 // -----------------------------------------------------------------------
1983 
1984 void ImplListBoxWindow::Paint( const Rectangle& rRect )
1985 {
1986     ImplDoPaint( rRect );
1987 }
1988 
1989 // -----------------------------------------------------------------------
1990 
1991 sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1992 {
1993     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1994 
1995     sal_uInt16 nCount = mpEntryList->GetEntryCount();
1996     long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1997     sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1998     if( nEntries > nCount-mnTop )
1999         nEntries = nCount-mnTop;
2000 
2001     return nEntries;
2002 }
2003 
2004 // -----------------------------------------------------------------------
2005 
2006 void ImplListBoxWindow::Resize()
2007 {
2008     Control::Resize();
2009 
2010     sal_Bool bShowFocusRect = mbHasFocusRect;
2011     if ( bShowFocusRect )
2012         ImplHideFocusRect();
2013 
2014     if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
2015     {
2016         Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
2017         maFocusRect.SetSize( aSz );
2018     }
2019 
2020     if ( bShowFocusRect )
2021         ImplShowFocusRect();
2022 
2023     ImplClearLayoutData();
2024 }
2025 
2026 // -----------------------------------------------------------------------
2027 
2028 void ImplListBoxWindow::GetFocus()
2029 {
2030     sal_uInt16 nPos = mnCurrentPos;
2031     if ( nPos == LISTBOX_ENTRY_NOTFOUND )
2032         nPos = 0;
2033     long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop, 0 );
2034     maFocusRect.SetPos( Point( 0, nHeightDiff ) );
2035     Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
2036     maFocusRect.SetSize( aSz );
2037     ImplShowFocusRect();
2038     Control::GetFocus();
2039 }
2040 
2041 // -----------------------------------------------------------------------
2042 
2043 void ImplListBoxWindow::LoseFocus()
2044 {
2045     ImplHideFocusRect();
2046     Control::LoseFocus();
2047 }
2048 
2049 // -----------------------------------------------------------------------
2050 
2051 /*
2052 void ImplListBoxWindow::RequestHelp( const HelpEvent& rHEvt )
2053 {
2054     if ( rHEvt.GetMode() & HELPMODE_BALLOON )
2055         Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), String() );
2056 
2057     Window::RequestHelp( rHEvt );
2058 }
2059 */
2060 
2061 // -----------------------------------------------------------------------
2062 
2063 void ImplListBoxWindow::SetTopEntry( sal_uInt16 nTop )
2064 {
2065     if( mpEntryList->GetEntryCount() == 0 )
2066         return;
2067 
2068     long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2069 
2070     sal_uInt16 nLastEntry = mpEntryList->GetEntryCount()-1;
2071     if( nTop > nLastEntry )
2072         nTop = nLastEntry;
2073     const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
2074     while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
2075         nTop--;
2076 
2077     if ( nTop != mnTop )
2078     {
2079         ImplClearLayoutData();
2080         long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
2081         Update();
2082         ImplHideFocusRect();
2083         mnTop = nTop;
2084         Scroll( 0, nDiff );
2085         Update();
2086         if( HasFocus() )
2087             ImplShowFocusRect();
2088         maScrollHdl.Call( this );
2089     }
2090 }
2091 
2092 // -----------------------------------------------------------------------
2093 
2094 void ImplListBoxWindow::ShowProminentEntry( sal_uInt16 nEntryPos )
2095 {
2096     if( meProminentType == PROMINENT_MIDDLE )
2097     {
2098         sal_uInt16 nPos = nEntryPos;
2099         long nWHeight = PixelToLogic( GetSizePixel() ).Height();
2100         while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
2101             nEntryPos--;
2102     }
2103     SetTopEntry( nEntryPos );
2104 }
2105 
2106 // -----------------------------------------------------------------------
2107 
2108 void ImplListBoxWindow::SetLeftIndent( long n )
2109 {
2110     ScrollHorz( n - mnLeft );
2111 }
2112 
2113 // -----------------------------------------------------------------------
2114 
2115 void ImplListBoxWindow::ScrollHorz( long n )
2116 {
2117     long nDiff = 0;
2118     if ( n > 0 )
2119     {
2120         long nWidth = GetOutputSizePixel().Width();
2121         if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2122             nDiff = n;
2123     }
2124     else if ( n < 0 )
2125     {
2126         if( mnLeft )
2127         {
2128             long nAbs = -n;
2129             nDiff = - ( ( mnLeft > nAbs ) ? nAbs : mnLeft );
2130         }
2131     }
2132 
2133     if ( nDiff )
2134     {
2135         ImplClearLayoutData();
2136         mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
2137         Update();
2138         ImplHideFocusRect();
2139         Scroll( -nDiff, 0 );
2140         Update();
2141         if( HasFocus() )
2142             ImplShowFocusRect();
2143         maScrollHdl.Call( this );
2144     }
2145 }
2146 
2147 // -----------------------------------------------------------------------
2148 
2149 Size ImplListBoxWindow::CalcSize( sal_uInt16 nMaxLines ) const
2150 {
2151     // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2152 
2153     Size aSz;
2154 //  sal_uInt16 nL = Min( nMaxLines, mpEntryList->GetEntryCount() );
2155     aSz.Height() =  nMaxLines * mnMaxHeight;
2156     aSz.Width() = mnMaxWidth + 2*mnBorder;
2157     return aSz;
2158 }
2159 
2160 // -----------------------------------------------------------------------
2161 
2162 Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_uInt16 nItem ) const
2163 {
2164     const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
2165     Size aSz( GetSizePixel().Width(), pEntry ? pEntry->mnHeight : GetEntryHeight() );
2166     //long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) - mpEntryList->GetAddedHeight( GetTopEntry() );
2167     //IAccessibility2 Impplementaton 2009-----
2168     long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeight();
2169     //-----IAccessibility2 Impplementaton 2009
2170     Rectangle aRect( Point( 0, nY ), aSz );
2171     return aRect;
2172 }
2173 
2174 
2175 // -----------------------------------------------------------------------
2176 
2177 void ImplListBoxWindow::StateChanged( StateChangedType nType )
2178 {
2179     Control::StateChanged( nType );
2180 
2181     if ( nType == STATE_CHANGE_ZOOM )
2182     {
2183         ImplInitSettings( sal_True, sal_False, sal_False );
2184         ImplCalcMetrics();
2185         Invalidate();
2186     }
2187     else if ( nType == STATE_CHANGE_UPDATEMODE )
2188     {
2189         if ( IsUpdateMode() && IsReallyVisible() )
2190             Invalidate();
2191     }
2192     else if ( nType == STATE_CHANGE_CONTROLFONT )
2193     {
2194         ImplInitSettings( sal_True, sal_False, sal_False );
2195         ImplCalcMetrics();
2196         Invalidate();
2197     }
2198     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2199     {
2200         ImplInitSettings( sal_False, sal_True, sal_False );
2201         Invalidate();
2202     }
2203     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2204     {
2205         ImplInitSettings( sal_False, sal_False, sal_True );
2206         Invalidate();
2207     }
2208     ImplClearLayoutData();
2209 }
2210 
2211 // -----------------------------------------------------------------------
2212 
2213 void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2214 {
2215     Control::DataChanged( rDCEvt );
2216 
2217     if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2218          (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2219          ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2220           (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2221     {
2222         ImplClearLayoutData();
2223         ImplInitSettings( sal_True, sal_True, sal_True );
2224         ImplCalcMetrics();
2225         Invalidate();
2226     }
2227 }
2228 
2229 // -----------------------------------------------------------------------
2230 
2231 sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
2232 {
2233     sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2234 
2235     if ( mpEntryList->HasImages() )
2236         nTextStyle |= TEXT_DRAW_LEFT;
2237     else if ( mbCenter )
2238         nTextStyle |= TEXT_DRAW_CENTER;
2239     else if ( mbRight )
2240         nTextStyle |= TEXT_DRAW_RIGHT;
2241     else
2242         nTextStyle |= TEXT_DRAW_LEFT;
2243 
2244     return nTextStyle;
2245 }
2246 
2247 // =======================================================================
2248 
2249 ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2250     Control( pParent, nWinStyle ),
2251     maLBWindow( this, nWinStyle&(~WB_BORDER) )
2252 {
2253     // for native widget rendering we must be able to detect this window type
2254     SetType( WINDOW_LISTBOXWINDOW );
2255 
2256     mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2257     mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2258     mpScrollBarBox  = new ScrollBarBox( this );
2259 
2260     Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2261     mpVScrollBar->SetScrollHdl( aLink );
2262     mpHScrollBar->SetScrollHdl( aLink );
2263 
2264     mbVScroll       = sal_False;
2265     mbHScroll       = sal_False;
2266     mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL ) ? sal_True : sal_False;
2267 
2268     maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2269     maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2270     maLBWindow.Show();
2271 }
2272 
2273 // -----------------------------------------------------------------------
2274 
2275 ImplListBox::~ImplListBox()
2276 {
2277     delete mpHScrollBar;
2278     delete mpVScrollBar;
2279     delete mpScrollBarBox;
2280 }
2281 
2282 // -----------------------------------------------------------------------
2283 
2284 void ImplListBox::Clear()
2285 {
2286     maLBWindow.Clear();
2287     if ( GetEntryList()->GetMRUCount() )
2288     {
2289         maLBWindow.GetEntryList()->SetMRUCount( 0 );
2290         maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2291     }
2292     mpVScrollBar->SetThumbPos( 0 );
2293     mpHScrollBar->SetThumbPos( 0 );
2294     StateChanged( STATE_CHANGE_DATA );
2295 }
2296 
2297 // -----------------------------------------------------------------------
2298 
2299 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr )
2300 {
2301     ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2302     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2303     StateChanged( STATE_CHANGE_DATA );
2304     return nNewPos;
2305 }
2306 
2307 // -----------------------------------------------------------------------
2308 
2309 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const Image& rImage )
2310 {
2311     ImplEntryType* pNewEntry = new ImplEntryType( rImage );
2312     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2313     StateChanged( STATE_CHANGE_DATA );
2314     return nNewPos;
2315 }
2316 
2317 // -----------------------------------------------------------------------
2318 
2319 sal_uInt16 ImplListBox::InsertEntry( sal_uInt16 nPos, const XubString& rStr, const Image& rImage )
2320 {
2321     ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2322     sal_uInt16 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2323     StateChanged( STATE_CHANGE_DATA );
2324     return nNewPos;
2325 }
2326 
2327 // -----------------------------------------------------------------------
2328 
2329 void ImplListBox::RemoveEntry( sal_uInt16 nPos )
2330 {
2331     maLBWindow.RemoveEntry( nPos );
2332     StateChanged( STATE_CHANGE_DATA );
2333 }
2334 
2335 // -----------------------------------------------------------------------
2336 
2337 void ImplListBox::SetEntryFlags( sal_uInt16 nPos, long nFlags )
2338 {
2339     maLBWindow.SetEntryFlags( nPos, nFlags );
2340 }
2341 
2342 // -----------------------------------------------------------------------
2343 
2344 long ImplListBox::GetEntryFlags( sal_uInt16 nPos ) const
2345 {
2346     return maLBWindow.GetEntryList()->GetEntryFlags( nPos );
2347 }
2348 
2349 // -----------------------------------------------------------------------
2350 
2351 void ImplListBox::SelectEntry( sal_uInt16 nPos, sal_Bool bSelect )
2352 {
2353     maLBWindow.SelectEntry( nPos, bSelect );
2354 }
2355 
2356 // -----------------------------------------------------------------------
2357 
2358 void ImplListBox::SetNoSelection()
2359 {
2360     maLBWindow.DeselectAll();
2361 }
2362 
2363 // -----------------------------------------------------------------------
2364 
2365 void ImplListBox::GetFocus()
2366 {
2367     maLBWindow.GrabFocus();
2368 }
2369 
2370 // -----------------------------------------------------------------------
2371 
2372 Window* ImplListBox::GetPreferredKeyInputWindow()
2373 {
2374     return &maLBWindow;
2375 }
2376 
2377 // -----------------------------------------------------------------------
2378 
2379 void ImplListBox::Resize()
2380 {
2381     Control::Resize();
2382     ImplResizeControls();
2383     ImplCheckScrollBars();
2384 }
2385 
2386 
2387 // -----------------------------------------------------------------------
2388 
2389 IMPL_LINK( ImplListBox, MRUChanged, void*, EMPTYARG )
2390 {
2391     StateChanged( STATE_CHANGE_DATA );
2392     return 1;
2393 }
2394 
2395 // -----------------------------------------------------------------------
2396 
2397 IMPL_LINK( ImplListBox, LBWindowScrolled, void*, EMPTYARG )
2398 {
2399     long nSet = GetTopEntry();
2400     if( nSet > mpVScrollBar->GetRangeMax() )
2401         mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2402     mpVScrollBar->SetThumbPos( GetTopEntry() );
2403 
2404     mpHScrollBar->SetThumbPos( GetLeftIndent() );
2405 
2406     maScrollHdl.Call( this );
2407 
2408     return 1;
2409 }
2410 
2411 // -----------------------------------------------------------------------
2412 
2413 IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2414 {
2415     sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2416     if( pSB == mpVScrollBar )
2417         SetTopEntry( nPos );
2418     else if( pSB == mpHScrollBar )
2419         SetLeftIndent( nPos );
2420 
2421     return 1;
2422 }
2423 
2424 // -----------------------------------------------------------------------
2425 
2426 void ImplListBox::ImplCheckScrollBars()
2427 {
2428     sal_Bool bArrange = sal_False;
2429 
2430     Size aOutSz = GetOutputSizePixel();
2431     sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2432     sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2433 
2434     // vert. ScrollBar
2435     if( nEntries > nMaxVisEntries )
2436     {
2437         if( !mbVScroll )
2438             bArrange = sal_True;
2439         mbVScroll = sal_True;
2440 
2441         // Ueberpruefung des rausgescrollten Bereichs
2442         if( GetEntryList()->GetSelectEntryCount() == 1 &&
2443             GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2444             ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2445         else
2446             SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2447     }
2448     else
2449     {
2450         if( mbVScroll )
2451             bArrange = sal_True;
2452         mbVScroll = sal_False;
2453         SetTopEntry( 0 );
2454     }
2455 
2456     // horz. ScrollBar
2457     if( mbAutoHScroll )
2458     {
2459         long nWidth = (sal_uInt16) aOutSz.Width();
2460         if ( mbVScroll )
2461             nWidth -= mpVScrollBar->GetSizePixel().Width();
2462 
2463         long nMaxWidth = GetMaxEntryWidth();
2464         if( nWidth < nMaxWidth )
2465         {
2466             if( !mbHScroll )
2467                 bArrange = sal_True;
2468             mbHScroll = sal_True;
2469 
2470             if ( !mbVScroll )   // ggf. brauchen wir jetzt doch einen
2471             {
2472                 nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2473                 if( nEntries > nMaxVisEntries )
2474                 {
2475                     bArrange = sal_True;
2476                     mbVScroll = sal_True;
2477 
2478                     // Ueberpruefung des rausgescrollten Bereichs
2479                     if( GetEntryList()->GetSelectEntryCount() == 1 &&
2480                         GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2481                         ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2482                     else
2483                         SetTopEntry( GetTopEntry() );   // MaxTop wird geprueft...
2484                 }
2485             }
2486 
2487             // Ueberpruefung des rausgescrollten Bereichs
2488             sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2489             if ( nMaxLI < GetLeftIndent() )
2490                 SetLeftIndent( nMaxLI );
2491         }
2492         else
2493         {
2494             if( mbHScroll )
2495                 bArrange = sal_True;
2496             mbHScroll = sal_False;
2497             SetLeftIndent( 0 );
2498         }
2499     }
2500 
2501     if( bArrange )
2502         ImplResizeControls();
2503 
2504     ImplInitScrollBars();
2505 }
2506 
2507 // -----------------------------------------------------------------------
2508 
2509 void ImplListBox::ImplInitScrollBars()
2510 {
2511     Size aOutSz = maLBWindow.GetOutputSizePixel();
2512 
2513     if ( mbVScroll )
2514     {
2515         sal_uInt16 nEntries = GetEntryList()->GetEntryCount();
2516         sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2517         mpVScrollBar->SetRangeMax( nEntries );
2518         mpVScrollBar->SetVisibleSize( nVisEntries );
2519         mpVScrollBar->SetPageSize( nVisEntries - 1 );
2520     }
2521 
2522     if ( mbHScroll )
2523     {
2524         mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2525         mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2526         mpHScrollBar->SetLineSize( HORZ_SCROLL );
2527         mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2528     }
2529 }
2530 
2531 // -----------------------------------------------------------------------
2532 
2533 void ImplListBox::ImplResizeControls()
2534 {
2535     // Hier werden die Controls nur angeordnet, ob die Scrollbars
2536     // sichtbar sein sollen wird bereits in ImplCheckScrollBars ermittelt.
2537 
2538     Size aOutSz = GetOutputSizePixel();
2539     long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2540     nSBWidth = CalcZoom( nSBWidth );
2541 
2542     Size aInnerSz( aOutSz );
2543     if ( mbVScroll )
2544         aInnerSz.Width() -= nSBWidth;
2545     if ( mbHScroll )
2546         aInnerSz.Height() -= nSBWidth;
2547 
2548     // pb: #106948# explicit mirroring for calc
2549     // Scrollbar on left or right side?
2550     sal_Bool bMirroring = maLBWindow.IsMirroring();
2551     Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2552     maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2553 
2554     // ScrollBarBox
2555     if( mbVScroll && mbHScroll )
2556     {
2557         Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2558         mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2559         mpScrollBarBox->Show();
2560     }
2561     else
2562     {
2563         mpScrollBarBox->Hide();
2564     }
2565 
2566     // vert. ScrollBar
2567     if( mbVScroll )
2568     {
2569         // Scrollbar on left or right side?
2570         Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2571         mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2572         mpVScrollBar->Show();
2573     }
2574     else
2575     {
2576         mpVScrollBar->Hide();
2577         // #107254# Don't reset top entry after resize, but check for max top entry
2578         SetTopEntry( GetTopEntry() );
2579     }
2580 
2581     // horz. ScrollBar
2582     if( mbHScroll )
2583     {
2584         Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2585         mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2586         mpHScrollBar->Show();
2587     }
2588     else
2589     {
2590         mpHScrollBar->Hide();
2591         SetLeftIndent( 0 );
2592     }
2593 }
2594 
2595 // -----------------------------------------------------------------------
2596 
2597 void ImplListBox::StateChanged( StateChangedType nType )
2598 {
2599     if ( nType == STATE_CHANGE_INITSHOW )
2600     {
2601         ImplCheckScrollBars();
2602     }
2603     else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2604     {
2605         sal_Bool bUpdate = IsUpdateMode();
2606         maLBWindow.SetUpdateMode( bUpdate );
2607 //      mpHScrollBar->SetUpdateMode( bUpdate );
2608 //      mpVScrollBar->SetUpdateMode( bUpdate );
2609         if ( bUpdate && IsReallyVisible() )
2610             ImplCheckScrollBars();
2611     }
2612     else if( nType == STATE_CHANGE_ENABLE )
2613     {
2614         mpHScrollBar->Enable( IsEnabled() );
2615         mpVScrollBar->Enable( IsEnabled() );
2616         mpScrollBarBox->Enable( IsEnabled() );
2617         Invalidate();
2618     }
2619     else if ( nType == STATE_CHANGE_ZOOM )
2620     {
2621         maLBWindow.SetZoom( GetZoom() );
2622         Resize();
2623     }
2624     else if ( nType == STATE_CHANGE_CONTROLFONT )
2625     {
2626         maLBWindow.SetControlFont( GetControlFont() );
2627     }
2628     else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2629     {
2630         maLBWindow.SetControlForeground( GetControlForeground() );
2631     }
2632     else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2633     {
2634         maLBWindow.SetControlBackground( GetControlBackground() );
2635     }
2636     else if( nType == STATE_CHANGE_MIRRORING )
2637     {
2638         maLBWindow.EnableRTL( IsRTLEnabled() );
2639         mpHScrollBar->EnableRTL( IsRTLEnabled() );
2640         mpVScrollBar->EnableRTL( IsRTLEnabled() );
2641         ImplResizeControls();
2642     }
2643 
2644     Control::StateChanged( nType );
2645 }
2646 
2647 // -----------------------------------------------------------------------
2648 
2649 void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2650 {
2651 //  if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2652 //       (rDCEvt.GetFlags() & SETTINGS_STYLE) )
2653 //  {
2654 //      maLBWindow.SetSettings( GetSettings() );
2655 //      Resize();
2656 //  }
2657 //  else
2658         Control::DataChanged( rDCEvt );
2659 }
2660 
2661 // -----------------------------------------------------------------------
2662 
2663 long ImplListBox::Notify( NotifyEvent& rNEvt )
2664 {
2665     long nDone = 0;
2666     if ( rNEvt.GetType() == EVENT_COMMAND )
2667     {
2668         const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2669         if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2670         {
2671             const CommandWheelData* pData = rCEvt.GetWheelData();
2672             if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2673             {
2674                 nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2675             }
2676         }
2677     }
2678 
2679     return nDone ? nDone : Window::Notify( rNEvt );
2680 }
2681 
2682 // -----------------------------------------------------------------------
2683 
2684 const Wallpaper& ImplListBox::GetDisplayBackground() const
2685 {
2686     return maLBWindow.GetDisplayBackground();
2687 }
2688 
2689 // -----------------------------------------------------------------------
2690 
2691 sal_Bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2692 {
2693     sal_Bool bDone = sal_False;
2694     if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2695     {
2696         const CommandWheelData* pData = rCEvt.GetWheelData();
2697         if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2698         {
2699             sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2700             KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2701             bDone = ProcessKeyInput( aKeyEvent );
2702         }
2703     }
2704     return bDone;
2705 }
2706 
2707 // -----------------------------------------------------------------------
2708 
2709 void ImplListBox::SetMRUEntries( const XubString& rEntries, xub_Unicode cSep )
2710 {
2711     sal_Bool bChanges = GetEntryList()->GetMRUCount() ? sal_True : sal_False;
2712 
2713     // Remove old MRU entries
2714     for ( sal_uInt16 n = GetEntryList()->GetMRUCount();n; )
2715         maLBWindow.RemoveEntry( --n );
2716 
2717     sal_uInt16 nMRUCount = 0;
2718     sal_uInt16 nEntries = rEntries.GetTokenCount( cSep );
2719     for ( sal_uInt16 nEntry = 0; nEntry < nEntries; nEntry++ )
2720     {
2721         XubString aEntry = rEntries.GetToken( nEntry, cSep );
2722         // Accept only existing entries
2723         if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2724         {
2725             ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2726             maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, sal_False );
2727             bChanges = sal_True;
2728         }
2729     }
2730 
2731     if ( bChanges )
2732     {
2733         maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2734         SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2735         StateChanged( STATE_CHANGE_DATA );
2736     }
2737 }
2738 
2739 // -----------------------------------------------------------------------
2740 
2741 XubString ImplListBox::GetMRUEntries( xub_Unicode cSep ) const
2742 {
2743     String aEntries;
2744     for ( sal_uInt16 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2745     {
2746         aEntries += GetEntryList()->GetEntryText( n );
2747         if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2748             aEntries += cSep;
2749     }
2750     return aEntries;
2751 }
2752 
2753 // =======================================================================
2754 
2755 ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2756     Control ( pParent, nWinStyle )
2757 {
2758     if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2759             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2760         SetBackground();
2761     else
2762         SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2763 
2764     mbInUserDraw = sal_False;
2765     mbUserDrawEnabled = sal_False;
2766     mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2767 }
2768 
2769 // -----------------------------------------------------------------------
2770 
2771 sal_Bool ImplWin::SetModeImage( const Image& rImage, BmpColorMode eMode )
2772 {
2773     if( eMode == BMP_COLOR_NORMAL )
2774         SetImage( rImage );
2775     else if( eMode == BMP_COLOR_HIGHCONTRAST )
2776         maImageHC = rImage;
2777     else
2778         return sal_False;
2779     return sal_True;
2780 }
2781 
2782 // -----------------------------------------------------------------------
2783 
2784 const Image& ImplWin::GetModeImage( BmpColorMode eMode ) const
2785 {
2786     if( eMode == BMP_COLOR_HIGHCONTRAST )
2787         return maImageHC;
2788     else
2789         return maImage;
2790 }
2791 
2792 // -----------------------------------------------------------------------
2793 
2794 void ImplWin::MBDown()
2795 {
2796     if( IsEnabled() )
2797         maMBDownHdl.Call( this );
2798 }
2799 
2800 // -----------------------------------------------------------------------
2801 
2802 void ImplWin::MouseButtonDown( const MouseEvent& )
2803 {
2804     if( IsEnabled() )
2805     {
2806 //      Control::MouseButtonDown( rMEvt );
2807         MBDown();
2808     }
2809 }
2810 
2811 // -----------------------------------------------------------------------
2812 
2813 void ImplWin::FillLayoutData() const
2814 {
2815     mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2816     const_cast<ImplWin*>(this)->ImplDraw( true );
2817 }
2818 
2819 // -----------------------------------------------------------------------
2820 
2821 long ImplWin::PreNotify( NotifyEvent& rNEvt )
2822 {
2823     long nDone = 0;
2824     const MouseEvent* pMouseEvt = NULL;
2825 
2826     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2827     {
2828         if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2829         {
2830             // trigger redraw as mouse over state has changed
2831             if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2832             && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2833             {
2834                 GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2835                 GetParent()->GetWindow( WINDOW_BORDER )->Update();
2836             }
2837         }
2838     }
2839 
2840     return nDone ? nDone : Control::PreNotify(rNEvt);
2841 }
2842 
2843 // -----------------------------------------------------------------------
2844 
2845 void ImplWin::ImplDraw( bool bLayout )
2846 {
2847     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2848 
2849     sal_Bool bNativeOK = sal_False;
2850 
2851     if( ! bLayout )
2852     {
2853         ControlState nState = CTRL_STATE_ENABLED;
2854         if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2855             && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2856         {
2857             // Repaint the (focused) area similarly to
2858             // ImplSmallBorderWindowView::DrawWindow() in
2859             // vcl/source/window/brdwin.cxx
2860             Window *pWin = GetParent();
2861 
2862             ImplControlValue aControlValue;
2863             if ( !pWin->IsEnabled() )
2864             nState &= ~CTRL_STATE_ENABLED;
2865             if ( pWin->HasFocus() )
2866             nState |= CTRL_STATE_FOCUSED;
2867 
2868             // The listbox is painted over the entire control including the
2869             // border, but ImplWin does not contain the border => correction
2870             // needed.
2871             sal_Int32 nLeft, nTop, nRight, nBottom;
2872             pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2873             Point aPoint( -nLeft, -nTop );
2874             Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2875 
2876             sal_Bool bMouseOver = sal_False;
2877             if( GetParent() )
2878             {
2879                 Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2880                 while( pChild && (bMouseOver = pChild->IsMouseOver()) == sal_False )
2881                     pChild = pChild->GetWindow( WINDOW_NEXT );
2882             }
2883 
2884             if( bMouseOver )
2885                 nState |= CTRL_STATE_ROLLOVER;
2886 
2887             // if parent has no border, then nobody has drawn the background
2888             // since no border window exists. so draw it here.
2889             WinBits nParentStyle = pWin->GetStyle();
2890             if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2891             {
2892                 Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2893                 pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2894                                          nState, aControlValue, rtl::OUString() );
2895             }
2896 
2897             bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2898                 aControlValue, rtl::OUString() );
2899         }
2900 
2901         if( IsEnabled() )
2902         {
2903             if( HasFocus() )
2904             {
2905                 SetTextColor( rStyleSettings.GetHighlightTextColor() );
2906                 SetFillColor( rStyleSettings.GetHighlightColor() );
2907                 DrawRect( maFocusRect );
2908             }
2909             else
2910             {
2911                 Color aColor;
2912                 if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2913                     aColor = rStyleSettings.GetFieldRolloverTextColor();
2914                 else
2915                     aColor = rStyleSettings.GetFieldTextColor();
2916                 if( IsControlForeground() )
2917                     aColor = GetControlForeground();
2918                 SetTextColor( aColor );
2919                 if ( !bNativeOK )
2920                     Erase( maFocusRect );
2921             }
2922         }
2923         else // Disabled
2924         {
2925             SetTextColor( rStyleSettings.GetDisableColor() );
2926             if ( !bNativeOK )
2927                 Erase( maFocusRect );
2928         }
2929     }
2930 
2931     if ( IsUserDrawEnabled() )
2932     {
2933         mbInUserDraw = sal_True;
2934         UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2935         maUserDrawHdl.Call( &aUDEvt );
2936         mbInUserDraw = sal_False;
2937     }
2938     else
2939     {
2940         DrawEntry( sal_True, sal_True, sal_False, bLayout );
2941     }
2942 }
2943 
2944 // -----------------------------------------------------------------------
2945 
2946 void ImplWin::Paint( const Rectangle& )
2947 {
2948     ImplDraw();
2949 }
2950 
2951 // -----------------------------------------------------------------------
2952 
2953 void ImplWin::DrawEntry( sal_Bool bDrawImage, sal_Bool bDrawText, sal_Bool bDrawTextAtImagePos, bool bLayout )
2954 {
2955     long nBorder = 1;
2956     Size aOutSz = GetOutputSizePixel();
2957 
2958     sal_Bool bImage = !!maImage;
2959     if( bDrawImage && bImage && !bLayout )
2960     {
2961         sal_uInt16 nStyle = 0;
2962         Size aImgSz = maImage.GetSizePixel();
2963         Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2964 
2965         // check for HC mode
2966         Image *pImage = &maImage;
2967 
2968         if( !!maImageHC )
2969         {
2970             if( GetSettings().GetStyleSettings().GetHighContrastMode() )
2971                 pImage = &maImageHC;
2972         }
2973 
2974         if ( !IsZoom() )
2975         {
2976             DrawImage( aPtImg, *pImage, nStyle );
2977         }
2978         else
2979         {
2980             aImgSz.Width() = CalcZoom( aImgSz.Width() );
2981             aImgSz.Height() = CalcZoom( aImgSz.Height() );
2982             DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2983         }
2984     }
2985 
2986     if( bDrawText && maString.Len() )
2987     {
2988         sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2989 
2990         if ( bDrawImage && bImage && !bLayout )
2991             nTextStyle |= TEXT_DRAW_LEFT;
2992         else if ( GetStyle() & WB_CENTER )
2993             nTextStyle |= TEXT_DRAW_CENTER;
2994         else if ( GetStyle() & WB_RIGHT )
2995             nTextStyle |= TEXT_DRAW_RIGHT;
2996         else
2997             nTextStyle |= TEXT_DRAW_LEFT;
2998 
2999         Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
3000 
3001         if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
3002         {
3003             long nMaxWidth = Max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
3004             aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
3005         }
3006 
3007         MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
3008         String* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
3009         DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
3010     }
3011 
3012     if( HasFocus() && !bLayout )
3013         ShowFocus( maFocusRect );
3014 }
3015 
3016 // -----------------------------------------------------------------------
3017 
3018 void ImplWin::Resize()
3019 {
3020     Control::Resize();
3021     maFocusRect.SetSize( GetOutputSizePixel() );
3022     Invalidate();
3023 }
3024 
3025 // -----------------------------------------------------------------------
3026 
3027 void ImplWin::GetFocus()
3028 {
3029     ShowFocus( maFocusRect );
3030     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3031         IsNativeWidgetEnabled() &&
3032         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3033     {
3034         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3035         if( ! pWin )
3036             pWin = GetParent();
3037         pWin->Invalidate();
3038     }
3039     else
3040         Invalidate();
3041     Control::GetFocus();
3042 }
3043 
3044 // -----------------------------------------------------------------------
3045 
3046 void ImplWin::LoseFocus()
3047 {
3048     HideFocus();
3049     if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3050         IsNativeWidgetEnabled() &&
3051         IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
3052     {
3053         Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
3054         if( ! pWin )
3055             pWin = GetParent();
3056         pWin->Invalidate();
3057     }
3058     else
3059         Invalidate();
3060     Control::LoseFocus();
3061 }
3062 
3063 // =======================================================================
3064 
3065 ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
3066     PushButton(  pParent, nWinStyle ),
3067     mbDown  ( sal_False )
3068 {
3069 }
3070 
3071 // -----------------------------------------------------------------------
3072 
3073 void ImplBtn::MBDown()
3074 {
3075     if( IsEnabled() )
3076        maMBDownHdl.Call( this );
3077 }
3078 
3079 // -----------------------------------------------------------------------
3080 
3081 void ImplBtn::MouseButtonDown( const MouseEvent& )
3082 {
3083     //PushButton::MouseButtonDown( rMEvt );
3084     if( IsEnabled() )
3085     {
3086         MBDown();
3087         mbDown = sal_True;
3088     }
3089 }
3090 
3091 // =======================================================================
3092 
3093 ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
3094     FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW )    // no drop shadow for list boxes
3095 {
3096     mpImplLB = NULL;
3097     mnDDLineCount = 0;
3098     mbAutoWidth = sal_False;
3099 
3100     mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
3101 
3102     EnableSaveBackground();
3103 
3104     Window * pBorderWindow = ImplGetBorderWindow();
3105     if( pBorderWindow )
3106     {
3107         SetAccessibleRole(accessibility::AccessibleRole::PANEL);
3108         pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3109     }
3110     else
3111     {
3112         SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
3113     }
3114 
3115 }
3116 
3117 // -----------------------------------------------------------------------
3118 
3119 long ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
3120 {
3121     if( rNEvt.GetType() == EVENT_LOSEFOCUS )
3122     {
3123         if( !GetParent()->HasChildPathFocus( sal_True ) )
3124             EndPopupMode();
3125     }
3126 
3127     return FloatingWindow::PreNotify( rNEvt );
3128 }
3129 
3130 // -----------------------------------------------------------------------
3131 
3132 void ImplListBoxFloatingWindow::SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
3133 {
3134     FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
3135 
3136     // Fix #60890# ( MBA ): um auch im aufgeklappten Zustand der Listbox die Gr"o\se einfach zu einen
3137     // Aufruf von Resize() "andern zu k"onnen, wird die Position hier ggf. angepa\t
3138     if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
3139     {
3140         Point aPos = GetParent()->GetPosPixel();
3141         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3142 
3143         if ( nFlags & WINDOW_POSSIZE_X )
3144             aPos.X() = nX;
3145 
3146         if ( nFlags & WINDOW_POSSIZE_Y )
3147             aPos.Y() = nY;
3148 
3149         sal_uInt16 nIndex;
3150         SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
3151     }
3152 
3153 //  if( !IsReallyVisible() )
3154     {
3155         // Die ImplListBox erhaelt kein Resize, weil nicht sichtbar.
3156         // Die Fenster muessen aber ein Resize() erhalten, damit die
3157         // Anzahl der sichtbaren Eintraege fuer PgUp/PgDown stimmt.
3158         // Die Anzahl kann auch nicht von List/Combobox berechnet werden,
3159         // weil hierfuer auch die ggf. vorhandene vertikale Scrollbar
3160         // beruecksichtigt werden muss.
3161         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3162         ((Window*)mpImplLB)->Resize();
3163         ((Window*)mpImplLB->GetMainWindow())->Resize();
3164     }
3165 }
3166 
3167 // -----------------------------------------------------------------------
3168 
3169 void ImplListBoxFloatingWindow::Resize()
3170 {
3171     mpImplLB->GetMainWindow()->ImplClearLayoutData();
3172     FloatingWindow::Resize();
3173 }
3174 
3175 // -----------------------------------------------------------------------
3176 
3177 Size ImplListBoxFloatingWindow::CalcFloatSize()
3178 {
3179     Size aFloatSz( maPrefSz );
3180 
3181     sal_Int32 nLeft, nTop, nRight, nBottom;
3182     GetBorder( nLeft, nTop, nRight, nBottom );
3183 
3184     sal_uInt16 nLines = mpImplLB->GetEntryList()->GetEntryCount();
3185     if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
3186         nLines = mnDDLineCount;
3187 
3188     Size aSz = mpImplLB->CalcSize( nLines );
3189     long nMaxHeight = aSz.Height() + nTop + nBottom;
3190 
3191     if ( mnDDLineCount )
3192         aFloatSz.Height() = nMaxHeight;
3193 
3194     if( mbAutoWidth )
3195     {
3196         // AutoSize erstmal nur fuer die Breite...
3197 
3198         aFloatSz.Width() = aSz.Width() + nLeft + nRight;
3199         aFloatSz.Width() += nRight; // etwas mehr Platz sieht besser aus...
3200 
3201         if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
3202         {
3203             // dann wird noch der vertikale Scrollbar benoetigt
3204             long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3205             aFloatSz.Width() += nSBWidth;
3206         }
3207     }
3208 
3209     if ( aFloatSz.Height() > nMaxHeight )
3210         aFloatSz.Height() = nMaxHeight;
3211 
3212     // Minimale Hoehe, falls Hoehe nicht auf Float-Hoehe eingestellt wurde.
3213     // Der Parent vom FloatWin muss die DropDown-Combo/Listbox sein.
3214     Size aParentSz = GetParent()->GetSizePixel();
3215     if( !mnDDLineCount && ( aFloatSz.Height() < aParentSz.Height() ) )
3216         aFloatSz.Height() = aParentSz.Height();
3217 
3218     // Nicht schmaler als der Parent werden...
3219     if( aFloatSz.Width() < aParentSz.Width() )
3220         aFloatSz.Width() = aParentSz.Width();
3221 
3222     // Hoehe auf Entries alignen...
3223     long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3224     long nEntryHeight = mpImplLB->GetEntryHeight();
3225     if ( nInnerHeight % nEntryHeight )
3226     {
3227         nInnerHeight /= nEntryHeight;
3228         nInnerHeight++;
3229         nInnerHeight *= nEntryHeight;
3230         aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3231     }
3232 
3233     return aFloatSz;
3234 }
3235 
3236 // -----------------------------------------------------------------------
3237 
3238 void ImplListBoxFloatingWindow::StartFloat( sal_Bool bStartTracking )
3239 {
3240     if( !IsInPopupMode() )
3241     {
3242         Size aFloatSz = CalcFloatSize();
3243 
3244         SetSizePixel( aFloatSz );
3245         mpImplLB->SetSizePixel( GetOutputSizePixel() );
3246 
3247         sal_uInt16 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3248         mnPopupModeStartSaveSelection = nPos;
3249 
3250         Size aSz = GetParent()->GetSizePixel();
3251         Point aPos = GetParent()->GetPosPixel();
3252         aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3253         // FIXME: this ugly hack is for Mac/Aqua
3254         // should be replaced by a real mechanism to place the float rectangle
3255         if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3256             GetParent()->IsNativeWidgetEnabled() )
3257         {
3258             sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3259             aPos.X() += nLeft;
3260             aPos.Y() += nTop;
3261             aSz.Width() -= nLeft + nRight;
3262             aSz.Height() -= nTop + nBottom;
3263         }
3264         Rectangle aRect( aPos, aSz );
3265 
3266         // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3267         // where the document is unmirrored
3268         // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3269         if( GetParent()->GetParent()->ImplIsAntiparallel() )
3270             GetParent()->GetParent()->ImplReMirror( aRect );
3271 
3272         StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3273 
3274         if( nPos != LISTBOX_ENTRY_NOTFOUND )
3275             mpImplLB->ShowProminentEntry( nPos );
3276 
3277         if( bStartTracking )
3278             mpImplLB->GetMainWindow()->EnableMouseMoveSelect( sal_True );
3279 
3280         if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3281             mpImplLB->GetMainWindow()->GrabFocus();
3282 
3283         mpImplLB->GetMainWindow()->ImplClearLayoutData();
3284     }
3285 }
3286