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