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