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