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