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