1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21 #include <vcl/commandevent.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/lstbox.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/uitest/uiobject.hxx>
26 #include <sal/log.hxx>
27
28 #include <svdata.hxx>
29 #include <controldata.hxx>
30 #include <listbox.hxx>
31 #include <dndeventdispatcher.hxx>
32 #include <comphelper/lok.hxx>
33
34 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
35 #include <boost/property_tree/ptree.hpp>
36
EnableQuickSelection(bool b)37 void ListBox::EnableQuickSelection( bool b )
38 {
39 mpImplLB->GetMainWindow()->EnableQuickSelection(b);
40 }
41
ListBox(WindowType nType)42 ListBox::ListBox(WindowType nType)
43 : Control(nType)
44 , mpImplLB(nullptr)
45 {
46 ImplInitListBoxData();
47 }
48
ListBox(vcl::Window * pParent,WinBits nStyle)49 ListBox::ListBox( vcl::Window* pParent, WinBits nStyle ) : Control( WindowType::LISTBOX )
50 {
51 ImplInitListBoxData();
52 ImplInit( pParent, nStyle );
53 }
54
~ListBox()55 ListBox::~ListBox()
56 {
57 disposeOnce();
58 }
59
dispose()60 void ListBox::dispose()
61 {
62 CallEventListeners( VclEventId::ObjectDying );
63
64 mpImplLB.disposeAndClear();
65 mpFloatWin.disposeAndClear();
66 mpImplWin.disposeAndClear();
67 mpBtn.disposeAndClear();
68
69 Control::dispose();
70 }
71
ImplInitListBoxData()72 void ListBox::ImplInitListBoxData()
73 {
74 mpFloatWin = nullptr;
75 mpImplWin = nullptr;
76 mpBtn = nullptr;
77 mnDDHeight = 0;
78 mnSaveValue = LISTBOX_ENTRY_NOTFOUND;
79 mnLineCount = 0;
80 m_nMaxWidthChars = -1;
81 mbDDAutoSize = true;
82 }
83
ImplInit(vcl::Window * pParent,WinBits nStyle)84 void ListBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
85 {
86 nStyle = ImplInitStyle( nStyle );
87 if ( !(nStyle & WB_NOBORDER) && ( nStyle & WB_DROPDOWN ) )
88 nStyle |= WB_BORDER;
89
90 Control::ImplInit( pParent, nStyle, nullptr );
91
92 css::uno::Reference< css::datatransfer::dnd::XDropTargetListener> xDrop = new DNDEventDispatcher(this);
93
94 if( nStyle & WB_DROPDOWN )
95 {
96 sal_Int32 nLeft, nTop, nRight, nBottom;
97 GetBorder( nLeft, nTop, nRight, nBottom );
98 mnDDHeight = static_cast<sal_uInt16>(GetTextHeight() + nTop + nBottom + 4);
99
100 if( IsNativeWidgetEnabled() &&
101 IsNativeControlSupported( ControlType::Listbox, ControlPart::Entire ) )
102 {
103 ImplControlValue aControlValue;
104 tools::Rectangle aCtrlRegion( Point( 0, 0 ), Size( 20, mnDDHeight ) );
105 tools::Rectangle aBoundingRgn( aCtrlRegion );
106 tools::Rectangle aContentRgn( aCtrlRegion );
107 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire, aCtrlRegion,
108 ControlState::ENABLED, aControlValue,
109 aBoundingRgn, aContentRgn ) )
110 {
111 sal_Int32 nHeight = aBoundingRgn.GetHeight();
112 if( nHeight > mnDDHeight )
113 mnDDHeight = static_cast<sal_uInt16>(nHeight);
114 }
115 }
116
117 mpFloatWin = VclPtr<ImplListBoxFloatingWindow>::Create( this );
118 if (!IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus))
119 mpFloatWin->RequestDoubleBuffering(true);
120 mpFloatWin->SetAutoWidth( true );
121 mpFloatWin->SetPopupModeEndHdl( LINK( this, ListBox, ImplPopupModeEndHdl ) );
122 mpFloatWin->GetDropTarget()->addDropTargetListener(xDrop);
123
124 mpImplWin = VclPtr<ImplWin>::Create( this, (nStyle & (WB_LEFT|WB_RIGHT|WB_CENTER))|WB_NOBORDER );
125 mpImplWin->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
126 mpImplWin->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
127 mpImplWin->Show();
128 mpImplWin->GetDropTarget()->addDropTargetListener(xDrop);
129 mpImplWin->SetEdgeBlending(false);
130
131 mpBtn = VclPtr<ImplBtn>::Create( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
132 ImplInitDropDownButton( mpBtn );
133 mpBtn->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
134 mpBtn->Show();
135 mpBtn->GetDropTarget()->addDropTargetListener(xDrop);
136 }
137
138 vcl::Window* pLBParent = this;
139 if ( mpFloatWin )
140 pLBParent = mpFloatWin;
141 mpImplLB = VclPtr<ImplListBox>::Create( pLBParent, nStyle&(~WB_BORDER) );
142 mpImplLB->SetSelectHdl( LINK( this, ListBox, ImplSelectHdl ) );
143 mpImplLB->SetScrollHdl( LINK( this, ListBox, ImplScrollHdl ) );
144 mpImplLB->SetCancelHdl( LINK( this, ListBox, ImplCancelHdl ) );
145 mpImplLB->SetDoubleClickHdl( LINK( this, ListBox, ImplDoubleClickHdl ) );
146 mpImplLB->SetUserDrawHdl( LINK( this, ListBox, ImplUserDrawHdl ) );
147 mpImplLB->SetFocusHdl( LINK( this, ListBox, ImplFocusHdl ) );
148 mpImplLB->SetListItemSelectHdl( LINK( this, ListBox, ImplListItemSelectHdl ) );
149 mpImplLB->SetPosPixel( Point() );
150 mpImplLB->SetEdgeBlending(false);
151 mpImplLB->Show();
152
153 mpImplLB->GetDropTarget()->addDropTargetListener(xDrop);
154
155 if ( mpFloatWin )
156 {
157 mpFloatWin->SetImplListBox( mpImplLB );
158 mpImplLB->SetSelectionChangedHdl( LINK( this, ListBox, ImplSelectionChangedHdl ) );
159 }
160 else
161 mpImplLB->GetMainWindow()->AllowGrabFocus( true );
162
163 SetCompoundControl( true );
164 }
165
ImplInitStyle(WinBits nStyle)166 WinBits ListBox::ImplInitStyle( WinBits nStyle )
167 {
168 if ( !(nStyle & WB_NOTABSTOP) )
169 nStyle |= WB_TABSTOP;
170 if ( !(nStyle & WB_NOGROUP) )
171 nStyle |= WB_GROUP;
172 return nStyle;
173 }
174
IMPL_LINK_NOARG(ListBox,ImplSelectHdl,LinkParamNone *,void)175 IMPL_LINK_NOARG(ListBox, ImplSelectHdl, LinkParamNone*, void)
176 {
177 bool bPopup = IsInDropDown();
178 if( IsDropDownBox() )
179 {
180 if( !mpImplLB->IsTravelSelect() )
181 {
182 mpFloatWin->EndPopupMode();
183 mpImplWin->GrabFocus();
184 }
185
186 mpImplWin->SetItemPos( GetSelectedEntryPos() );
187 mpImplWin->SetString( GetSelectedEntry() );
188 if( mpImplLB->GetEntryList()->HasImages() )
189 {
190 Image aImage = mpImplLB->GetEntryList()->GetEntryImage( GetSelectedEntryPos() );
191 mpImplWin->SetImage( aImage );
192 }
193 mpImplWin->Invalidate();
194 }
195
196 if ( ( !IsTravelSelect() || mpImplLB->IsSelectionChanged() ) || ( bPopup && !IsMultiSelectionEnabled() ) )
197 Select();
198 }
199
IMPL_LINK(ListBox,ImplFocusHdl,sal_Int32,nPos,void)200 IMPL_LINK( ListBox, ImplFocusHdl, sal_Int32, nPos, void )
201 {
202 CallEventListeners( VclEventId::ListboxFocus, reinterpret_cast<void*>(nPos) );
203 }
204
IMPL_LINK_NOARG(ListBox,ImplListItemSelectHdl,LinkParamNone *,void)205 IMPL_LINK_NOARG( ListBox, ImplListItemSelectHdl, LinkParamNone*, void )
206 {
207 CallEventListeners( VclEventId::DropdownSelect );
208 }
209
IMPL_LINK_NOARG(ListBox,ImplScrollHdl,ImplListBox *,void)210 IMPL_LINK_NOARG(ListBox, ImplScrollHdl, ImplListBox*, void)
211 {
212 CallEventListeners( VclEventId::ListboxScrolled );
213 }
214
IMPL_LINK_NOARG(ListBox,ImplCancelHdl,LinkParamNone *,void)215 IMPL_LINK_NOARG(ListBox, ImplCancelHdl, LinkParamNone*, void)
216 {
217 if( IsInDropDown() )
218 mpFloatWin->EndPopupMode();
219 }
220
IMPL_LINK(ListBox,ImplSelectionChangedHdl,sal_Int32,nChanged,void)221 IMPL_LINK( ListBox, ImplSelectionChangedHdl, sal_Int32, nChanged, void )
222 {
223 if ( !mpImplLB->IsTrackingSelect() )
224 {
225 const ImplEntryList* pEntryList = mpImplLB->GetEntryList();
226 if ( pEntryList->IsEntryPosSelected( nChanged ) )
227 {
228 // FIXME? This should've been turned into an ImplPaintEntry some time ago...
229 if ( nChanged < pEntryList->GetMRUCount() )
230 nChanged = pEntryList->FindEntry( pEntryList->GetEntryText( nChanged ) );
231 mpImplWin->SetItemPos( nChanged );
232 mpImplWin->SetString( mpImplLB->GetEntryList()->GetEntryText( nChanged ) );
233 if( mpImplLB->GetEntryList()->HasImages() )
234 {
235 Image aImage = mpImplLB->GetEntryList()->GetEntryImage( nChanged );
236 mpImplWin->SetImage( aImage );
237 }
238 }
239 else
240 {
241 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
242 mpImplWin->SetString( OUString() );
243 Image aImage;
244 mpImplWin->SetImage( aImage );
245 }
246 mpImplWin->Invalidate();
247 }
248 }
249
IMPL_LINK_NOARG(ListBox,ImplDoubleClickHdl,ImplListBoxWindow *,void)250 IMPL_LINK_NOARG(ListBox, ImplDoubleClickHdl, ImplListBoxWindow*, void)
251 {
252 DoubleClick();
253 }
254
IMPL_LINK_NOARG(ListBox,ImplClickBtnHdl,void *,void)255 IMPL_LINK_NOARG(ListBox, ImplClickBtnHdl, void*, void)
256 {
257 if( !mpFloatWin->IsInPopupMode() )
258 {
259 CallEventListeners( VclEventId::DropdownPreOpen );
260 mpImplWin->GrabFocus();
261 mpBtn->SetPressed( true );
262 mpFloatWin->StartFloat( true );
263 CallEventListeners( VclEventId::DropdownOpen );
264
265 ImplClearLayoutData();
266 if( mpImplLB )
267 mpImplLB->GetMainWindow()->ImplClearLayoutData();
268 if( mpImplWin )
269 mpImplWin->ImplClearLayoutData();
270 }
271 }
272
IMPL_LINK_NOARG(ListBox,ImplPopupModeEndHdl,FloatingWindow *,void)273 IMPL_LINK_NOARG(ListBox, ImplPopupModeEndHdl, FloatingWindow*, void)
274 {
275 if( mpFloatWin->IsPopupModeCanceled() )
276 {
277 if ( ( mpFloatWin->GetPopupModeStartSaveSelection() != LISTBOX_ENTRY_NOTFOUND )
278 && !IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
279 {
280 mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), true );
281 bool bTravelSelect = mpImplLB->IsTravelSelect();
282 mpImplLB->SetTravelSelect( true );
283
284 VclPtr<vcl::Window> xWindow = this;
285 Select();
286 if ( xWindow->IsDisposed() )
287 return;
288
289 mpImplLB->SetTravelSelect( bTravelSelect );
290 }
291 }
292
293 ImplClearLayoutData();
294 if( mpImplLB )
295 mpImplLB->GetMainWindow()->ImplClearLayoutData();
296 if( mpImplWin )
297 mpImplWin->ImplClearLayoutData();
298
299 mpBtn->SetPressed( false );
300 CallEventListeners( VclEventId::DropdownClose );
301 }
302
ToggleDropDown()303 void ListBox::ToggleDropDown()
304 {
305 if( IsDropDownBox() )
306 {
307 if( mpFloatWin->IsInPopupMode() )
308 mpFloatWin->EndPopupMode();
309 else
310 {
311 CallEventListeners( VclEventId::DropdownPreOpen );
312 mpImplWin->GrabFocus();
313 mpBtn->SetPressed( true );
314 mpFloatWin->StartFloat( true );
315 CallEventListeners( VclEventId::DropdownOpen );
316 }
317 }
318 }
319
ApplySettings(vcl::RenderContext & rRenderContext)320 void ListBox::ApplySettings(vcl::RenderContext& rRenderContext)
321 {
322 rRenderContext.SetBackground();
323 }
324
Draw(OutputDevice * pDev,const Point & rPos,const Size & rSize,DrawFlags nFlags)325 void ListBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags )
326 {
327 mpImplLB->GetMainWindow()->ApplySettings(*pDev);
328
329 Point aPos = pDev->LogicToPixel( rPos );
330 Size aSize = pDev->LogicToPixel( rSize );
331 vcl::Font aFont = mpImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
332 OutDevType eOutDevType = pDev->GetOutDevType();
333
334 pDev->Push();
335 pDev->SetMapMode();
336 pDev->SetFont( aFont );
337 pDev->SetTextFillColor();
338
339 // Border/Background
340 pDev->SetLineColor();
341 pDev->SetFillColor();
342 bool bBorder = (GetStyle() & WB_BORDER);
343 bool bBackground = IsControlBackground();
344 if ( bBorder || bBackground )
345 {
346 tools::Rectangle aRect( aPos, aSize );
347 if ( bBorder )
348 {
349 ImplDrawFrame( pDev, aRect );
350 }
351 if ( bBackground )
352 {
353 pDev->SetFillColor( GetControlBackground() );
354 pDev->DrawRect( aRect );
355 }
356 }
357
358 // Content
359 if ( ( nFlags & DrawFlags::Mono ) || ( eOutDevType == OUTDEV_PRINTER ) )
360 {
361 pDev->SetTextColor( COL_BLACK );
362 }
363 else
364 {
365 if ( !IsEnabled() )
366 {
367 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
368 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
369 }
370 else
371 {
372 pDev->SetTextColor( GetTextColor() );
373 }
374 }
375
376 const long nOnePixel = GetDrawPixel( pDev, 1 );
377 const long nOffX = 3*nOnePixel;
378 DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
379 tools::Rectangle aTextRect( aPos, aSize );
380
381 if ( GetStyle() & WB_CENTER )
382 nTextStyle |= DrawTextFlags::Center;
383 else if ( GetStyle() & WB_RIGHT )
384 nTextStyle |= DrawTextFlags::Right;
385 else
386 nTextStyle |= DrawTextFlags::Left;
387
388 aTextRect.AdjustLeft(nOffX );
389 aTextRect.AdjustRight( -nOffX );
390
391 if ( IsDropDownBox() )
392 {
393 OUString aText = GetSelectedEntry();
394 long nTextHeight = pDev->GetTextHeight();
395 long nTextWidth = pDev->GetTextWidth( aText );
396 long nOffY = (aSize.Height()-nTextHeight) / 2;
397
398 // Clipping?
399 if ( (nOffY < 0) ||
400 ((nOffY+nTextHeight) > aSize.Height()) ||
401 ((nOffX+nTextWidth) > aSize.Width()) )
402 {
403 tools::Rectangle aClip( aPos, aSize );
404 if ( nTextHeight > aSize.Height() )
405 aClip.AdjustBottom(nTextHeight-aSize.Height()+1 ); // So that HP Printers don't optimize this away
406 pDev->IntersectClipRegion( aClip );
407 }
408
409 pDev->DrawText( aTextRect, aText, nTextStyle );
410 }
411 else
412 {
413 long nTextHeight = pDev->GetTextHeight();
414 sal_uInt16 nLines = ( nTextHeight > 0 ) ? static_cast<sal_uInt16>(aSize.Height() / nTextHeight) : 1;
415 tools::Rectangle aClip( aPos, aSize );
416
417 pDev->IntersectClipRegion( aClip );
418
419 if ( !nLines )
420 nLines = 1;
421
422 for ( sal_uInt16 n = 0; n < nLines; n++ )
423 {
424 sal_Int32 nEntry = n+mpImplLB->GetTopEntry();
425 bool bSelected = mpImplLB->GetEntryList()->IsEntryPosSelected( nEntry );
426 if ( bSelected )
427 {
428 pDev->SetFillColor( COL_BLACK );
429 pDev->DrawRect( tools::Rectangle( Point( aPos.X(), aPos.Y() + n*nTextHeight ),
430 Point( aPos.X() + aSize.Width(), aPos.Y() + (n+1)*nTextHeight + 2*nOnePixel ) ) );
431 pDev->SetFillColor();
432 pDev->SetTextColor( COL_WHITE );
433 }
434
435 aTextRect.SetTop( aPos.Y() + n*nTextHeight );
436 aTextRect.SetBottom( aTextRect.Top() + nTextHeight );
437
438 pDev->DrawText( aTextRect, mpImplLB->GetEntryList()->GetEntryText( nEntry ), nTextStyle );
439
440 if ( bSelected )
441 pDev->SetTextColor( COL_BLACK );
442 }
443 }
444
445 pDev->Pop();
446 }
447
GetFocus()448 void ListBox::GetFocus()
449 {
450 if ( mpImplLB )
451 {
452 if( IsDropDownBox() )
453 mpImplWin->GrabFocus();
454 else
455 mpImplLB->GrabFocus();
456 }
457
458 Control::GetFocus();
459 }
460
LoseFocus()461 void ListBox::LoseFocus()
462 {
463 if( IsDropDownBox() )
464 {
465 if (mpImplWin)
466 mpImplWin->HideFocus();
467 }
468 else
469 {
470 if (mpImplLB)
471 mpImplLB->HideFocus();
472 }
473
474 Control::LoseFocus();
475 }
476
DataChanged(const DataChangedEvent & rDCEvt)477 void ListBox::DataChanged( const DataChangedEvent& rDCEvt )
478 {
479 Control::DataChanged( rDCEvt );
480
481 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
482 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
483 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
484 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
485 {
486 SetBackground(); // Due to a hack in Window::UpdateSettings the background must be reset
487 // otherwise it will overpaint NWF drawn listboxes
488 Resize();
489 mpImplLB->Resize(); // Is not called by ListBox::Resize() if the ImplLB does not change
490
491 if ( mpImplWin )
492 {
493 mpImplWin->SetSettings( GetSettings() ); // If not yet set...
494 mpImplWin->ApplySettings(*mpImplWin);
495
496 mpBtn->SetSettings( GetSettings() );
497 ImplInitDropDownButton( mpBtn );
498 }
499
500 if ( IsDropDownBox() )
501 Invalidate();
502 }
503 }
504
EnableAutoSize(bool bAuto)505 void ListBox::EnableAutoSize( bool bAuto )
506 {
507 mbDDAutoSize = bAuto;
508 if ( mpFloatWin )
509 {
510 if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
511 {
512 // use GetListBoxMaximumLineCount here; before, was on fixed number of five
513 AdaptDropDownLineCountToMaximum();
514 }
515 else if ( !bAuto )
516 {
517 mpFloatWin->SetDropDownLineCount( 0 );
518 }
519 }
520 }
521
SetDropDownLineCount(sal_uInt16 nLines)522 void ListBox::SetDropDownLineCount( sal_uInt16 nLines )
523 {
524 mnLineCount = nLines;
525 if ( mpFloatWin )
526 mpFloatWin->SetDropDownLineCount( mnLineCount );
527 }
528
AdaptDropDownLineCountToMaximum()529 void ListBox::AdaptDropDownLineCountToMaximum()
530 {
531 // Adapt to maximum allowed number.
532 // Limit for LOK as we can't render outside of the dialog canvas.
533 if (comphelper::LibreOfficeKit::isActive())
534 SetDropDownLineCount(11);
535 else
536 SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
537 }
538
GetDropDownLineCount() const539 sal_uInt16 ListBox::GetDropDownLineCount() const
540 {
541 if ( mpFloatWin )
542 return mpFloatWin->GetDropDownLineCount();
543 return mnLineCount;
544 }
545
setPosSizePixel(long nX,long nY,long nWidth,long nHeight,PosSizeFlags nFlags)546 void ListBox::setPosSizePixel( long nX, long nY, long nWidth, long nHeight, PosSizeFlags nFlags )
547 {
548 if( IsDropDownBox() && ( nFlags & PosSizeFlags::Size ) )
549 {
550 Size aPrefSz = mpFloatWin->GetPrefSize();
551 if ( ( nFlags & PosSizeFlags::Height ) && ( nHeight >= 2*mnDDHeight ) )
552 aPrefSz.setHeight( nHeight-mnDDHeight );
553 if ( nFlags & PosSizeFlags::Width )
554 aPrefSz.setWidth( nWidth );
555 mpFloatWin->SetPrefSize( aPrefSz );
556
557 if (IsAutoSizeEnabled())
558 nHeight = mnDDHeight;
559 }
560
561 Control::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
562 }
563
Resize()564 void ListBox::Resize()
565 {
566 Size aOutSz = GetOutputSizePixel();
567 if( IsDropDownBox() )
568 {
569 // Initialize the dropdown button size with the standard scrollbar width
570 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
571 long nBottom = aOutSz.Height();
572
573 // Note: in case of no border, pBorder will actually be this
574 vcl::Window *pBorder = GetWindow( GetWindowType::Border );
575 ImplControlValue aControlValue;
576 Point aPoint;
577 tools::Rectangle aContent, aBound;
578
579 // Use the full extent of the control
580 tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
581
582 if ( GetNativeControlRegion( ControlType::Listbox, ControlPart::ButtonDown,
583 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
584 {
585 // Convert back from border space to local coordinates
586 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
587 aContent.Move( -aPoint.X(), -aPoint.Y() );
588
589 // Use the themes drop down size for the button
590 aOutSz.setWidth( aContent.Left() );
591 mpBtn->setPosSizePixel( aContent.Left(), 0, aContent.GetWidth(), nBottom );
592
593 // Adjust the size of the edit field
594 if ( GetNativeControlRegion( ControlType::Listbox, ControlPart::SubEdit,
595 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
596 {
597 // Convert back from border space to local coordinates
598 aContent.Move( -aPoint.X(), -aPoint.Y() );
599
600 // Use the themes drop down size
601 if( ! (GetStyle() & WB_BORDER) && ImplGetSVData()->maNWFData.mbNoFocusRects )
602 {
603 // No border but focus ring behavior -> we have a problem; the
604 // native rect relies on the border to draw the focus
605 // let's do the best we can and center vertically, so it doesn't look
606 // completely wrong.
607 Size aSz( GetOutputSizePixel() );
608 long nDiff = aContent.Top() - (aSz.Height() - aContent.GetHeight())/2;
609 aContent.AdjustTop( -nDiff );
610 aContent.AdjustBottom( -nDiff );
611 }
612 mpImplWin->SetPosSizePixel( aContent.TopLeft(), aContent.GetSize() );
613 }
614 else
615 mpImplWin->SetSizePixel( aOutSz );
616 }
617 else
618 {
619 nSBWidth = CalcZoom( nSBWidth );
620 mpImplWin->setPosSizePixel( 0, 0, aOutSz.Width() - nSBWidth, aOutSz.Height() );
621 mpBtn->setPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
622 }
623 }
624 else
625 {
626 mpImplLB->SetSizePixel( aOutSz );
627 }
628
629 // Retain FloatingWindow size even when it's invisible, as we still process KEY_PGUP/DOWN ...
630 if ( mpFloatWin )
631 mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );
632
633 Control::Resize();
634 }
635
FillLayoutData() const636 void ListBox::FillLayoutData() const
637 {
638 mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
639 const ImplListBoxWindow* rMainWin = mpImplLB->GetMainWindow();
640 if( mpFloatWin )
641 {
642 // Dropdown mode
643 AppendLayoutData( *mpImplWin );
644 mpImplWin->SetLayoutDataParent( this );
645 if( mpFloatWin->IsReallyVisible() )
646 {
647 AppendLayoutData( *rMainWin );
648 rMainWin->SetLayoutDataParent( this );
649 }
650 }
651 else
652 {
653 AppendLayoutData( *rMainWin );
654 rMainWin->SetLayoutDataParent( this );
655 }
656 }
657
GetIndexForPoint(const Point & rPoint,sal_Int32 & rPos) const658 long ListBox::GetIndexForPoint( const Point& rPoint, sal_Int32& rPos ) const
659 {
660 if( !HasLayoutData() )
661 FillLayoutData();
662
663 // Check whether rPoint fits at all
664 long nIndex = Control::GetIndexForPoint( rPoint );
665 if( nIndex != -1 )
666 {
667 // Point must be either in main list window
668 // or in impl window (dropdown case)
669 ImplListBoxWindow* rMain = mpImplLB->GetMainWindow();
670
671 // Convert coordinates to ImplListBoxWindow pixel coordinate space
672 Point aConvPoint = LogicToPixel( rPoint );
673 aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
674 aConvPoint = rMain->AbsoluteScreenToOutputPixel( aConvPoint );
675 aConvPoint = rMain->PixelToLogic( aConvPoint );
676
677 // Try to find entry
678 sal_Int32 nEntry = rMain->GetEntryPosForPoint( aConvPoint );
679 if( nEntry == LISTBOX_ENTRY_NOTFOUND )
680 {
681 // Not found, maybe dropdown case
682 if( mpImplWin && mpImplWin->IsReallyVisible() )
683 {
684 // Convert to impl window pixel coordinates
685 aConvPoint = LogicToPixel( rPoint );
686 aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
687 aConvPoint = mpImplWin->AbsoluteScreenToOutputPixel( aConvPoint );
688
689 // Check whether converted point is inside impl window
690 Size aImplWinSize = mpImplWin->GetOutputSizePixel();
691 if( aConvPoint.X() >= 0 && aConvPoint.Y() >= 0 && aConvPoint.X() < aImplWinSize.Width() && aConvPoint.Y() < aImplWinSize.Height() )
692 {
693 // Inside the impl window, the position is the current item pos
694 rPos = mpImplWin->GetItemPos();
695 }
696 else
697 nIndex = -1;
698 }
699 else
700 nIndex = -1;
701 }
702 else
703 rPos = nEntry;
704
705 SAL_WARN_IF( nIndex == -1, "vcl", "found index for point, but relative index failed" );
706 }
707
708 // Get line relative index
709 if( nIndex != -1 )
710 nIndex = ToRelativeLineIndex( nIndex );
711
712 return nIndex;
713 }
714
StateChanged(StateChangedType nType)715 void ListBox::StateChanged( StateChangedType nType )
716 {
717 if( nType == StateChangedType::ReadOnly )
718 {
719 if( mpImplWin )
720 mpImplWin->Enable( !IsReadOnly() );
721 if( mpBtn )
722 mpBtn->Enable( !IsReadOnly() );
723 }
724 else if( nType == StateChangedType::Enable )
725 {
726 mpImplLB->Enable( IsEnabled() );
727 if( mpImplWin )
728 {
729 mpImplWin->Enable( IsEnabled() );
730 if ( IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
731 && ! IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown) )
732 {
733 GetWindow( GetWindowType::Border )->Invalidate( InvalidateFlags::NoErase );
734 }
735 else
736 mpImplWin->Invalidate();
737 }
738 if( mpBtn )
739 mpBtn->Enable( IsEnabled() );
740 }
741 else if( nType == StateChangedType::UpdateMode )
742 {
743 mpImplLB->SetUpdateMode( IsUpdateMode() );
744 }
745 else if ( nType == StateChangedType::Zoom )
746 {
747 mpImplLB->SetZoom( GetZoom() );
748 if ( mpImplWin )
749 {
750 mpImplWin->SetZoom( GetZoom() );
751 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
752 mpImplWin->Invalidate();
753 }
754 Resize();
755 }
756 else if ( nType == StateChangedType::ControlFont )
757 {
758 mpImplLB->SetControlFont( GetControlFont() );
759 if ( mpImplWin )
760 {
761 mpImplWin->SetControlFont( GetControlFont() );
762 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
763 mpImplWin->Invalidate();
764 }
765 Resize();
766 }
767 else if ( nType == StateChangedType::ControlForeground )
768 {
769 mpImplLB->SetControlForeground( GetControlForeground() );
770 if ( mpImplWin )
771 {
772 mpImplWin->SetControlForeground( GetControlForeground() );
773 mpImplWin->SetTextColor( GetControlForeground() );
774 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
775 mpImplWin->Invalidate();
776 }
777 }
778 else if ( nType == StateChangedType::ControlBackground )
779 {
780 mpImplLB->SetControlBackground( GetControlBackground() );
781 if ( mpImplWin )
782 {
783 if ( mpImplWin->IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire) )
784 {
785 // Transparent background
786 mpImplWin->SetBackground();
787 mpImplWin->SetControlBackground();
788 }
789 else
790 {
791 mpImplWin->SetBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
792 mpImplWin->SetControlBackground( mpImplLB->GetMainWindow()->GetControlBackground() );
793 }
794 mpImplWin->SetFont( mpImplLB->GetMainWindow()->GetFont() );
795 mpImplWin->Invalidate();
796 }
797 }
798 else if ( nType == StateChangedType::Style )
799 {
800 SetStyle( ImplInitStyle( GetStyle() ) );
801 mpImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) != 0 );
802 bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) != 0;
803 mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
804 }
805 else if( nType == StateChangedType::Mirroring )
806 {
807 if( mpBtn )
808 {
809 mpBtn->EnableRTL( IsRTLEnabled() );
810 ImplInitDropDownButton( mpBtn );
811 }
812 mpImplLB->EnableRTL( IsRTLEnabled() );
813 if( mpImplWin )
814 mpImplWin->EnableRTL( IsRTLEnabled() );
815 Resize();
816 }
817
818 Control::StateChanged( nType );
819 }
820
PreNotify(NotifyEvent & rNEvt)821 bool ListBox::PreNotify( NotifyEvent& rNEvt )
822 {
823 bool bDone = false;
824 if ( mpImplLB )
825 {
826 if( ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) && ( rNEvt.GetWindow() == mpImplWin ) )
827 {
828 KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
829 switch( aKeyEvt.GetKeyCode().GetCode() )
830 {
831 case KEY_DOWN:
832 {
833 if( mpFloatWin && !mpFloatWin->IsInPopupMode() &&
834 aKeyEvt.GetKeyCode().IsMod2() )
835 {
836 CallEventListeners( VclEventId::DropdownPreOpen );
837 mpBtn->SetPressed( true );
838 mpFloatWin->StartFloat( false );
839 CallEventListeners( VclEventId::DropdownOpen );
840 bDone = true;
841 }
842 else
843 {
844 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
845 }
846 }
847 break;
848 case KEY_UP:
849 {
850 if( mpFloatWin && mpFloatWin->IsInPopupMode() &&
851 aKeyEvt.GetKeyCode().IsMod2() )
852 {
853 mpFloatWin->EndPopupMode();
854 bDone = true;
855 }
856 else
857 {
858 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
859 }
860 }
861 break;
862 case KEY_RETURN:
863 {
864 if( IsInDropDown() )
865 {
866 mpImplLB->ProcessKeyInput( aKeyEvt );
867 bDone = true;
868 }
869 }
870 break;
871
872 default:
873 {
874 bDone = mpImplLB->ProcessKeyInput( aKeyEvt );
875 }
876 }
877 }
878 else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
879 {
880 if ( IsInDropDown() && !HasChildPathFocus( true ) )
881 mpFloatWin->EndPopupMode();
882 }
883 else if ( (rNEvt.GetType() == MouseNotifyEvent::COMMAND) &&
884 (rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel) &&
885 (rNEvt.GetWindow() == mpImplWin) )
886 {
887 MouseWheelBehaviour nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
888 if ( ( nWheelBehavior == MouseWheelBehaviour::ALWAYS )
889 || ( ( nWheelBehavior == MouseWheelBehaviour::FocusOnly )
890 && HasChildPathFocus()
891 )
892 )
893 {
894 bDone = mpImplLB->HandleWheelAsCursorTravel( *rNEvt.GetCommandEvent() );
895 }
896 else
897 {
898 bDone = false; // Don't consume this event, let the default handling take it (i.e. scroll the context)
899 }
900 }
901 }
902
903 return bDone || Control::PreNotify( rNEvt );
904 }
905
Select()906 void ListBox::Select()
907 {
908 ImplCallEventListenersAndHandler( VclEventId::ListboxSelect, [this] () { maSelectHdl.Call(*this); } );
909 }
910
DoubleClick()911 void ListBox::DoubleClick()
912 {
913 ImplCallEventListenersAndHandler( VclEventId::ListboxDoubleClick, [this] () { maDoubleClickHdl.Call(*this); } );
914 }
915
Clear()916 void ListBox::Clear()
917 {
918 if (!mpImplLB)
919 return;
920 mpImplLB->Clear();
921 if( IsDropDownBox() )
922 {
923 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
924 mpImplWin->SetString( OUString() );
925 Image aImage;
926 mpImplWin->SetImage( aImage );
927 mpImplWin->Invalidate();
928 }
929 CallEventListeners( VclEventId::ListboxItemRemoved, reinterpret_cast<void*>(-1) );
930 }
931
SetNoSelection()932 void ListBox::SetNoSelection()
933 {
934 mpImplLB->SetNoSelection();
935 if( IsDropDownBox() )
936 {
937 mpImplWin->SetItemPos( LISTBOX_ENTRY_NOTFOUND );
938 mpImplWin->SetString( OUString() );
939 Image aImage;
940 mpImplWin->SetImage( aImage );
941 mpImplWin->Invalidate();
942 }
943 }
944
InsertEntry(const OUString & rStr,sal_Int32 nPos)945 sal_Int32 ListBox::InsertEntry( const OUString& rStr, sal_Int32 nPos )
946 {
947 sal_Int32 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr );
948 nRealPos = sal::static_int_cast<sal_Int32>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
949 CallEventListeners( VclEventId::ListboxItemAdded, reinterpret_cast<void*>(nRealPos) );
950 return nRealPos;
951 }
952
InsertEntry(const OUString & rStr,const Image & rImage,sal_Int32 nPos)953 sal_Int32 ListBox::InsertEntry( const OUString& rStr, const Image& rImage, sal_Int32 nPos )
954 {
955 sal_Int32 nRealPos = mpImplLB->InsertEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), rStr, rImage );
956 nRealPos = sal::static_int_cast<sal_Int32>(nRealPos - mpImplLB->GetEntryList()->GetMRUCount());
957 CallEventListeners( VclEventId::ListboxItemAdded, reinterpret_cast<void*>(nRealPos) );
958 return nRealPos;
959 }
960
RemoveEntry(const OUString & rStr)961 void ListBox::RemoveEntry( const OUString& rStr )
962 {
963 RemoveEntry( GetEntryPos( rStr ) );
964 }
965
RemoveEntry(sal_Int32 nPos)966 void ListBox::RemoveEntry( sal_Int32 nPos )
967 {
968 mpImplLB->RemoveEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
969 CallEventListeners( VclEventId::ListboxItemRemoved, reinterpret_cast<void*>(nPos) );
970 }
971
GetEntryImage(sal_Int32 nPos) const972 Image ListBox::GetEntryImage( sal_Int32 nPos ) const
973 {
974 if ( mpImplLB && mpImplLB->GetEntryList()->HasEntryImage( nPos ) )
975 return mpImplLB->GetEntryList()->GetEntryImage( nPos );
976 return Image();
977 }
978
GetEntryPos(const OUString & rStr) const979 sal_Int32 ListBox::GetEntryPos( const OUString& rStr ) const
980 {
981 if (!mpImplLB)
982 return LISTBOX_ENTRY_NOTFOUND;
983 sal_Int32 nPos = mpImplLB->GetEntryList()->FindEntry( rStr );
984 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
985 nPos = nPos - mpImplLB->GetEntryList()->GetMRUCount();
986 return nPos;
987 }
988
GetEntryPos(const void * pData) const989 sal_Int32 ListBox::GetEntryPos( const void* pData ) const
990 {
991 if (!mpImplLB)
992 return LISTBOX_ENTRY_NOTFOUND;
993 sal_Int32 nPos = mpImplLB->GetEntryList()->FindEntry( pData );
994 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
995 nPos = nPos - mpImplLB->GetEntryList()->GetMRUCount();
996 return nPos;
997 }
998
GetEntry(sal_Int32 nPos) const999 OUString ListBox::GetEntry( sal_Int32 nPos ) const
1000 {
1001 if (!mpImplLB)
1002 return OUString();
1003 return mpImplLB->GetEntryList()->GetEntryText( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1004 }
1005
GetEntryCount() const1006 sal_Int32 ListBox::GetEntryCount() const
1007 {
1008 if (!mpImplLB)
1009 return 0;
1010 return mpImplLB->GetEntryList()->GetEntryCount() - mpImplLB->GetEntryList()->GetMRUCount();
1011 }
1012
GetSelectedEntry(sal_Int32 nIndex) const1013 OUString ListBox::GetSelectedEntry(sal_Int32 nIndex) const
1014 {
1015 return GetEntry( GetSelectedEntryPos( nIndex ) );
1016 }
1017
GetSelectedEntryCount() const1018 sal_Int32 ListBox::GetSelectedEntryCount() const
1019 {
1020 if (!mpImplLB)
1021 return 0;
1022 return mpImplLB->GetEntryList()->GetSelectedEntryCount();
1023 }
1024
GetSelectedEntryPos(sal_Int32 nIndex) const1025 sal_Int32 ListBox::GetSelectedEntryPos( sal_Int32 nIndex ) const
1026 {
1027 if (!mpImplLB || !mpImplLB->GetEntryList())
1028 return LISTBOX_ENTRY_NOTFOUND;
1029
1030 sal_Int32 nPos = mpImplLB->GetEntryList()->GetSelectedEntryPos( nIndex );
1031 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
1032 {
1033 if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
1034 nPos = mpImplLB->GetEntryList()->FindEntry( mpImplLB->GetEntryList()->GetEntryText( nPos ) );
1035 nPos = nPos - mpImplLB->GetEntryList()->GetMRUCount();
1036 }
1037 return nPos;
1038 }
1039
IsEntrySelected(const OUString & rStr) const1040 bool ListBox::IsEntrySelected(const OUString& rStr) const
1041 {
1042 return IsEntryPosSelected( GetEntryPos( rStr ) );
1043 }
1044
IsEntryPosSelected(sal_Int32 nPos) const1045 bool ListBox::IsEntryPosSelected( sal_Int32 nPos ) const
1046 {
1047 return mpImplLB->GetEntryList()->IsEntryPosSelected( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1048 }
1049
SelectEntry(const OUString & rStr,bool bSelect)1050 void ListBox::SelectEntry( const OUString& rStr, bool bSelect )
1051 {
1052 SelectEntryPos( GetEntryPos( rStr ), bSelect );
1053 }
1054
SelectEntryPos(sal_Int32 nPos,bool bSelect)1055 void ListBox::SelectEntryPos( sal_Int32 nPos, bool bSelect )
1056 {
1057 if (!mpImplLB)
1058 return;
1059
1060 if ( 0 <= nPos && nPos < mpImplLB->GetEntryList()->GetEntryCount() )
1061 {
1062 sal_Int32 nCurrentPos = mpImplLB->GetCurrentPos();
1063 mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), bSelect );
1064 //Only when bSelect == true, send both Selection & Focus events
1065 if (nCurrentPos != nPos && bSelect)
1066 {
1067 CallEventListeners( VclEventId::ListboxSelect, reinterpret_cast<void*>(nPos));
1068 if (HasFocus())
1069 CallEventListeners( VclEventId::ListboxFocus, reinterpret_cast<void*>(nPos));
1070 }
1071 }
1072 }
1073
SetEntryData(sal_Int32 nPos,void * pNewData)1074 void ListBox::SetEntryData( sal_Int32 nPos, void* pNewData )
1075 {
1076 mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount(), pNewData );
1077 }
1078
GetEntryData(sal_Int32 nPos) const1079 void* ListBox::GetEntryData( sal_Int32 nPos ) const
1080 {
1081 return mpImplLB->GetEntryList()->GetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1082 }
1083
SetEntryFlags(sal_Int32 nPos,ListBoxEntryFlags nFlags)1084 void ListBox::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
1085 {
1086 mpImplLB->SetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount(), nFlags );
1087 }
1088
GetEntryFlags(sal_Int32 nPos) const1089 ListBoxEntryFlags ListBox::GetEntryFlags( sal_Int32 nPos ) const
1090 {
1091 return mpImplLB->GetEntryList()->GetEntryFlags( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1092 }
1093
SetTopEntry(sal_Int32 nPos)1094 void ListBox::SetTopEntry( sal_Int32 nPos )
1095 {
1096 mpImplLB->SetTopEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1097 }
1098
GetTopEntry() const1099 sal_Int32 ListBox::GetTopEntry() const
1100 {
1101 sal_Int32 nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
1102 if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
1103 nPos = 0;
1104 return nPos;
1105 }
1106
IsTravelSelect() const1107 bool ListBox::IsTravelSelect() const
1108 {
1109 return mpImplLB->IsTravelSelect();
1110 }
1111
IsInDropDown() const1112 bool ListBox::IsInDropDown() const
1113 {
1114 // when the dropdown is dismissed, first mbInPopupMode is set to false, and on the next event iteration then
1115 // mbPopupMode is set to false
1116 return mpFloatWin && mpFloatWin->IsInPopupMode() && mpFloatWin->ImplIsInPrivatePopupMode();
1117 }
1118
GetBoundingRectangle(sal_Int32 nItem) const1119 tools::Rectangle ListBox::GetBoundingRectangle( sal_Int32 nItem ) const
1120 {
1121 tools::Rectangle aRect = mpImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
1122 tools::Rectangle aOffset = mpImplLB->GetMainWindow()->GetWindowExtentsRelative( static_cast<vcl::Window*>(const_cast<ListBox *>(this)) );
1123 aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
1124 return aRect;
1125 }
1126
EnableMultiSelection(bool bMulti)1127 void ListBox::EnableMultiSelection( bool bMulti )
1128 {
1129 EnableMultiSelection( bMulti, false );
1130 }
1131
EnableMultiSelection(bool bMulti,bool bStackSelection)1132 void ListBox::EnableMultiSelection( bool bMulti, bool bStackSelection )
1133 {
1134 mpImplLB->EnableMultiSelection( bMulti, bStackSelection );
1135
1136 // WB_SIMPLEMODE:
1137 // The MultiListBox behaves just like a normal ListBox
1138 // MultiSelection is possible via corresponding additional keys
1139 bool bSimpleMode = ( GetStyle() & WB_SIMPLEMODE ) != 0;
1140 mpImplLB->SetMultiSelectionSimpleMode( bSimpleMode );
1141
1142 // In a MultiSelection, we can't see us travelling without focus
1143 if ( mpFloatWin )
1144 mpImplLB->GetMainWindow()->AllowGrabFocus( bMulti );
1145 }
1146
IsMultiSelectionEnabled() const1147 bool ListBox::IsMultiSelectionEnabled() const
1148 {
1149 return mpImplLB->IsMultiSelectionEnabled();
1150 }
1151
CalcMinimumSize() const1152 Size ListBox::CalcMinimumSize() const
1153 {
1154 Size aSz;
1155
1156 if (!mpImplLB)
1157 return aSz;
1158
1159 aSz = CalcSubEditSize();
1160
1161 bool bAddScrollWidth = false;
1162
1163 if (IsDropDownBox())
1164 {
1165 aSz.AdjustHeight(4 ); // add a space between entry and border
1166 aSz.AdjustWidth(4 ); // add a little breathing space
1167 bAddScrollWidth = true;
1168 }
1169 else
1170 bAddScrollWidth = (GetStyle() & WB_VSCROLL) == WB_VSCROLL;
1171
1172 if (bAddScrollWidth)
1173 {
1174 // Try native borders; scrollbar size may not be a good indicator
1175 // See how large the edit area inside is to estimate what is needed for the dropdown
1176 ImplControlValue aControlValue;
1177 tools::Rectangle aContent, aBound;
1178 Size aTestSize( 100, 20 );
1179 tools::Rectangle aArea( Point(), aTestSize );
1180 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::SubEdit, aArea, ControlState::NONE,
1181 aControlValue, aBound, aContent) )
1182 {
1183 // use the themes drop down size
1184 aSz.AdjustWidth(aTestSize.Width() - aContent.GetWidth() );
1185 }
1186 else
1187 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1188 }
1189
1190 aSz = CalcWindowSize( aSz );
1191
1192 if (IsDropDownBox()) // Check minimum height of dropdown box
1193 {
1194 ImplControlValue aControlValue;
1195 tools::Rectangle aRect( Point( 0, 0 ), aSz );
1196 tools::Rectangle aContent, aBound;
1197 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire, aRect, ControlState::NONE,
1198 aControlValue, aBound, aContent) )
1199 {
1200 if( aBound.GetHeight() > aSz.Height() )
1201 aSz.setHeight( aBound.GetHeight() );
1202 }
1203 }
1204
1205 return aSz;
1206 }
1207
CalcSubEditSize() const1208 Size ListBox::CalcSubEditSize() const
1209 {
1210 Size aSz;
1211
1212 if (!mpImplLB)
1213 return aSz;
1214
1215 if ( !IsDropDownBox() )
1216 aSz = mpImplLB->CalcSize (mnLineCount ? mnLineCount : mpImplLB->GetEntryList()->GetEntryCount());
1217 else
1218 {
1219 aSz.setHeight( mpImplLB->GetEntryHeight() );
1220 // Size to maximum entry width
1221 aSz.setWidth( mpImplLB->GetMaxEntryWidth() );
1222
1223 if (m_nMaxWidthChars != -1)
1224 {
1225 long nMaxWidth = m_nMaxWidthChars * approximate_char_width();
1226 aSz.setWidth( std::min(aSz.Width(), nMaxWidth) );
1227 }
1228
1229 // Do not create ultrathin ListBoxes, it doesn't look good
1230 if( aSz.Width() < GetSettings().GetStyleSettings().GetScrollBarSize() )
1231 aSz.setWidth( GetSettings().GetStyleSettings().GetScrollBarSize() );
1232 }
1233
1234 return aSz;
1235 }
1236
GetOptimalSize() const1237 Size ListBox::GetOptimalSize() const
1238 {
1239 return CalcMinimumSize();
1240 }
1241
CalcAdjustedSize(const Size & rPrefSize) const1242 Size ListBox::CalcAdjustedSize( const Size& rPrefSize ) const
1243 {
1244 Size aSz = rPrefSize;
1245 sal_Int32 nLeft, nTop, nRight, nBottom;
1246 static_cast<vcl::Window*>(const_cast<ListBox *>(this))->GetBorder( nLeft, nTop, nRight, nBottom );
1247 aSz.AdjustHeight( -(nTop+nBottom) );
1248 if ( !IsDropDownBox() )
1249 {
1250 long nEntryHeight = CalcBlockSize( 1, 1 ).Height();
1251 long nLines = aSz.Height() / nEntryHeight;
1252 if ( nLines < 1 )
1253 nLines = 1;
1254 aSz.setHeight( nLines * nEntryHeight );
1255 }
1256 else
1257 {
1258 aSz.setHeight( mnDDHeight );
1259 }
1260 aSz.AdjustHeight(nTop+nBottom );
1261
1262 aSz = CalcWindowSize( aSz );
1263 return aSz;
1264 }
1265
CalcBlockSize(sal_uInt16 nColumns,sal_uInt16 nLines) const1266 Size ListBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
1267 {
1268 // ScrollBars are shown if needed
1269 Size aMinSz = CalcMinimumSize();
1270 // aMinSz = ImplCalcOutSz( aMinSz );
1271
1272 Size aSz;
1273
1274 // Height
1275 if ( nLines )
1276 {
1277 if ( !IsDropDownBox() )
1278 aSz.setHeight( mpImplLB->CalcSize( nLines ).Height() );
1279 else
1280 aSz.setHeight( mnDDHeight );
1281 }
1282 else
1283 aSz.setHeight( aMinSz.Height() );
1284
1285 // Width
1286 if ( nColumns )
1287 aSz.setWidth( nColumns * GetTextWidth( OUString('X') ) );
1288 else
1289 aSz.setWidth( aMinSz.Width() );
1290
1291 if ( IsDropDownBox() )
1292 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1293
1294 if ( !IsDropDownBox() )
1295 {
1296 if ( aSz.Width() < aMinSz.Width() )
1297 aSz.AdjustHeight(GetSettings().GetStyleSettings().GetScrollBarSize() );
1298 if ( aSz.Height() < aMinSz.Height() )
1299 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1300 }
1301
1302 aSz = CalcWindowSize( aSz );
1303 return aSz;
1304 }
1305
GetMaxVisColumnsAndLines(sal_uInt16 & rnCols,sal_uInt16 & rnLines) const1306 void ListBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
1307 {
1308 float nCharWidth = approximate_char_width();
1309 if ( !IsDropDownBox() )
1310 {
1311 Size aOutSz = mpImplLB->GetMainWindow()->GetOutputSizePixel();
1312 rnCols = static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth);
1313 rnLines = static_cast<sal_uInt16>(aOutSz.Height()/mpImplLB->GetEntryHeightWithMargin());
1314 }
1315 else
1316 {
1317 Size aOutSz = mpImplWin->GetOutputSizePixel();
1318 rnCols = static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth);
1319 rnLines = 1;
1320 }
1321 }
1322
IMPL_LINK(ListBox,ImplUserDrawHdl,UserDrawEvent *,pEvent,void)1323 IMPL_LINK( ListBox, ImplUserDrawHdl, UserDrawEvent*, pEvent, void )
1324 {
1325 UserDraw( *pEvent );
1326 }
1327
UserDraw(const UserDrawEvent &)1328 void ListBox::UserDraw( const UserDrawEvent& )
1329 {
1330 }
1331
DrawEntry(const UserDrawEvent & rEvt)1332 void ListBox::DrawEntry(const UserDrawEvent& rEvt)
1333 {
1334 if (rEvt.GetWindow() == mpImplLB->GetMainWindow())
1335 mpImplLB->GetMainWindow()->DrawEntry(*rEvt.GetRenderContext(), rEvt.GetItemId(), true/*bDrawImage*/, true/*bDrawText*/, false/*bDrawTextAtImagePos*/ );
1336 else if (rEvt.GetWindow() == mpImplWin)
1337 mpImplWin->DrawEntry(*rEvt.GetRenderContext(), false/*layout*/);
1338 }
1339
EnableUserDraw(bool bUserDraw)1340 void ListBox::EnableUserDraw( bool bUserDraw )
1341 {
1342 mpImplLB->GetMainWindow()->EnableUserDraw( bUserDraw );
1343 if ( mpImplWin )
1344 mpImplWin->EnableUserDraw( bUserDraw );
1345 }
1346
SetReadOnly(bool bReadOnly)1347 void ListBox::SetReadOnly( bool bReadOnly )
1348 {
1349 if ( mpImplLB->IsReadOnly() != bReadOnly )
1350 {
1351 mpImplLB->SetReadOnly( bReadOnly );
1352 CompatStateChanged( StateChangedType::ReadOnly );
1353 }
1354 }
1355
IsReadOnly() const1356 bool ListBox::IsReadOnly() const
1357 {
1358 return mpImplLB->IsReadOnly();
1359 }
1360
SetSeparatorPos(sal_Int32 n)1361 void ListBox::SetSeparatorPos( sal_Int32 n )
1362 {
1363 mpImplLB->SetSeparatorPos( n );
1364 }
1365
GetSeparatorPos() const1366 sal_Int32 ListBox::GetSeparatorPos() const
1367 {
1368 return mpImplLB->GetSeparatorPos();
1369 }
1370
AddSeparator(sal_Int32 n)1371 void ListBox::AddSeparator( sal_Int32 n )
1372 {
1373 mpImplLB->AddSeparator( n );
1374 }
1375
GetDisplayLineCount() const1376 sal_uInt16 ListBox::GetDisplayLineCount() const
1377 {
1378 return mpImplLB->GetDisplayLineCount();
1379 }
1380
EnableMirroring()1381 void ListBox::EnableMirroring()
1382 {
1383 mpImplLB->EnableMirroring();
1384 }
1385
GetDropDownPosSizePixel() const1386 tools::Rectangle ListBox::GetDropDownPosSizePixel() const
1387 {
1388 return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ListBox*>(this) ) : tools::Rectangle();
1389 }
1390
GetDisplayBackground() const1391 const Wallpaper& ListBox::GetDisplayBackground() const
1392 {
1393 // !!! Recursion does not occur because the ImplListBox is initialized by default
1394 // to a non-transparent color in Window::ImplInitData
1395 return mpImplLB->GetDisplayBackground();
1396 }
1397
setMaxWidthChars(sal_Int32 nWidth)1398 void ListBox::setMaxWidthChars(sal_Int32 nWidth)
1399 {
1400 if (nWidth != m_nMaxWidthChars)
1401 {
1402 m_nMaxWidthChars = nWidth;
1403 queue_resize();
1404 }
1405 }
1406
set_property(const OString & rKey,const OUString & rValue)1407 bool ListBox::set_property(const OString &rKey, const OUString &rValue)
1408 {
1409 if (rKey == "active")
1410 SelectEntryPos(rValue.toInt32());
1411 else if (rKey == "max-width-chars")
1412 setMaxWidthChars(rValue.toInt32());
1413 else if (rKey == "can-focus")
1414 {
1415 // as far as I can see in Gtk, setting a ComboBox as can.focus means
1416 // the focus gets stuck in it, so try here to behave like gtk does
1417 // with the settings that work, i.e. can.focus of false doesn't
1418 // set the hard WB_NOTABSTOP
1419 WinBits nBits = GetStyle();
1420 nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
1421 if (toBool(rValue))
1422 nBits |= WB_TABSTOP;
1423 SetStyle(nBits);
1424 }
1425 else
1426 return Control::set_property(rKey, rValue);
1427 return true;
1428 }
1429
GetUITestFactory() const1430 FactoryFunction ListBox::GetUITestFactory() const
1431 {
1432 return ListBoxUIObject::create;
1433 }
1434
DumpAsPropertyTree()1435 boost::property_tree::ptree ListBox::DumpAsPropertyTree()
1436 {
1437 boost::property_tree::ptree aTree(Control::DumpAsPropertyTree());
1438 boost::property_tree::ptree aEntries;
1439
1440 for (int i = 0; i < GetEntryCount(); ++i)
1441 {
1442 boost::property_tree::ptree aEntry;
1443 aEntry.put("", GetEntry(i));
1444 aEntries.push_back(std::make_pair("", aEntry));
1445 }
1446
1447 aTree.add_child("entries", aEntries);
1448
1449 boost::property_tree::ptree aSelected;
1450
1451 for (int i = 0; i < GetSelectedEntryCount(); ++i)
1452 {
1453 boost::property_tree::ptree aEntry;
1454 aEntry.put("", GetSelectedEntryPos(i));
1455 aSelected.push_back(std::make_pair("", aEntry));
1456 }
1457
1458 aTree.put("selectedCount", GetSelectedEntryCount());
1459 aTree.add_child("selectedEntries", aSelected);
1460
1461 return aTree;
1462 }
1463
MultiListBox(vcl::Window * pParent,WinBits nStyle)1464 MultiListBox::MultiListBox( vcl::Window* pParent, WinBits nStyle ) :
1465 ListBox( WindowType::MULTILISTBOX )
1466 {
1467 ImplInit( pParent, nStyle );
1468 EnableMultiSelection( true );
1469 }
1470
1471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1472