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 0 : void ImplInitFieldSettings( Window* pWin, bool bFont, bool bForeground, bool bBackground )
50 : {
51 0 : const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings();
52 :
53 0 : if ( bFont )
54 : {
55 0 : Font aFont = rStyleSettings.GetFieldFont();
56 0 : if ( pWin->IsControlFont() )
57 0 : aFont.Merge( pWin->GetControlFont() );
58 0 : pWin->SetZoomedPointFont( aFont );
59 : }
60 :
61 0 : if ( bFont || bForeground )
62 : {
63 0 : Color aTextColor = rStyleSettings.GetFieldTextColor();
64 0 : if ( pWin->IsControlForeground() )
65 0 : aTextColor = pWin->GetControlForeground();
66 0 : pWin->SetTextColor( aTextColor );
67 : }
68 :
69 0 : if ( bBackground )
70 : {
71 0 : if( pWin->IsControlBackground() )
72 0 : pWin->SetBackground( pWin->GetControlBackground() );
73 : else
74 0 : pWin->SetBackground( rStyleSettings.GetFieldColor() );
75 : }
76 0 : }
77 :
78 0 : void ImplInitDropDownButton( PushButton* pButton )
79 : {
80 0 : if ( pButton->GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
81 0 : pButton->SetSymbol( SYMBOL_SPIN_UPDOWN );
82 : else
83 0 : pButton->SetSymbol( SYMBOL_SPIN_DOWN );
84 :
85 0 : if ( pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
86 0 : && ! pButton->IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
87 0 : pButton->SetBackground();
88 0 : }
89 :
90 0 : ImplEntryList::ImplEntryList( Window* pWindow )
91 : {
92 0 : mpWindow = pWindow;
93 0 : mnLastSelected = LISTBOX_ENTRY_NOTFOUND;
94 0 : mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND;
95 0 : mnImages = 0;
96 0 : mbCallSelectionChangedHdl = true;
97 :
98 0 : mnMRUCount = 0;
99 0 : mnMaxMRUCount = 0;
100 0 : }
101 :
102 0 : ImplEntryList::~ImplEntryList()
103 : {
104 0 : Clear();
105 0 : }
106 :
107 0 : void ImplEntryList::Clear()
108 : {
109 0 : mnImages = 0;
110 0 : maEntries.clear();
111 0 : }
112 :
113 0 : void ImplEntryList::SelectEntry( sal_Int32 nPos, bool bSelect )
114 : {
115 0 : if (0 <= nPos && static_cast<size_t>(nPos) < maEntries.size())
116 : {
117 0 : boost::ptr_vector<ImplEntryType>::iterator iter = maEntries.begin()+nPos;
118 :
119 0 : if ( ( iter->mbIsSelected != bSelect ) &&
120 0 : ( (iter->mnFlags & LISTBOX_ENTRY_FLAG_DISABLE_SELECTION) == 0 ) )
121 : {
122 0 : iter->mbIsSelected = bSelect;
123 0 : if ( mbCallSelectionChangedHdl )
124 0 : maSelectionChangedHdl.Call( (void*)sal_IntPtr(nPos) );
125 : }
126 : }
127 0 : }
128 :
129 : namespace
130 : {
131 : struct theSorter
132 : : public rtl::StaticWithInit< comphelper::string::NaturalStringSorter, theSorter >
133 : {
134 0 : comphelper::string::NaturalStringSorter operator () ()
135 : {
136 : return comphelper::string::NaturalStringSorter(
137 : ::comphelper::getProcessComponentContext(),
138 0 : Application::GetSettings().GetLanguageTag().getLocale());
139 : }
140 : };
141 : }
142 :
143 0 : sal_Int32 ImplEntryList::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort )
144 : {
145 0 : if (nPos < 0 || LISTBOX_MAX_ENTRIES <= maEntries.size())
146 0 : return LISTBOX_ERROR;
147 :
148 0 : if ( !!pNewEntry->maImage )
149 0 : mnImages++;
150 :
151 0 : sal_Int32 insPos = 0;
152 :
153 0 : if ( !bSort || maEntries.empty())
154 : {
155 0 : if (0 <= nPos && static_cast<size_t>(nPos) < maEntries.size())
156 : {
157 0 : insPos = nPos;
158 0 : maEntries.insert( maEntries.begin() + nPos, pNewEntry );
159 : }
160 : else
161 : {
162 0 : insPos = maEntries.size();
163 0 : maEntries.push_back(pNewEntry);
164 : }
165 : }
166 : else
167 : {
168 0 : const comphelper::string::NaturalStringSorter &rSorter = theSorter::get();
169 :
170 0 : const OUString& rStr = pNewEntry->maStr;
171 : sal_uLong nLow, nHigh, nMid;
172 :
173 0 : nHigh = maEntries.size();
174 :
175 0 : ImplEntryType* pTemp = GetEntry( (sal_Int32)(nHigh-1) );
176 :
177 : try
178 : {
179 0 : sal_Int32 nComp = rSorter.compare(rStr, pTemp->maStr);
180 :
181 : // fast insert for sorted data
182 0 : if ( nComp >= 0 )
183 : {
184 0 : insPos = maEntries.size();
185 0 : maEntries.push_back(pNewEntry);
186 : }
187 : else
188 : {
189 0 : nLow = mnMRUCount;
190 0 : pTemp = (ImplEntryType*)GetEntry( (sal_Int32)nLow );
191 :
192 0 : nComp = rSorter.compare(rStr, pTemp->maStr);
193 0 : if ( nComp <= 0 )
194 : {
195 0 : insPos = 0;
196 0 : maEntries.insert(maEntries.begin(),pNewEntry);
197 : }
198 : else
199 : {
200 : // binary search
201 0 : nHigh--;
202 0 : do
203 : {
204 0 : nMid = (nLow + nHigh) / 2;
205 0 : pTemp = (ImplEntryType*)GetEntry( nMid );
206 :
207 0 : nComp = rSorter.compare(rStr, pTemp->maStr);
208 :
209 0 : if ( nComp < 0 )
210 0 : nHigh = nMid-1;
211 : else
212 : {
213 0 : if ( nComp > 0 )
214 0 : nLow = nMid + 1;
215 : else
216 0 : break;
217 : }
218 : }
219 : while ( nLow <= nHigh );
220 :
221 0 : if ( nComp >= 0 )
222 0 : nMid++;
223 :
224 0 : insPos = nMid;
225 0 : 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 0 : 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 0 : sal_Int32 ImplEntryList::FindEntry( const OUString& rString, bool bSearchMRUArea ) const
258 : {
259 0 : sal_Int32 nEntries = maEntries.size();
260 0 : for ( sal_Int32 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
261 : {
262 0 : OUString aComp( vcl::I18nHelper::filterFormattingChars( maEntries[n].maStr ) );
263 0 : if ( aComp == rString )
264 0 : return n;
265 0 : }
266 0 : return LISTBOX_ENTRY_NOTFOUND;
267 : }
268 :
269 0 : sal_Int32 ImplEntryList::FindMatchingEntry( const OUString& rStr, sal_Int32 nStart, bool bForward, bool bLazy ) const
270 : {
271 0 : sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
272 0 : sal_Int32 nEntryCount = GetEntryCount();
273 0 : if ( !bForward )
274 0 : nStart++; // decrements right away
275 :
276 0 : const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
277 0 : for ( sal_Int32 n = nStart; bForward ? n < nEntryCount : n != 0; )
278 : {
279 0 : if ( !bForward )
280 0 : n--;
281 :
282 0 : ImplEntryType* pImplEntry = GetEntry( n );
283 : bool bMatch;
284 0 : if ( bLazy )
285 : {
286 0 : bMatch = rI18nHelper.MatchString( rStr, pImplEntry->maStr );
287 : }
288 : else
289 : {
290 0 : bMatch = rStr.isEmpty() || (rStr == pImplEntry->maStr );
291 : }
292 0 : if ( bMatch )
293 : {
294 0 : nPos = n;
295 0 : break;
296 : }
297 :
298 0 : if ( bForward )
299 0 : n++;
300 : }
301 :
302 0 : 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 0 : long ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex, sal_Int32 i_nBeginIndex, long i_nBeginHeight ) const
321 : {
322 0 : long nHeight = i_nBeginHeight;
323 0 : sal_Int32 nStart = i_nEndIndex > i_nBeginIndex ? i_nBeginIndex : i_nEndIndex;
324 0 : sal_Int32 nStop = i_nEndIndex > i_nBeginIndex ? i_nEndIndex : i_nBeginIndex;
325 0 : sal_Int32 nEntryCount = GetEntryCount();
326 0 : if( 0 <= nStop && nStop != LISTBOX_ENTRY_NOTFOUND && nEntryCount != 0 )
327 : {
328 : // sanity check
329 0 : if( nStop > nEntryCount-1 )
330 0 : nStop = nEntryCount-1;
331 0 : if (nStart < 0)
332 0 : nStart = 0;
333 0 : else if( nStart > nEntryCount-1 )
334 0 : nStart = nEntryCount-1;
335 :
336 0 : sal_Int32 nIndex = nStart;
337 0 : while( nIndex != LISTBOX_ENTRY_NOTFOUND && nIndex < nStop )
338 : {
339 0 : long nPosHeight = GetEntryPtr( nIndex )->mnHeight;
340 0 : if (nHeight > ::std::numeric_limits<long>::max() - nPosHeight)
341 : {
342 : SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated");
343 0 : break;
344 : }
345 0 : nHeight += nPosHeight;
346 0 : nIndex++;
347 0 : }
348 : }
349 : else
350 0 : nHeight = 0;
351 0 : return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
352 : }
353 :
354 0 : long ImplEntryList::GetEntryHeight( sal_Int32 nPos ) const
355 : {
356 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
357 0 : return pImplEntry ? pImplEntry->mnHeight : 0;
358 : }
359 :
360 0 : OUString ImplEntryList::GetEntryText( sal_Int32 nPos ) const
361 : {
362 0 : OUString aEntryText;
363 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
364 0 : if ( pImplEntry )
365 0 : aEntryText = pImplEntry->maStr;
366 0 : return aEntryText;
367 : }
368 :
369 0 : bool ImplEntryList::HasEntryImage( sal_Int32 nPos ) const
370 : {
371 0 : bool bImage = false;
372 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
373 0 : if ( pImplEntry )
374 0 : bImage = !!pImplEntry->maImage;
375 0 : return bImage;
376 : }
377 :
378 0 : Image ImplEntryList::GetEntryImage( sal_Int32 nPos ) const
379 : {
380 0 : Image aImage;
381 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
382 0 : if ( pImplEntry )
383 0 : aImage = pImplEntry->maImage;
384 0 : return aImage;
385 : }
386 :
387 0 : void ImplEntryList::SetEntryData( sal_Int32 nPos, void* pNewData )
388 : {
389 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
390 0 : if ( pImplEntry )
391 0 : pImplEntry->mpUserData = pNewData;
392 0 : }
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 0 : sal_Int32 ImplEntryList::GetSelectEntryCount() const
414 : {
415 0 : sal_Int32 nSelCount = 0;
416 0 : for ( sal_Int32 n = GetEntryCount(); n; )
417 : {
418 0 : ImplEntryType* pImplEntry = GetEntry( --n );
419 0 : if ( pImplEntry->mbIsSelected )
420 0 : nSelCount++;
421 : }
422 0 : return nSelCount;
423 : }
424 :
425 0 : OUString ImplEntryList::GetSelectEntry( sal_Int32 nIndex ) const
426 : {
427 0 : return GetEntryText( GetSelectEntryPos( nIndex ) );
428 : }
429 :
430 0 : sal_Int32 ImplEntryList::GetSelectEntryPos( sal_Int32 nIndex ) const
431 : {
432 0 : sal_Int32 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND;
433 0 : sal_Int32 nSel = 0;
434 0 : sal_Int32 nEntryCount = GetEntryCount();
435 :
436 0 : for ( sal_Int32 n = 0; n < nEntryCount; n++ )
437 : {
438 0 : ImplEntryType* pImplEntry = GetEntry( n );
439 0 : if ( pImplEntry->mbIsSelected )
440 : {
441 0 : if ( nSel == nIndex )
442 : {
443 0 : nSelEntryPos = n;
444 0 : break;
445 : }
446 0 : nSel++;
447 : }
448 : }
449 :
450 0 : return nSelEntryPos;
451 : }
452 :
453 0 : bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex ) const
454 : {
455 0 : ImplEntryType* pImplEntry = GetEntry( nIndex );
456 0 : return pImplEntry ? pImplEntry->mbIsSelected : false;
457 : }
458 :
459 0 : bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos ) const
460 : {
461 0 : ImplEntryType* pImplEntry = GetEntry( nPos );
462 0 : 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 0 : ImplListBoxWindow::ImplListBoxWindow( Window* pParent, WinBits nWinStyle ) :
492 : Control( pParent, 0 ),
493 0 : maQuickSelectionEngine( *this )
494 : {
495 0 : mpEntryList = new ImplEntryList( this );
496 :
497 0 : mnTop = 0;
498 0 : mnLeft = 0;
499 0 : mnBorder = 1;
500 0 : mnSelectModifier = 0;
501 0 : mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND;
502 0 : mbTrack = false;
503 0 : mbImgsDiffSz = false;
504 0 : mbTravelSelect = false;
505 0 : mbTrackingSelect = false;
506 0 : mbSelectionChanged = false;
507 0 : mbMouseMoveSelect = false;
508 0 : mbMulti = false;
509 0 : mbStackMode = false;
510 0 : mbGrabFocus = false;
511 0 : mbUserDrawEnabled = false;
512 0 : mbInUserDraw = false;
513 0 : mbReadOnly = false;
514 0 : mbHasFocusRect = false;
515 0 : mbRight = ( nWinStyle & WB_RIGHT );
516 0 : mbCenter = ( nWinStyle & WB_CENTER );
517 0 : mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE );
518 0 : mbSort = ( nWinStyle & WB_SORT );
519 0 : mbEdgeBlending = false;
520 :
521 : // pb: #106948# explicit mirroring for calc
522 0 : mbMirroring = false;
523 :
524 0 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
525 0 : mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND;
526 0 : mnSeparatorPos = LISTBOX_ENTRY_NOTFOUND;
527 0 : meProminentType = PROMINENT_TOP;
528 :
529 0 : SetLineColor();
530 0 : SetTextFillColor();
531 0 : SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
532 :
533 0 : ImplInitSettings( true, true, true );
534 0 : ImplCalcMetrics();
535 0 : }
536 :
537 0 : ImplListBoxWindow::~ImplListBoxWindow()
538 : {
539 0 : delete mpEntryList;
540 0 : }
541 :
542 0 : void ImplListBoxWindow::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
543 : {
544 0 : ImplInitFieldSettings( this, bFont, bForeground, bBackground );
545 0 : }
546 :
547 0 : void ImplListBoxWindow::ImplCalcMetrics()
548 : {
549 0 : mnMaxWidth = 0;
550 0 : mnMaxTxtWidth = 0;
551 0 : mnMaxImgWidth = 0;
552 0 : mnMaxImgTxtWidth= 0;
553 0 : mnMaxImgHeight = 0;
554 :
555 0 : mnTextHeight = (sal_uInt16)GetTextHeight();
556 0 : mnMaxTxtHeight = mnTextHeight + mnBorder;
557 0 : mnMaxHeight = mnMaxTxtHeight;
558 :
559 0 : if ( maUserItemSize.Height() > mnMaxHeight )
560 0 : mnMaxHeight = (sal_uInt16) maUserItemSize.Height();
561 0 : if ( maUserItemSize.Width() > mnMaxWidth )
562 0 : mnMaxWidth= (sal_uInt16) maUserItemSize.Width();
563 :
564 0 : for ( sal_Int32 n = mpEntryList->GetEntryCount(); n; )
565 : {
566 0 : ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
567 0 : ImplUpdateEntryMetrics( *pEntry );
568 : }
569 :
570 0 : if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
571 : {
572 0 : Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->mnHeight );
573 0 : maFocusRect.SetSize( aSz );
574 : }
575 0 : }
576 :
577 0 : void ImplListBoxWindow::Clear()
578 : {
579 0 : mpEntryList->Clear();
580 :
581 0 : mnMaxHeight = mnMaxTxtHeight;
582 0 : mnMaxWidth = 0;
583 0 : mnMaxTxtWidth = 0;
584 0 : mnMaxImgTxtWidth= 0;
585 0 : mnMaxImgWidth = 0;
586 0 : mnMaxImgHeight = 0;
587 0 : mnTop = 0;
588 0 : mnLeft = 0;
589 0 : mbImgsDiffSz = false;
590 0 : ImplClearLayoutData();
591 :
592 0 : mnCurrentPos = LISTBOX_ENTRY_NOTFOUND;
593 0 : maQuickSelectionEngine.Reset();
594 :
595 0 : Invalidate();
596 0 : }
597 :
598 0 : void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
599 : {
600 0 : ImplClearLayoutData();
601 0 : maUserItemSize = rSz;
602 0 : ImplCalcMetrics();
603 0 : }
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 0 : void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
622 : {
623 : ImplEntryMetrics aMetrics;
624 0 : aMetrics.bText = !rEntry.maStr.isEmpty();
625 0 : aMetrics.bImage = !!rEntry.maImage;
626 0 : aMetrics.nEntryWidth = 0;
627 0 : aMetrics.nEntryHeight = 0;
628 0 : aMetrics.nTextWidth = 0;
629 0 : aMetrics.nImgWidth = 0;
630 0 : aMetrics.nImgHeight = 0;
631 :
632 0 : if ( aMetrics.bText )
633 : {
634 0 : 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 0 : aMetrics.nTextWidth = (sal_uInt16)GetTextWidth( rEntry.maStr );
653 0 : if( aMetrics.nTextWidth > mnMaxTxtWidth )
654 0 : mnMaxTxtWidth = aMetrics.nTextWidth;
655 0 : aMetrics.nEntryWidth = mnMaxTxtWidth;
656 0 : aMetrics.nEntryHeight = mnTextHeight + mnBorder;
657 : }
658 : }
659 0 : if ( aMetrics.bImage )
660 : {
661 0 : Size aImgSz = rEntry.maImage.GetSizePixel();
662 0 : aMetrics.nImgWidth = (sal_uInt16) CalcZoom( aImgSz.Width() );
663 0 : aMetrics.nImgHeight = (sal_uInt16) CalcZoom( aImgSz.Height() );
664 :
665 0 : if( mnMaxImgWidth && ( aMetrics.nImgWidth != mnMaxImgWidth ) )
666 0 : mbImgsDiffSz = true;
667 0 : else if ( mnMaxImgHeight && ( aMetrics.nImgHeight != mnMaxImgHeight ) )
668 0 : mbImgsDiffSz = true;
669 :
670 0 : if( aMetrics.nImgWidth > mnMaxImgWidth )
671 0 : mnMaxImgWidth = aMetrics.nImgWidth;
672 0 : if( aMetrics.nImgHeight > mnMaxImgHeight )
673 0 : mnMaxImgHeight = aMetrics.nImgHeight;
674 :
675 0 : mnMaxImgTxtWidth = std::max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
676 0 : aMetrics.nEntryHeight = std::max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
677 :
678 : }
679 0 : if ( IsUserDrawEnabled() || aMetrics.bImage )
680 : {
681 0 : aMetrics.nEntryWidth = std::max( aMetrics.nImgWidth, maUserItemSize.Width() );
682 0 : if ( aMetrics.bText )
683 0 : aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE;
684 0 : aMetrics.nEntryHeight = std::max( std::max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
685 0 : aMetrics.nEntryHeight );
686 : }
687 :
688 0 : 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 0 : if ( aMetrics.nEntryWidth > mnMaxWidth )
696 0 : mnMaxWidth = aMetrics.nEntryWidth;
697 0 : if ( aMetrics.nEntryHeight > mnMaxHeight )
698 0 : mnMaxHeight = aMetrics.nEntryHeight;
699 :
700 0 : rEntry.mnHeight = aMetrics.nEntryHeight;
701 0 : }
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 0 : sal_Int32 ImplListBoxWindow::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry )
745 : {
746 0 : if (nPos < 0 || LISTBOX_MAX_ENTRIES <= mpEntryList->GetEntryCount())
747 0 : return LISTBOX_ERROR;
748 :
749 0 : ImplClearLayoutData();
750 0 : sal_Int32 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, mbSort );
751 :
752 0 : if( (GetStyle() & WB_WORDBREAK) )
753 0 : pNewEntry->mnFlags |= LISTBOX_ENTRY_FLAG_MULTILINE;
754 :
755 0 : ImplUpdateEntryMetrics( *pNewEntry );
756 0 : 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 0 : void ImplListBoxWindow::ImplHideFocusRect()
785 : {
786 0 : if ( mbHasFocusRect )
787 : {
788 0 : HideFocus();
789 0 : mbHasFocusRect = false;
790 : }
791 0 : }
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 0 : bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry ) const
811 : {
812 0 : bool bRet = false;
813 :
814 0 : if( i_nEntry >= mnTop )
815 : {
816 0 : if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
817 0 : PixelToLogic( GetSizePixel() ).Height() )
818 : {
819 0 : bRet = true;
820 : }
821 : }
822 :
823 0 : return bRet;
824 : }
825 :
826 0 : sal_Int32 ImplListBoxWindow::GetLastVisibleEntry() const
827 : {
828 0 : sal_Int32 nPos = mnTop;
829 0 : long nWindowHeight = GetSizePixel().Height();
830 0 : sal_Int32 nCount = mpEntryList->GetEntryCount();
831 : long nDiff;
832 0 : for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
833 0 : nPos++;
834 :
835 0 : if( nDiff > nWindowHeight && nPos > mnTop )
836 0 : nPos--;
837 :
838 0 : if( nPos >= nCount )
839 0 : nPos = nCount-1;
840 :
841 0 : 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 : 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 0 : void ImplListBoxWindow::DeselectAll()
963 : {
964 0 : while ( GetEntryList()->GetSelectEntryCount() )
965 : {
966 0 : sal_Int32 nS = GetEntryList()->GetSelectEntryPos( 0 );
967 0 : SelectEntry( nS, false );
968 : }
969 0 : }
970 :
971 0 : void ImplListBoxWindow::SelectEntry( sal_Int32 nPos, bool bSelect )
972 : {
973 0 : if( (mpEntryList->IsEntryPosSelected( nPos ) != bSelect) && mpEntryList->IsEntrySelectable( nPos ) )
974 : {
975 0 : ImplHideFocusRect();
976 0 : if( bSelect )
977 : {
978 0 : if( !mbMulti )
979 : {
980 : // deselect the selected entry
981 0 : sal_Int32 nDeselect = GetEntryList()->GetSelectEntryPos( 0 );
982 0 : if( nDeselect != LISTBOX_ENTRY_NOTFOUND )
983 : {
984 : //SelectEntryPos( nDeselect, false );
985 0 : GetEntryList()->SelectEntry( nDeselect, false );
986 0 : if ( IsUpdateMode() && IsReallyVisible() )
987 0 : ImplPaint( nDeselect, true );
988 : }
989 : }
990 0 : mpEntryList->SelectEntry( nPos, true );
991 0 : mnCurrentPos = nPos;
992 0 : if ( ( nPos != LISTBOX_ENTRY_NOTFOUND ) && IsUpdateMode() )
993 : {
994 0 : ImplPaint( nPos );
995 0 : if ( !IsVisible( nPos ) )
996 : {
997 0 : ImplClearLayoutData();
998 0 : sal_Int32 nVisibleEntries = GetLastVisibleEntry()-mnTop;
999 0 : if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
1000 : {
1001 0 : Resize();
1002 0 : ShowProminentEntry( nPos );
1003 : }
1004 : else
1005 : {
1006 0 : ShowProminentEntry( nPos );
1007 : }
1008 : }
1009 : }
1010 : }
1011 : else
1012 : {
1013 0 : mpEntryList->SelectEntry( nPos, false );
1014 0 : ImplPaint( nPos, true );
1015 : }
1016 0 : mbSelectionChanged = true;
1017 : }
1018 0 : }
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() ) ? true : !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 : 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 foreward
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 + 1, _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 0 : void ImplListBoxWindow::ImplPaint( sal_Int32 nPos, bool bErase, bool bLayout )
1697 : {
1698 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1699 :
1700 0 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1701 0 : if( ! pEntry )
1702 0 : return;
1703 :
1704 0 : long nWidth = GetOutputSizePixel().Width();
1705 0 : long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1706 0 : Rectangle aRect( Point( 0, nY ), Size( nWidth, pEntry->mnHeight ) );
1707 :
1708 0 : if( ! bLayout )
1709 : {
1710 0 : if( mpEntryList->IsEntryPosSelected( nPos ) )
1711 : {
1712 0 : SetTextColor( !IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor() );
1713 0 : SetFillColor( rStyleSettings.GetHighlightColor() );
1714 0 : SetTextFillColor( rStyleSettings.GetHighlightColor() );
1715 0 : DrawRect( aRect );
1716 : }
1717 : else
1718 : {
1719 0 : ImplInitSettings( false, true, false );
1720 0 : if( !IsEnabled() )
1721 0 : SetTextColor( rStyleSettings.GetDisableColor() );
1722 0 : SetTextFillColor();
1723 0 : if( bErase )
1724 0 : Erase( aRect );
1725 : }
1726 : }
1727 :
1728 0 : if ( IsUserDrawEnabled() )
1729 : {
1730 0 : mbInUserDraw = true;
1731 0 : mnUserDrawEntry = nPos;
1732 0 : aRect.Left() -= mnLeft;
1733 0 : if ( nPos < GetEntryList()->GetMRUCount() )
1734 0 : nPos = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nPos ) );
1735 0 : nPos = nPos - GetEntryList()->GetMRUCount();
1736 0 : sal_Int32 nCurr = mnCurrentPos;
1737 0 : if ( mnCurrentPos < GetEntryList()->GetMRUCount() )
1738 0 : nCurr = GetEntryList()->FindEntry( GetEntryList()->GetEntryText( nCurr ) );
1739 0 : nCurr = sal::static_int_cast<sal_Int32>( nCurr - GetEntryList()->GetMRUCount());
1740 :
1741 0 : UserDrawEvent aUDEvt( this, aRect, nPos, nCurr );
1742 0 : maUserDrawHdl.Call( &aUDEvt );
1743 0 : mbInUserDraw = false;
1744 : }
1745 : else
1746 : {
1747 0 : DrawEntry( nPos, true, true, false, bLayout );
1748 : }
1749 : }
1750 :
1751 0 : void ImplListBoxWindow::DrawEntry( sal_Int32 nPos, bool bDrawImage, bool bDrawText, bool bDrawTextAtImagePos, bool bLayout )
1752 : {
1753 0 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1754 0 : if( ! pEntry )
1755 0 : return;
1756 :
1757 : // when changing this function don't forget to adjust ImplWin::DrawEntry()
1758 :
1759 0 : if ( mbInUserDraw )
1760 0 : nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1761 :
1762 0 : long nY = mpEntryList->GetAddedHeight( nPos, mnTop );
1763 0 : Size aImgSz;
1764 :
1765 0 : if( bDrawImage && mpEntryList->HasImages() && !bLayout )
1766 : {
1767 0 : Image aImage = mpEntryList->GetEntryImage( nPos );
1768 0 : if( !!aImage )
1769 : {
1770 0 : aImgSz = aImage.GetSizePixel();
1771 0 : Point aPtImg( mnBorder - mnLeft, nY + ( ( pEntry->mnHeight - aImgSz.Height() ) / 2 ) );
1772 :
1773 : // pb: #106948# explicit mirroring for calc
1774 0 : if ( mbMirroring )
1775 : // right aligned
1776 0 : aPtImg.X() = mnMaxWidth + mnBorder - aImgSz.Width() - mnLeft;
1777 :
1778 0 : if ( !IsZoom() )
1779 : {
1780 0 : 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 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1790 0 : const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1791 :
1792 0 : 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 0 : }
1805 : }
1806 :
1807 0 : if( bDrawText )
1808 : {
1809 0 : MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
1810 0 : OUString* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
1811 0 : OUString aStr( mpEntryList->GetEntryText( nPos ) );
1812 0 : if ( !aStr.isEmpty() )
1813 : {
1814 : long nMaxWidth = std::max( static_cast< long >( mnMaxWidth ),
1815 0 : GetOutputSizePixel().Width() - 2*mnBorder );
1816 : // a multiline entry should only be as wide a the window
1817 0 : if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1818 0 : nMaxWidth = GetOutputSizePixel().Width() - 2*mnBorder;
1819 :
1820 : Rectangle aTextRect( Point( mnBorder - mnLeft, nY ),
1821 0 : Size( nMaxWidth, pEntry->mnHeight ) );
1822 :
1823 0 : if( !bDrawTextAtImagePos && ( mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled() ) )
1824 : {
1825 0 : long nImageWidth = std::max( mnMaxImgWidth, maUserItemSize.Width() );
1826 0 : aTextRect.Left() += nImageWidth + IMG_TXT_DISTANCE;
1827 : }
1828 :
1829 0 : if( bLayout )
1830 0 : mpControlData->mpLayoutData->m_aLineIndices.push_back( mpControlData->mpLayoutData->m_aDisplayText.getLength() );
1831 :
1832 : // pb: #106948# explicit mirroring for calc
1833 0 : 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 0 : sal_uInt16 nDrawStyle = ImplGetTextStyle();
1842 0 : if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_MULTILINE) )
1843 0 : nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS;
1844 0 : if( (pEntry->mnFlags & LISTBOX_ENTRY_FLAG_DRAW_DISABLED) )
1845 0 : nDrawStyle |= TEXT_DRAW_DISABLE;
1846 :
1847 0 : DrawText( aTextRect, aStr, nDrawStyle, pVector, pDisplayText );
1848 0 : }
1849 : }
1850 :
1851 0 : if( !bLayout )
1852 : {
1853 0 : if ( ( mnSeparatorPos != LISTBOX_ENTRY_NOTFOUND ) &&
1854 0 : ( ( nPos == mnSeparatorPos ) || ( nPos == mnSeparatorPos+1 ) ) )
1855 : {
1856 0 : Color aOldLineColor( GetLineColor() );
1857 0 : SetLineColor( ( GetBackground().GetColor() != COL_LIGHTGRAY ) ? COL_LIGHTGRAY : COL_GRAY );
1858 0 : Point aStartPos( 0, nY );
1859 0 : if ( nPos == mnSeparatorPos )
1860 0 : aStartPos.Y() += pEntry->mnHeight-1;
1861 0 : Point aEndPos( aStartPos );
1862 0 : aEndPos.X() = GetOutputSizePixel().Width();
1863 0 : DrawLine( aStartPos, aEndPos );
1864 0 : 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 0 : void ImplListBoxWindow::ImplDoPaint( const Rectangle& rRect, bool bLayout )
1877 : {
1878 0 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1879 :
1880 0 : bool bShowFocusRect = mbHasFocusRect;
1881 0 : if ( mbHasFocusRect && ! bLayout )
1882 0 : ImplHideFocusRect();
1883 :
1884 0 : long nY = 0; // + mnBorder;
1885 0 : long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1886 :
1887 0 : for( sal_Int32 i = (sal_Int32)mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++ )
1888 : {
1889 0 : const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( i );
1890 0 : if( nY + pEntry->mnHeight >= rRect.Top() &&
1891 0 : nY <= rRect.Bottom() + mnMaxHeight )
1892 : {
1893 0 : ImplPaint( i, false, bLayout );
1894 : }
1895 0 : nY += pEntry->mnHeight;
1896 : }
1897 :
1898 0 : long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop, 0 );
1899 0 : maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1900 0 : Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1901 0 : maFocusRect.SetSize( aSz );
1902 0 : if( HasFocus() && bShowFocusRect && !bLayout )
1903 0 : ImplShowFocusRect();
1904 0 : }
1905 :
1906 0 : void ImplListBoxWindow::Paint( const Rectangle& rRect )
1907 : {
1908 0 : ImplDoPaint( rRect );
1909 0 : }
1910 :
1911 0 : sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1912 : {
1913 : // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
1914 :
1915 0 : sal_Int32 nCount = mpEntryList->GetEntryCount();
1916 0 : long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + mnBorder;
1917 0 : sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1918 0 : if( nEntries > nCount-mnTop )
1919 0 : nEntries = nCount-mnTop;
1920 :
1921 0 : return nEntries;
1922 : }
1923 :
1924 0 : void ImplListBoxWindow::Resize()
1925 : {
1926 0 : Control::Resize();
1927 :
1928 0 : bool bShowFocusRect = mbHasFocusRect;
1929 0 : if ( bShowFocusRect )
1930 0 : ImplHideFocusRect();
1931 :
1932 0 : if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND )
1933 : {
1934 0 : Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1935 0 : maFocusRect.SetSize( aSz );
1936 : }
1937 :
1938 0 : if ( bShowFocusRect )
1939 0 : ImplShowFocusRect();
1940 :
1941 0 : ImplClearLayoutData();
1942 0 : }
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 0 : void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop )
1964 : {
1965 0 : if( mpEntryList->GetEntryCount() == 0 )
1966 0 : return;
1967 :
1968 0 : long nWHeight = PixelToLogic( GetSizePixel() ).Height();
1969 :
1970 0 : sal_Int32 nLastEntry = mpEntryList->GetEntryCount()-1;
1971 0 : if( nTop > nLastEntry )
1972 0 : nTop = nLastEntry;
1973 0 : const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
1974 0 : while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->mnHeight <= nWHeight )
1975 0 : nTop--;
1976 :
1977 0 : if ( nTop != mnTop )
1978 : {
1979 0 : ImplClearLayoutData();
1980 0 : long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop, 0 );
1981 0 : Update();
1982 0 : ImplHideFocusRect();
1983 0 : mnTop = nTop;
1984 0 : Scroll( 0, nDiff );
1985 0 : Update();
1986 0 : if( HasFocus() )
1987 0 : ImplShowFocusRect();
1988 0 : maScrollHdl.Call( this );
1989 : }
1990 : }
1991 :
1992 0 : void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos )
1993 : {
1994 0 : if( meProminentType == PROMINENT_MIDDLE )
1995 : {
1996 0 : sal_Int32 nPos = nEntryPos;
1997 0 : long nWHeight = PixelToLogic( GetSizePixel() ).Height();
1998 0 : while( nEntryPos > 0 && mpEntryList->GetAddedHeight( nPos+1, nEntryPos ) < nWHeight/2 )
1999 0 : nEntryPos--;
2000 : }
2001 0 : SetTopEntry( nEntryPos );
2002 0 : }
2003 :
2004 0 : void ImplListBoxWindow::SetLeftIndent( long n )
2005 : {
2006 0 : ScrollHorz( n - mnLeft );
2007 0 : }
2008 :
2009 0 : void ImplListBoxWindow::ScrollHorz( long n )
2010 : {
2011 0 : long nDiff = 0;
2012 0 : if ( n > 0 )
2013 : {
2014 0 : long nWidth = GetOutputSizePixel().Width();
2015 0 : if( ( mnMaxWidth - mnLeft + n ) > nWidth )
2016 0 : nDiff = n;
2017 : }
2018 0 : 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 0 : 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 0 : }
2040 :
2041 0 : Size ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines) const
2042 : {
2043 : // FIXME: LISTBOX_ENTRY_FLAG_MULTILINE
2044 :
2045 0 : Size aSz;
2046 0 : aSz.Height() = nMaxLines * mnMaxHeight;
2047 0 : aSz.Width() = mnMaxWidth + 2*mnBorder;
2048 0 : 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 0 : void ImplListBoxWindow::StateChanged( StateChangedType nType )
2061 : {
2062 0 : Control::StateChanged( nType );
2063 :
2064 0 : if ( nType == STATE_CHANGE_ZOOM )
2065 : {
2066 0 : ImplInitSettings( true, false, false );
2067 0 : ImplCalcMetrics();
2068 0 : Invalidate();
2069 : }
2070 0 : else if ( nType == STATE_CHANGE_UPDATEMODE )
2071 : {
2072 0 : if ( IsUpdateMode() && IsReallyVisible() )
2073 0 : Invalidate();
2074 : }
2075 0 : else if ( nType == STATE_CHANGE_CONTROLFONT )
2076 : {
2077 0 : ImplInitSettings( true, false, false );
2078 0 : ImplCalcMetrics();
2079 0 : Invalidate();
2080 : }
2081 0 : else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2082 : {
2083 0 : ImplInitSettings( false, true, false );
2084 0 : Invalidate();
2085 : }
2086 0 : else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2087 : {
2088 0 : ImplInitSettings( false, false, true );
2089 0 : Invalidate();
2090 : }
2091 0 : else if( nType == STATE_CHANGE_ENABLE )
2092 : {
2093 0 : Invalidate();
2094 : }
2095 :
2096 0 : ImplClearLayoutData();
2097 0 : }
2098 :
2099 0 : void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2100 : {
2101 0 : Control::DataChanged( rDCEvt );
2102 :
2103 0 : if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2104 0 : (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2105 0 : ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2106 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2107 : {
2108 0 : ImplClearLayoutData();
2109 0 : ImplInitSettings( true, true, true );
2110 0 : ImplCalcMetrics();
2111 0 : Invalidate();
2112 : }
2113 0 : }
2114 :
2115 0 : sal_uInt16 ImplListBoxWindow::ImplGetTextStyle() const
2116 : {
2117 0 : sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2118 :
2119 0 : if ( mpEntryList->HasImages() )
2120 0 : nTextStyle |= TEXT_DRAW_LEFT;
2121 0 : else if ( mbCenter )
2122 0 : nTextStyle |= TEXT_DRAW_CENTER;
2123 0 : else if ( mbRight )
2124 0 : nTextStyle |= TEXT_DRAW_RIGHT;
2125 : else
2126 0 : nTextStyle |= TEXT_DRAW_LEFT;
2127 :
2128 0 : return nTextStyle;
2129 : }
2130 :
2131 0 : ImplListBox::ImplListBox( Window* pParent, WinBits nWinStyle ) :
2132 : Control( pParent, nWinStyle ),
2133 0 : maLBWindow( this, nWinStyle&(~WB_BORDER) )
2134 : {
2135 : // for native widget rendering we must be able to detect this window type
2136 0 : SetType( WINDOW_LISTBOXWINDOW );
2137 :
2138 0 : mpVScrollBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
2139 0 : mpHScrollBar = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
2140 0 : mpScrollBarBox = new ScrollBarBox( this );
2141 :
2142 0 : Link aLink( LINK( this, ImplListBox, ScrollBarHdl ) );
2143 0 : mpVScrollBar->SetScrollHdl( aLink );
2144 0 : mpHScrollBar->SetScrollHdl( aLink );
2145 :
2146 0 : mbVScroll = false;
2147 0 : mbHScroll = false;
2148 0 : mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL );
2149 0 : mbEdgeBlending = false;
2150 :
2151 0 : maLBWindow.SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled ) );
2152 0 : maLBWindow.SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged ) );
2153 0 : maLBWindow.SetEdgeBlending(GetEdgeBlending());
2154 0 : maLBWindow.Show();
2155 0 : }
2156 :
2157 0 : ImplListBox::~ImplListBox()
2158 : {
2159 0 : delete mpHScrollBar;
2160 0 : delete mpVScrollBar;
2161 0 : delete mpScrollBarBox;
2162 0 : }
2163 :
2164 0 : void ImplListBox::Clear()
2165 : {
2166 0 : maLBWindow.Clear();
2167 0 : if ( GetEntryList()->GetMRUCount() )
2168 : {
2169 0 : maLBWindow.GetEntryList()->SetMRUCount( 0 );
2170 0 : maLBWindow.SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND );
2171 : }
2172 0 : mpVScrollBar->SetThumbPos( 0 );
2173 0 : mpHScrollBar->SetThumbPos( 0 );
2174 0 : StateChanged( STATE_CHANGE_DATA );
2175 0 : }
2176 :
2177 0 : sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr )
2178 : {
2179 0 : ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2180 0 : sal_Int32 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2181 0 : if (nNewPos == LISTBOX_ERROR)
2182 : {
2183 0 : delete pNewEntry;
2184 0 : return nNewPos;
2185 : }
2186 0 : StateChanged( STATE_CHANGE_DATA );
2187 0 : return nNewPos;
2188 : }
2189 :
2190 0 : sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr, const Image& rImage )
2191 : {
2192 0 : ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2193 0 : sal_Int32 nNewPos = maLBWindow.InsertEntry( nPos, pNewEntry );
2194 0 : if (nNewPos == LISTBOX_ERROR)
2195 : {
2196 0 : delete pNewEntry;
2197 0 : return nNewPos;
2198 : }
2199 0 : StateChanged( STATE_CHANGE_DATA );
2200 0 : return nNewPos;
2201 : }
2202 :
2203 0 : void ImplListBox::RemoveEntry( sal_Int32 nPos )
2204 : {
2205 0 : maLBWindow.RemoveEntry( nPos );
2206 0 : StateChanged( STATE_CHANGE_DATA );
2207 0 : }
2208 :
2209 0 : void ImplListBox::SetEntryFlags( sal_Int32 nPos, long nFlags )
2210 : {
2211 0 : maLBWindow.SetEntryFlags( nPos, nFlags );
2212 0 : }
2213 :
2214 0 : void ImplListBox::SelectEntry( sal_Int32 nPos, bool bSelect )
2215 : {
2216 0 : maLBWindow.SelectEntry( nPos, bSelect );
2217 0 : }
2218 :
2219 0 : void ImplListBox::SetNoSelection()
2220 : {
2221 0 : maLBWindow.DeselectAll();
2222 0 : }
2223 :
2224 0 : void ImplListBox::GetFocus()
2225 : {
2226 0 : maLBWindow.GrabFocus();
2227 0 : }
2228 :
2229 0 : Window* ImplListBox::GetPreferredKeyInputWindow()
2230 : {
2231 0 : return &maLBWindow;
2232 : }
2233 :
2234 0 : void ImplListBox::Resize()
2235 : {
2236 0 : Control::Resize();
2237 0 : ImplResizeControls();
2238 0 : ImplCheckScrollBars();
2239 0 : }
2240 :
2241 0 : IMPL_LINK_NOARG(ImplListBox, MRUChanged)
2242 : {
2243 0 : StateChanged( STATE_CHANGE_DATA );
2244 0 : return 1;
2245 : }
2246 :
2247 0 : IMPL_LINK_NOARG(ImplListBox, LBWindowScrolled)
2248 : {
2249 0 : long nSet = GetTopEntry();
2250 0 : if( nSet > mpVScrollBar->GetRangeMax() )
2251 0 : mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2252 0 : mpVScrollBar->SetThumbPos( GetTopEntry() );
2253 :
2254 0 : mpHScrollBar->SetThumbPos( GetLeftIndent() );
2255 :
2256 0 : maScrollHdl.Call( this );
2257 :
2258 0 : return 1;
2259 : }
2260 :
2261 0 : IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB )
2262 : {
2263 0 : sal_uInt16 nPos = (sal_uInt16) pSB->GetThumbPos();
2264 0 : if( pSB == mpVScrollBar )
2265 0 : SetTopEntry( nPos );
2266 0 : else if( pSB == mpHScrollBar )
2267 0 : SetLeftIndent( nPos );
2268 :
2269 0 : return 1;
2270 : }
2271 :
2272 0 : void ImplListBox::ImplCheckScrollBars()
2273 : {
2274 0 : bool bArrange = false;
2275 :
2276 0 : Size aOutSz = GetOutputSizePixel();
2277 0 : sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2278 0 : sal_uInt16 nMaxVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2279 :
2280 : // vertical ScrollBar
2281 0 : if( nEntries > nMaxVisEntries )
2282 : {
2283 0 : if( !mbVScroll )
2284 0 : bArrange = true;
2285 0 : mbVScroll = true;
2286 :
2287 : // check of the scrolled-out region
2288 0 : if( GetEntryList()->GetSelectEntryCount() == 1 &&
2289 0 : GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2290 0 : ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2291 : else
2292 0 : SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2293 : }
2294 : else
2295 : {
2296 0 : if( mbVScroll )
2297 0 : bArrange = true;
2298 0 : mbVScroll = false;
2299 0 : SetTopEntry( 0 );
2300 : }
2301 :
2302 : // horizontal ScrollBar
2303 0 : if( mbAutoHScroll )
2304 : {
2305 0 : long nWidth = (sal_uInt16) aOutSz.Width();
2306 0 : if ( mbVScroll )
2307 0 : nWidth -= mpVScrollBar->GetSizePixel().Width();
2308 :
2309 0 : long nMaxWidth = GetMaxEntryWidth();
2310 0 : if( nWidth < nMaxWidth )
2311 : {
2312 0 : if( !mbHScroll )
2313 0 : bArrange = true;
2314 0 : mbHScroll = true;
2315 :
2316 0 : if ( !mbVScroll ) // maybe we do need one now
2317 : {
2318 0 : nMaxVisEntries = (sal_uInt16) ( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeight() );
2319 0 : if( nEntries > nMaxVisEntries )
2320 : {
2321 0 : bArrange = true;
2322 0 : mbVScroll = true;
2323 :
2324 : // check of the scrolled-out region
2325 0 : if( GetEntryList()->GetSelectEntryCount() == 1 &&
2326 0 : GetEntryList()->GetSelectEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND )
2327 0 : ShowProminentEntry( GetEntryList()->GetSelectEntryPos( 0 ) );
2328 : else
2329 0 : SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2330 : }
2331 : }
2332 :
2333 : // check of the scrolled-out region
2334 0 : sal_uInt16 nMaxLI = (sal_uInt16) (nMaxWidth - nWidth);
2335 0 : if ( nMaxLI < GetLeftIndent() )
2336 0 : SetLeftIndent( nMaxLI );
2337 : }
2338 : else
2339 : {
2340 0 : if( mbHScroll )
2341 0 : bArrange = true;
2342 0 : mbHScroll = false;
2343 0 : SetLeftIndent( 0 );
2344 : }
2345 : }
2346 :
2347 0 : if( bArrange )
2348 0 : ImplResizeControls();
2349 :
2350 0 : ImplInitScrollBars();
2351 0 : }
2352 :
2353 0 : void ImplListBox::ImplInitScrollBars()
2354 : {
2355 0 : Size aOutSz = maLBWindow.GetOutputSizePixel();
2356 :
2357 0 : if ( mbVScroll )
2358 : {
2359 0 : sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2360 0 : sal_uInt16 nVisEntries = (sal_uInt16) (aOutSz.Height() / GetEntryHeight());
2361 0 : mpVScrollBar->SetRangeMax( nEntries );
2362 0 : mpVScrollBar->SetVisibleSize( nVisEntries );
2363 0 : mpVScrollBar->SetPageSize( nVisEntries - 1 );
2364 : }
2365 :
2366 0 : if ( mbHScroll )
2367 : {
2368 0 : mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL );
2369 0 : mpHScrollBar->SetVisibleSize( (sal_uInt16)aOutSz.Width() );
2370 0 : mpHScrollBar->SetLineSize( HORZ_SCROLL );
2371 0 : mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL );
2372 : }
2373 0 : }
2374 :
2375 0 : void ImplListBox::ImplResizeControls()
2376 : {
2377 : // Here we only position the Controls; if the Scrollbars are to be
2378 : // visible is already determined in ImplCheckScrollBars
2379 :
2380 0 : Size aOutSz = GetOutputSizePixel();
2381 0 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2382 0 : nSBWidth = CalcZoom( nSBWidth );
2383 :
2384 0 : Size aInnerSz( aOutSz );
2385 0 : if ( mbVScroll )
2386 0 : aInnerSz.Width() -= nSBWidth;
2387 0 : if ( mbHScroll )
2388 0 : aInnerSz.Height() -= nSBWidth;
2389 :
2390 : // pb: #106948# explicit mirroring for calc
2391 : // Scrollbar on left or right side?
2392 0 : bool bMirroring = maLBWindow.IsMirroring();
2393 0 : Point aWinPos( bMirroring && mbVScroll ? nSBWidth : 0, 0 );
2394 0 : maLBWindow.SetPosSizePixel( aWinPos, aInnerSz );
2395 :
2396 : // ScrollBarBox
2397 0 : if( mbVScroll && mbHScroll )
2398 : {
2399 0 : Point aBoxPos( bMirroring ? 0 : aInnerSz.Width(), aInnerSz.Height() );
2400 0 : mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2401 0 : mpScrollBarBox->Show();
2402 : }
2403 : else
2404 : {
2405 0 : mpScrollBarBox->Hide();
2406 : }
2407 :
2408 : // vertical ScrollBar
2409 0 : if( mbVScroll )
2410 : {
2411 : // Scrollbar on left or right side?
2412 0 : Point aVPos( bMirroring ? 0 : aOutSz.Width() - nSBWidth, 0 );
2413 0 : mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2414 0 : mpVScrollBar->Show();
2415 : }
2416 : else
2417 : {
2418 0 : mpVScrollBar->Hide();
2419 : // #107254# Don't reset top entry after resize, but check for max top entry
2420 0 : SetTopEntry( GetTopEntry() );
2421 : }
2422 :
2423 : // horizontal ScrollBar
2424 0 : if( mbHScroll )
2425 : {
2426 0 : Point aHPos( ( bMirroring && mbVScroll ) ? nSBWidth : 0, aOutSz.Height() - nSBWidth );
2427 0 : mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2428 0 : mpHScrollBar->Show();
2429 : }
2430 : else
2431 : {
2432 0 : mpHScrollBar->Hide();
2433 0 : SetLeftIndent( 0 );
2434 : }
2435 0 : }
2436 :
2437 0 : void ImplListBox::StateChanged( StateChangedType nType )
2438 : {
2439 0 : if ( nType == STATE_CHANGE_INITSHOW )
2440 : {
2441 0 : ImplCheckScrollBars();
2442 : }
2443 0 : else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
2444 : {
2445 0 : bool bUpdate = IsUpdateMode();
2446 0 : maLBWindow.SetUpdateMode( bUpdate );
2447 0 : if ( bUpdate && IsReallyVisible() )
2448 0 : ImplCheckScrollBars();
2449 : }
2450 0 : else if( nType == STATE_CHANGE_ENABLE )
2451 : {
2452 0 : mpHScrollBar->Enable( IsEnabled() );
2453 0 : mpVScrollBar->Enable( IsEnabled() );
2454 0 : mpScrollBarBox->Enable( IsEnabled() );
2455 0 : maLBWindow.Enable( IsEnabled() );
2456 :
2457 0 : Invalidate();
2458 : }
2459 0 : else if ( nType == STATE_CHANGE_ZOOM )
2460 : {
2461 0 : maLBWindow.SetZoom( GetZoom() );
2462 0 : Resize();
2463 : }
2464 0 : else if ( nType == STATE_CHANGE_CONTROLFONT )
2465 : {
2466 0 : maLBWindow.SetControlFont( GetControlFont() );
2467 : }
2468 0 : else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2469 : {
2470 0 : maLBWindow.SetControlForeground( GetControlForeground() );
2471 : }
2472 0 : else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2473 : {
2474 0 : maLBWindow.SetControlBackground( GetControlBackground() );
2475 : }
2476 0 : else if( nType == STATE_CHANGE_MIRRORING )
2477 : {
2478 0 : maLBWindow.EnableRTL( IsRTLEnabled() );
2479 0 : mpHScrollBar->EnableRTL( IsRTLEnabled() );
2480 0 : mpVScrollBar->EnableRTL( IsRTLEnabled() );
2481 0 : ImplResizeControls();
2482 : }
2483 :
2484 0 : Control::StateChanged( nType );
2485 0 : }
2486 :
2487 0 : void ImplListBox::DataChanged( const DataChangedEvent& rDCEvt )
2488 : {
2489 0 : Control::DataChanged( rDCEvt );
2490 0 : }
2491 :
2492 0 : bool ImplListBox::Notify( NotifyEvent& rNEvt )
2493 : {
2494 0 : bool nDone = false;
2495 0 : if ( rNEvt.GetType() == EVENT_COMMAND )
2496 : {
2497 0 : const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2498 0 : if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2499 : {
2500 0 : const CommandWheelData* pData = rCEvt.GetWheelData();
2501 0 : if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2502 : {
2503 0 : nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2504 : }
2505 : }
2506 : }
2507 :
2508 0 : return nDone || Window::Notify( rNEvt );
2509 : }
2510 :
2511 0 : const Wallpaper& ImplListBox::GetDisplayBackground() const
2512 : {
2513 0 : return maLBWindow.GetDisplayBackground();
2514 : }
2515 :
2516 0 : bool ImplListBox::HandleWheelAsCursorTravel( const CommandEvent& rCEvt )
2517 : {
2518 0 : bool bDone = false;
2519 0 : if ( rCEvt.GetCommand() == COMMAND_WHEEL )
2520 : {
2521 0 : const CommandWheelData* pData = rCEvt.GetWheelData();
2522 0 : if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
2523 : {
2524 0 : sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2525 0 : KeyEvent aKeyEvent( 0, KeyCode( nKey ) );
2526 0 : bDone = ProcessKeyInput( aKeyEvent );
2527 : }
2528 : }
2529 0 : return bDone;
2530 : }
2531 :
2532 0 : void ImplListBox::SetMRUEntries( const OUString& rEntries, sal_Unicode cSep )
2533 : {
2534 0 : bool bChanges = GetEntryList()->GetMRUCount() ? true : false;
2535 :
2536 : // Remove old MRU entries
2537 0 : for ( sal_Int32 n = GetEntryList()->GetMRUCount();n; )
2538 0 : maLBWindow.RemoveEntry( --n );
2539 :
2540 0 : sal_Int32 nMRUCount = 0;
2541 0 : sal_Int32 nIndex = 0;
2542 0 : do
2543 : {
2544 0 : OUString aEntry = rEntries.getToken( 0, cSep, nIndex );
2545 : // Accept only existing entries
2546 0 : if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND )
2547 : {
2548 0 : ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2549 0 : maLBWindow.GetEntryList()->InsertEntry( nMRUCount++, pNewEntry, false );
2550 0 : bChanges = true;
2551 0 : }
2552 : }
2553 0 : while ( nIndex >= 0 );
2554 :
2555 0 : if ( bChanges )
2556 : {
2557 0 : maLBWindow.GetEntryList()->SetMRUCount( nMRUCount );
2558 0 : SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2559 0 : StateChanged( STATE_CHANGE_DATA );
2560 : }
2561 0 : }
2562 :
2563 0 : OUString ImplListBox::GetMRUEntries( sal_Unicode cSep ) const
2564 : {
2565 0 : OUStringBuffer aEntries;
2566 0 : for ( sal_Int32 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2567 : {
2568 0 : aEntries.append(GetEntryList()->GetEntryText( n ));
2569 0 : if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2570 0 : aEntries.append(cSep);
2571 : }
2572 0 : return aEntries.makeStringAndClear();
2573 : }
2574 :
2575 0 : void ImplListBox::SetEdgeBlending(bool bNew)
2576 : {
2577 0 : if(mbEdgeBlending != bNew)
2578 : {
2579 0 : mbEdgeBlending = bNew;
2580 0 : maLBWindow.SetEdgeBlending(GetEdgeBlending());
2581 : }
2582 0 : }
2583 :
2584 0 : ImplWin::ImplWin( Window* pParent, WinBits nWinStyle ) :
2585 0 : Control ( pParent, nWinStyle )
2586 : {
2587 0 : if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2588 0 : && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2589 0 : SetBackground();
2590 : else
2591 0 : SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2592 :
2593 0 : mbInUserDraw = false;
2594 0 : mbUserDrawEnabled = false;
2595 0 : mbEdgeBlending = false;
2596 0 : mnItemPos = LISTBOX_ENTRY_NOTFOUND;
2597 0 : }
2598 :
2599 0 : void ImplWin::MBDown()
2600 : {
2601 0 : if( IsEnabled() )
2602 0 : maMBDownHdl.Call( this );
2603 0 : }
2604 :
2605 0 : void ImplWin::MouseButtonDown( const MouseEvent& )
2606 : {
2607 0 : if( IsEnabled() )
2608 : {
2609 0 : MBDown();
2610 : }
2611 0 : }
2612 :
2613 0 : void ImplWin::FillLayoutData() const
2614 : {
2615 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
2616 0 : const_cast<ImplWin*>(this)->ImplDraw( true );
2617 0 : }
2618 :
2619 0 : bool ImplWin::PreNotify( NotifyEvent& rNEvt )
2620 : {
2621 0 : const MouseEvent* pMouseEvt = NULL;
2622 :
2623 0 : if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
2624 : {
2625 0 : if( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() )
2626 : {
2627 : // trigger redraw as mouse over state has changed
2628 0 : if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2629 0 : && ! IsNativeControlSupported(CTRL_LISTBOX, PART_BUTTON_DOWN) )
2630 : {
2631 0 : GetParent()->GetWindow( WINDOW_BORDER )->Invalidate( INVALIDATE_NOERASE );
2632 0 : GetParent()->GetWindow( WINDOW_BORDER )->Update();
2633 : }
2634 : }
2635 : }
2636 :
2637 0 : return Control::PreNotify(rNEvt);
2638 : }
2639 :
2640 0 : void ImplWin::ImplDraw( bool bLayout )
2641 : {
2642 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2643 :
2644 0 : bool bNativeOK = false;
2645 :
2646 0 : if( ! bLayout )
2647 : {
2648 0 : ControlState nState = CTRL_STATE_ENABLED;
2649 0 : if ( IsNativeControlSupported(CTRL_LISTBOX, PART_ENTIRE_CONTROL)
2650 0 : && IsNativeControlSupported(CTRL_LISTBOX, HAS_BACKGROUND_TEXTURE) )
2651 : {
2652 : // Repaint the (focused) area similarly to
2653 : // ImplSmallBorderWindowView::DrawWindow() in
2654 : // vcl/source/window/brdwin.cxx
2655 0 : Window *pWin = GetParent();
2656 :
2657 0 : ImplControlValue aControlValue;
2658 0 : if ( !pWin->IsEnabled() )
2659 0 : nState &= ~CTRL_STATE_ENABLED;
2660 0 : if ( pWin->HasFocus() )
2661 0 : nState |= CTRL_STATE_FOCUSED;
2662 :
2663 : // The listbox is painted over the entire control including the
2664 : // border, but ImplWin does not contain the border => correction
2665 : // needed.
2666 : sal_Int32 nLeft, nTop, nRight, nBottom;
2667 0 : pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2668 0 : Point aPoint( -nLeft, -nTop );
2669 0 : Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2670 :
2671 0 : bool bMouseOver = false;
2672 0 : if( GetParent() )
2673 : {
2674 0 : Window *pChild = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
2675 0 : while( pChild && !(bMouseOver = pChild->IsMouseOver()) )
2676 0 : pChild = pChild->GetWindow( WINDOW_NEXT );
2677 : }
2678 :
2679 0 : if( bMouseOver )
2680 0 : nState |= CTRL_STATE_ROLLOVER;
2681 :
2682 : // if parent has no border, then nobody has drawn the background
2683 : // since no border window exists. so draw it here.
2684 0 : WinBits nParentStyle = pWin->GetStyle();
2685 0 : if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2686 : {
2687 0 : Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2688 : pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentRect,
2689 0 : nState, aControlValue, OUString() );
2690 : }
2691 :
2692 : bNativeOK = DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
2693 0 : aControlValue, OUString() );
2694 : }
2695 :
2696 0 : if( IsEnabled() )
2697 : {
2698 0 : if( HasFocus() )
2699 : {
2700 0 : SetTextColor( rStyleSettings.GetHighlightTextColor() );
2701 0 : SetFillColor( rStyleSettings.GetHighlightColor() );
2702 0 : DrawRect( maFocusRect );
2703 : }
2704 : else
2705 : {
2706 0 : Color aColor;
2707 0 : if( ImplGetSVData()->maNWFData.mbDDListBoxNoTextArea )
2708 : {
2709 0 : if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2710 0 : aColor = rStyleSettings.GetButtonRolloverTextColor();
2711 : else
2712 0 : aColor = rStyleSettings.GetButtonTextColor();
2713 : }
2714 : else
2715 : {
2716 0 : if( bNativeOK && (nState & CTRL_STATE_ROLLOVER) )
2717 0 : aColor = rStyleSettings.GetFieldRolloverTextColor();
2718 : else
2719 0 : aColor = rStyleSettings.GetFieldTextColor();
2720 : }
2721 0 : if( IsControlForeground() )
2722 0 : aColor = GetControlForeground();
2723 0 : SetTextColor( aColor );
2724 0 : if ( !bNativeOK )
2725 0 : Erase( maFocusRect );
2726 : }
2727 : }
2728 : else // Disabled
2729 : {
2730 0 : SetTextColor( rStyleSettings.GetDisableColor() );
2731 0 : if ( !bNativeOK )
2732 0 : Erase( maFocusRect );
2733 : }
2734 : }
2735 :
2736 0 : if ( IsUserDrawEnabled() )
2737 : {
2738 0 : mbInUserDraw = true;
2739 0 : UserDrawEvent aUDEvt( this, maFocusRect, mnItemPos, 0 );
2740 0 : maUserDrawHdl.Call( &aUDEvt );
2741 0 : mbInUserDraw = false;
2742 : }
2743 : else
2744 : {
2745 0 : DrawEntry( true, true, false, bLayout );
2746 : }
2747 0 : }
2748 :
2749 0 : void ImplWin::Paint( const Rectangle& )
2750 : {
2751 0 : ImplDraw();
2752 0 : }
2753 :
2754 0 : void ImplWin::DrawEntry( bool bDrawImage, bool bDrawText, bool bDrawTextAtImagePos, bool bLayout )
2755 : {
2756 0 : long nBorder = 1;
2757 0 : Size aOutSz = GetOutputSizePixel();
2758 :
2759 0 : bool bImage = !!maImage;
2760 0 : if( bDrawImage && bImage && !bLayout )
2761 : {
2762 0 : sal_uInt16 nStyle = 0;
2763 0 : Size aImgSz = maImage.GetSizePixel();
2764 0 : Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2765 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2766 :
2767 : // check for HC mode
2768 0 : Image *pImage = &maImage;
2769 :
2770 0 : if ( !IsZoom() )
2771 : {
2772 0 : DrawImage( aPtImg, *pImage, nStyle );
2773 : }
2774 : else
2775 : {
2776 0 : aImgSz.Width() = CalcZoom( aImgSz.Width() );
2777 0 : aImgSz.Height() = CalcZoom( aImgSz.Height() );
2778 0 : DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2779 : }
2780 :
2781 0 : const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
2782 :
2783 0 : if(nEdgeBlendingPercent)
2784 : {
2785 0 : const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
2786 0 : const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
2787 0 : const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
2788 0 : const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
2789 :
2790 0 : if(!aBlendFrame.IsEmpty())
2791 : {
2792 0 : DrawBitmapEx(aPtImg, aBlendFrame);
2793 0 : }
2794 : }
2795 : }
2796 :
2797 0 : if( bDrawText && !maString.isEmpty() )
2798 : {
2799 0 : sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
2800 :
2801 0 : if ( bDrawImage && bImage && !bLayout )
2802 0 : nTextStyle |= TEXT_DRAW_LEFT;
2803 0 : else if ( GetStyle() & WB_CENTER )
2804 0 : nTextStyle |= TEXT_DRAW_CENTER;
2805 0 : else if ( GetStyle() & WB_RIGHT )
2806 0 : nTextStyle |= TEXT_DRAW_RIGHT;
2807 : else
2808 0 : nTextStyle |= TEXT_DRAW_LEFT;
2809 :
2810 0 : Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
2811 :
2812 0 : if ( !bDrawTextAtImagePos && ( bImage || IsUserDrawEnabled() ) )
2813 : {
2814 0 : long nMaxWidth = std::max( maImage.GetSizePixel().Width(), maUserItemSize.Width() );
2815 0 : aTextRect.Left() += nMaxWidth + IMG_TXT_DISTANCE;
2816 : }
2817 :
2818 0 : MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : NULL;
2819 0 : OUString* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : NULL;
2820 0 : DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
2821 : }
2822 :
2823 0 : if( HasFocus() && !bLayout )
2824 0 : ShowFocus( maFocusRect );
2825 0 : }
2826 :
2827 0 : void ImplWin::Resize()
2828 : {
2829 0 : Control::Resize();
2830 0 : maFocusRect.SetSize( GetOutputSizePixel() );
2831 0 : Invalidate();
2832 0 : }
2833 :
2834 0 : void ImplWin::GetFocus()
2835 : {
2836 0 : ShowFocus( maFocusRect );
2837 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2838 0 : IsNativeWidgetEnabled() &&
2839 0 : IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2840 : {
2841 0 : Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
2842 0 : if( ! pWin )
2843 0 : pWin = GetParent();
2844 0 : pWin->Invalidate();
2845 : }
2846 : else
2847 0 : Invalidate();
2848 0 : Control::GetFocus();
2849 0 : }
2850 :
2851 0 : void ImplWin::LoseFocus()
2852 : {
2853 0 : HideFocus();
2854 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2855 0 : IsNativeWidgetEnabled() &&
2856 0 : IsNativeControlSupported( CTRL_LISTBOX, PART_ENTIRE_CONTROL ) )
2857 : {
2858 0 : Window* pWin = GetParent()->GetWindow( WINDOW_BORDER );
2859 0 : if( ! pWin )
2860 0 : pWin = GetParent();
2861 0 : pWin->Invalidate();
2862 : }
2863 : else
2864 0 : Invalidate();
2865 0 : Control::LoseFocus();
2866 0 : }
2867 :
2868 0 : ImplBtn::ImplBtn( Window* pParent, WinBits nWinStyle ) :
2869 : PushButton( pParent, nWinStyle ),
2870 0 : mbDown ( false )
2871 : {
2872 0 : }
2873 :
2874 0 : void ImplBtn::MBDown()
2875 : {
2876 0 : if( IsEnabled() )
2877 0 : maMBDownHdl.Call( this );
2878 0 : }
2879 :
2880 0 : void ImplBtn::MouseButtonDown( const MouseEvent& )
2881 : {
2882 : //PushButton::MouseButtonDown( rMEvt );
2883 0 : if( IsEnabled() )
2884 : {
2885 0 : MBDown();
2886 0 : mbDown = true;
2887 : }
2888 0 : }
2889 :
2890 0 : ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( Window* pParent ) :
2891 0 : FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
2892 : {
2893 0 : mpImplLB = NULL;
2894 0 : mnDDLineCount = 0;
2895 0 : mbAutoWidth = false;
2896 :
2897 0 : mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND;
2898 :
2899 0 : EnableSaveBackground();
2900 :
2901 0 : Window * pBorderWindow = ImplGetBorderWindow();
2902 0 : if( pBorderWindow )
2903 : {
2904 0 : SetAccessibleRole(accessibility::AccessibleRole::PANEL);
2905 0 : pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2906 : }
2907 : else
2908 : {
2909 0 : SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2910 : }
2911 :
2912 0 : }
2913 :
2914 0 : bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
2915 : {
2916 0 : if( rNEvt.GetType() == EVENT_LOSEFOCUS )
2917 : {
2918 0 : if( !GetParent()->HasChildPathFocus( true ) )
2919 0 : EndPopupMode();
2920 : }
2921 :
2922 0 : return FloatingWindow::PreNotify( rNEvt );
2923 : }
2924 :
2925 0 : void ImplListBoxFloatingWindow::setPosSizePixel( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
2926 : {
2927 0 : FloatingWindow::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
2928 :
2929 : // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2930 : // after a call to Resize(), we adjust its position if necessary
2931 0 : if ( IsReallyVisible() && ( nFlags & WINDOW_POSSIZE_HEIGHT ) )
2932 : {
2933 0 : Point aPos = GetParent()->GetPosPixel();
2934 0 : aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
2935 :
2936 0 : if ( nFlags & WINDOW_POSSIZE_X )
2937 0 : aPos.X() = nX;
2938 :
2939 0 : if ( nFlags & WINDOW_POSSIZE_Y )
2940 0 : aPos.Y() = nY;
2941 :
2942 : sal_uInt16 nIndex;
2943 0 : SetPosPixel( ImplCalcPos( this, Rectangle( aPos, GetParent()->GetSizePixel() ), FLOATWIN_POPUPMODE_DOWN, nIndex ) );
2944 : }
2945 :
2946 : // if( !IsReallyVisible() )
2947 : {
2948 : // The ImplListBox does not get a Resize() as not visible.
2949 : // But the windows must get a Resize(), so that the number of
2950 : // visible entries is correct for PgUp/PgDown.
2951 : // The number also cannot be calculated by List/Combobox, as for
2952 : // this the presence of the vertical Scrollbar has to be known.
2953 0 : mpImplLB->SetSizePixel( GetOutputSizePixel() );
2954 0 : ((Window*)mpImplLB)->Resize();
2955 0 : ((Window*)mpImplLB->GetMainWindow())->Resize();
2956 : }
2957 0 : }
2958 :
2959 0 : void ImplListBoxFloatingWindow::Resize()
2960 : {
2961 0 : mpImplLB->GetMainWindow()->ImplClearLayoutData();
2962 0 : FloatingWindow::Resize();
2963 0 : }
2964 :
2965 0 : Size ImplListBoxFloatingWindow::CalcFloatSize()
2966 : {
2967 0 : Size aFloatSz( maPrefSz );
2968 :
2969 : sal_Int32 nLeft, nTop, nRight, nBottom;
2970 0 : GetBorder( nLeft, nTop, nRight, nBottom );
2971 :
2972 0 : sal_Int32 nLines = mpImplLB->GetEntryList()->GetEntryCount();
2973 0 : if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
2974 0 : nLines = mnDDLineCount;
2975 :
2976 0 : Size aSz = mpImplLB->CalcSize( nLines );
2977 0 : long nMaxHeight = aSz.Height() + nTop + nBottom;
2978 :
2979 0 : if ( mnDDLineCount )
2980 0 : aFloatSz.Height() = nMaxHeight;
2981 :
2982 0 : if( mbAutoWidth )
2983 : {
2984 : // AutoSize first only for width...
2985 :
2986 0 : aFloatSz.Width() = aSz.Width() + nLeft + nRight;
2987 0 : aFloatSz.Width() += nRight; // adding some space looks better...
2988 :
2989 0 : if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
2990 : {
2991 : // then we also need the vertical Scrollbar
2992 0 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2993 0 : aFloatSz.Width() += nSBWidth;
2994 : }
2995 :
2996 0 : long nDesktopWidth = GetDesktopRectPixel().getWidth();
2997 0 : if (aFloatSz.Width() > nDesktopWidth)
2998 : // Don't exceed the desktop width.
2999 0 : aFloatSz.Width() = nDesktopWidth;
3000 : }
3001 :
3002 0 : if ( aFloatSz.Height() > nMaxHeight )
3003 0 : aFloatSz.Height() = nMaxHeight;
3004 :
3005 : // Minimal height, in case height is not set to Float height.
3006 : // The parent of FloatWin must be DropDown-Combo/Listbox.
3007 0 : Size aParentSz = GetParent()->GetSizePixel();
3008 0 : if( (!mnDDLineCount || !nLines) && ( aFloatSz.Height() < aParentSz.Height() ) )
3009 0 : aFloatSz.Height() = aParentSz.Height();
3010 :
3011 : // do not get narrower than the parent...
3012 0 : if( aFloatSz.Width() < aParentSz.Width() )
3013 0 : aFloatSz.Width() = aParentSz.Width();
3014 :
3015 : // align height to entries...
3016 0 : long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
3017 0 : long nEntryHeight = mpImplLB->GetEntryHeight();
3018 0 : if ( nInnerHeight % nEntryHeight )
3019 : {
3020 0 : nInnerHeight /= nEntryHeight;
3021 0 : nInnerHeight++;
3022 0 : nInnerHeight *= nEntryHeight;
3023 0 : aFloatSz.Height() = nInnerHeight + nTop + nBottom;
3024 : }
3025 :
3026 0 : if (aFloatSz.Width() < aSz.Width())
3027 : {
3028 : // The max width of list box entries exceeds the window width.
3029 : // Account for the scroll bar height.
3030 0 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
3031 0 : aFloatSz.Height() += nSBWidth;
3032 : }
3033 :
3034 0 : return aFloatSz;
3035 : }
3036 :
3037 0 : void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking )
3038 : {
3039 0 : if( !IsInPopupMode() )
3040 : {
3041 0 : Size aFloatSz = CalcFloatSize();
3042 :
3043 0 : SetSizePixel( aFloatSz );
3044 0 : mpImplLB->SetSizePixel( GetOutputSizePixel() );
3045 :
3046 0 : sal_Int32 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
3047 0 : mnPopupModeStartSaveSelection = nPos;
3048 :
3049 0 : Size aSz = GetParent()->GetSizePixel();
3050 0 : Point aPos = GetParent()->GetPosPixel();
3051 0 : aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
3052 : // FIXME: this ugly hack is for Mac/Aqua
3053 : // should be replaced by a real mechanism to place the float rectangle
3054 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
3055 0 : GetParent()->IsNativeWidgetEnabled() )
3056 : {
3057 0 : sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
3058 0 : aPos.X() += nLeft;
3059 0 : aPos.Y() += nTop;
3060 0 : aSz.Width() -= nLeft + nRight;
3061 0 : aSz.Height() -= nTop + nBottom;
3062 : }
3063 0 : Rectangle aRect( aPos, aSz );
3064 :
3065 : // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
3066 : // where the document is unmirrored
3067 : // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
3068 0 : Window *pGrandparent = GetParent()->GetParent();
3069 0 : const OutputDevice *pGrandparentOutDev = pGrandparent->GetOutDev();
3070 :
3071 0 : if( pGrandparent->ImplIsAntiparallel() )
3072 0 : pGrandparentOutDev->ReMirror( aRect );
3073 :
3074 0 : StartPopupMode( aRect, FLOATWIN_POPUPMODE_DOWN );
3075 :
3076 0 : if( nPos != LISTBOX_ENTRY_NOTFOUND )
3077 0 : mpImplLB->ShowProminentEntry( nPos );
3078 :
3079 0 : if( bStartTracking )
3080 0 : mpImplLB->GetMainWindow()->EnableMouseMoveSelect( true );
3081 :
3082 0 : if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
3083 0 : mpImplLB->GetMainWindow()->GrabFocus();
3084 :
3085 0 : mpImplLB->GetMainWindow()->ImplClearLayoutData();
3086 : }
3087 0 : }
3088 :
3089 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|