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 <set>
21 : #include <comphelper/string.hxx>
22 : #include <tools/debug.hxx>
23 : #include <tools/rc.h>
24 : #include <vcl/decoview.hxx>
25 : #include <vcl/lstbox.h>
26 : #include <vcl/button.hxx>
27 : #include <vcl/event.hxx>
28 : #include <vcl/combobox.hxx>
29 : #include <vcl/settings.hxx>
30 :
31 : #include <svdata.hxx>
32 : #include <ilstbox.hxx>
33 : #include <controldata.hxx>
34 :
35 0 : static void lcl_GetSelectedEntries( ::std::set< sal_Int32 >& rSelectedPos, const OUString& rText, sal_Unicode cTokenSep, const ImplEntryList* pEntryList )
36 : {
37 0 : for (sal_Int32 n = comphelper::string::getTokenCount(rText, cTokenSep); n;)
38 : {
39 0 : OUString aToken = rText.getToken( --n, cTokenSep );
40 0 : aToken = comphelper::string::strip(aToken, ' ');
41 0 : sal_Int32 nPos = pEntryList->FindEntry( aToken );
42 0 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
43 0 : rSelectedPos.insert( nPos );
44 0 : }
45 0 : }
46 :
47 4490 : ComboBox::ComboBox( vcl::Window* pParent, WinBits nStyle ) :
48 4490 : Edit( WINDOW_COMBOBOX )
49 : {
50 4490 : ImplInitComboBoxData();
51 4490 : ImplInit( pParent, nStyle );
52 4490 : SetWidthInChars(-1);
53 4490 : }
54 :
55 1216 : ComboBox::ComboBox( vcl::Window* pParent, const ResId& rResId ) :
56 1216 : Edit( WINDOW_COMBOBOX )
57 : {
58 1216 : ImplInitComboBoxData();
59 1216 : rResId.SetRT( RSC_COMBOBOX );
60 1216 : WinBits nStyle = ImplInitRes( rResId );
61 1216 : ImplInit( pParent, nStyle );
62 1216 : ImplLoadRes( rResId );
63 :
64 1216 : SetWidthInChars(-1);
65 1216 : if ( !(nStyle & WB_HIDE ) )
66 0 : Show();
67 1216 : }
68 :
69 11458 : ComboBox::~ComboBox()
70 : {
71 5706 : SetSubEdit( NULL );
72 5706 : delete mpSubEdit;
73 :
74 5706 : ImplListBox *pImplLB = mpImplLB;
75 5706 : mpImplLB = NULL;
76 5706 : delete pImplLB;
77 :
78 5706 : delete mpFloatWin;
79 5706 : delete mpBtn;
80 5752 : }
81 :
82 5706 : void ComboBox::ImplInitComboBoxData()
83 : {
84 5706 : mpSubEdit = NULL;
85 5706 : mpBtn = NULL;
86 5706 : mpImplLB = NULL;
87 5706 : mpFloatWin = NULL;
88 :
89 5706 : mnDDHeight = 0;
90 5706 : mbDDAutoSize = true;
91 5706 : mbSyntheticModify = false;
92 5706 : mbMatchCase = false;
93 5706 : mcMultiSep = ';';
94 5706 : m_nMaxWidthChars = -1;
95 5706 : }
96 :
97 6034 : void ComboBox::ImplCalcEditHeight()
98 : {
99 : sal_Int32 nLeft, nTop, nRight, nBottom;
100 6034 : GetBorder( nLeft, nTop, nRight, nBottom );
101 6034 : mnDDHeight = (sal_uInt16)(mpSubEdit->GetTextHeight() + nTop + nBottom + 4);
102 6034 : if ( !IsDropDownBox() )
103 112 : mnDDHeight += 4;
104 :
105 6034 : Rectangle aCtrlRegion( Point( 0, 0 ), Size( 10, 10 ) );
106 6034 : Rectangle aBoundRegion, aContentRegion;
107 6034 : ImplControlValue aControlValue;
108 6034 : ControlType aType = IsDropDownBox() ? CTRL_COMBOBOX : CTRL_EDITBOX;
109 12068 : if( GetNativeControlRegion( aType, PART_ENTIRE_CONTROL,
110 : aCtrlRegion,
111 : CTRL_STATE_ENABLED,
112 : aControlValue, OUString(),
113 12068 : aBoundRegion, aContentRegion ) )
114 : {
115 0 : const long nNCHeight = aBoundRegion.GetHeight();
116 0 : if( mnDDHeight < nNCHeight )
117 0 : mnDDHeight = sal::static_int_cast<sal_uInt16>( nNCHeight );
118 6034 : }
119 6034 : }
120 :
121 5706 : void ComboBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
122 : {
123 5706 : ImplInitStyle( nStyle );
124 :
125 5706 : bool bNoBorder = ( nStyle & WB_NOBORDER ) ? true : false;
126 5706 : if ( !(nStyle & WB_DROPDOWN) )
127 : {
128 28 : nStyle &= ~WB_BORDER;
129 28 : nStyle |= WB_NOBORDER;
130 : }
131 : else
132 : {
133 5678 : if ( !bNoBorder )
134 5678 : nStyle |= WB_BORDER;
135 : }
136 :
137 5706 : Edit::ImplInit( pParent, nStyle );
138 5706 : SetBackground();
139 :
140 : // DropDown ?
141 5706 : WinBits nEditStyle = nStyle & ( WB_LEFT | WB_RIGHT | WB_CENTER );
142 5706 : WinBits nListStyle = nStyle;
143 5706 : if( nStyle & WB_DROPDOWN )
144 : {
145 5678 : mpFloatWin = new ImplListBoxFloatingWindow( this );
146 5678 : mpFloatWin->SetAutoWidth( true );
147 5678 : mpFloatWin->SetPopupModeEndHdl( LINK( this, ComboBox, ImplPopupModeEndHdl ) );
148 :
149 5678 : mpBtn = new ImplBtn( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
150 5678 : ImplInitDropDownButton( mpBtn );
151 5678 : mpBtn->buttonDownSignal.connect( boost::bind( &ComboBox::ImplClickButtonHandler, this, _1 ));
152 5678 : mpBtn->Show();
153 :
154 5678 : nEditStyle |= WB_NOBORDER;
155 5678 : nListStyle &= ~WB_BORDER;
156 5678 : nListStyle |= WB_NOBORDER;
157 : }
158 : else
159 : {
160 28 : if ( !bNoBorder )
161 : {
162 28 : nEditStyle |= WB_BORDER;
163 28 : nListStyle &= ~WB_NOBORDER;
164 28 : nListStyle |= WB_BORDER;
165 : }
166 : }
167 :
168 5706 : mpSubEdit = new Edit( this, nEditStyle );
169 5706 : mpSubEdit->EnableRTL( false );
170 5706 : SetSubEdit( mpSubEdit );
171 5706 : mpSubEdit->SetPosPixel( Point() );
172 5706 : EnableAutocomplete( true );
173 5706 : mpSubEdit->Show();
174 :
175 5706 : vcl::Window* pLBParent = this;
176 5706 : if ( mpFloatWin )
177 5678 : pLBParent = mpFloatWin;
178 5706 : mpImplLB = new ImplListBox( pLBParent, nListStyle|WB_SIMPLEMODE|WB_AUTOHSCROLL );
179 5706 : mpImplLB->SetPosPixel( Point() );
180 5706 : mpImplLB->SetSelectHdl( LINK( this, ComboBox, ImplSelectHdl ) );
181 5706 : mpImplLB->SetCancelHdl( LINK( this, ComboBox, ImplCancelHdl ) );
182 5706 : mpImplLB->SetDoubleClickHdl( LINK( this, ComboBox, ImplDoubleClickHdl ) );
183 5706 : mpImplLB->userDrawSignal.connect( boost::bind( &ComboBox::ImplUserDrawHandler, this, _1 ) );
184 5706 : mpImplLB->SetSelectionChangedHdl( LINK( this, ComboBox, ImplSelectionChangedHdl ) );
185 5706 : mpImplLB->SetListItemSelectHdl( LINK( this, ComboBox, ImplListItemSelectHdl ) );
186 5706 : mpImplLB->Show();
187 :
188 5706 : if ( mpFloatWin )
189 5678 : mpFloatWin->SetImplListBox( mpImplLB );
190 : else
191 28 : mpImplLB->GetMainWindow().AllowGrabFocus( true );
192 :
193 5706 : ImplCalcEditHeight();
194 :
195 5706 : SetCompoundControl( true );
196 5706 : }
197 :
198 23646 : WinBits ComboBox::ImplInitStyle( WinBits nStyle )
199 : {
200 23646 : if ( !(nStyle & WB_NOTABSTOP) )
201 23646 : nStyle |= WB_TABSTOP;
202 23646 : if ( !(nStyle & WB_NOGROUP) )
203 23646 : nStyle |= WB_GROUP;
204 23646 : return nStyle;
205 : }
206 :
207 1216 : void ComboBox::ImplLoadRes( const ResId& rResId )
208 : {
209 1216 : Edit::ImplLoadRes( rResId );
210 :
211 1216 : sal_Int32 nNumber = ReadLongRes();
212 :
213 1216 : if( nNumber )
214 : {
215 0 : for( sal_Int32 i = 0; i < nNumber; i++ )
216 : {
217 0 : InsertEntry( ReadStringRes(), LISTBOX_APPEND );
218 : }
219 : }
220 1216 : }
221 :
222 8932 : void ComboBox::EnableAutocomplete( bool bEnable, bool bMatchCase )
223 : {
224 8932 : mbMatchCase = bMatchCase;
225 :
226 8932 : if ( bEnable )
227 : {
228 6960 : if( !mAutocompleteConnection.connected())
229 11424 : mAutocompleteConnection = mpSubEdit->autocompleteSignal.connect(
230 11424 : boost::bind( &ComboBox::ImplAutocompleteHandler, this, _1 ) );
231 : }
232 : else
233 1972 : mAutocompleteConnection.disconnect();
234 8932 : }
235 :
236 0 : bool ComboBox::IsAutocompleteEnabled() const
237 : {
238 0 : return mAutocompleteConnection.connected();
239 : }
240 :
241 0 : void ComboBox::ImplClickButtonHandler( ImplBtn* )
242 : {
243 0 : ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
244 0 : mpSubEdit->GrabFocus();
245 0 : if ( !mpImplLB->GetEntryList()->GetMRUCount() )
246 0 : ImplUpdateFloatSelection();
247 : else
248 0 : mpImplLB->SelectEntry( 0 , true );
249 0 : mpBtn->SetPressed( true );
250 0 : SetSelection( Selection( 0, SELECTION_MAX ) );
251 0 : mpFloatWin->StartFloat( true );
252 0 : ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
253 :
254 0 : ImplClearLayoutData();
255 0 : if( mpImplLB )
256 0 : mpImplLB->GetMainWindow().ImplClearLayoutData();
257 0 : }
258 :
259 4 : IMPL_LINK_NOARG(ComboBox, ImplPopupModeEndHdl)
260 : {
261 2 : if( mpFloatWin->IsPopupModeCanceled() )
262 : {
263 0 : if ( !mpImplLB->GetEntryList()->IsEntryPosSelected( mpFloatWin->GetPopupModeStartSaveSelection() ) )
264 : {
265 0 : mpImplLB->SelectEntry( mpFloatWin->GetPopupModeStartSaveSelection(), true );
266 0 : bool bTravelSelect = mpImplLB->IsTravelSelect();
267 0 : mpImplLB->SetTravelSelect( true );
268 0 : Select();
269 0 : mpImplLB->SetTravelSelect( bTravelSelect );
270 : }
271 : }
272 :
273 2 : ImplClearLayoutData();
274 2 : if( mpImplLB )
275 2 : mpImplLB->GetMainWindow().ImplClearLayoutData();
276 :
277 2 : mpBtn->SetPressed( false );
278 2 : ImplCallEventListeners( VCLEVENT_DROPDOWN_CLOSE );
279 2 : return 0;
280 : }
281 :
282 0 : void ComboBox::ImplAutocompleteHandler( Edit* pEdit )
283 : {
284 0 : Selection aSel = pEdit->GetSelection();
285 0 : AutocompleteAction eAction = pEdit->GetAutocompleteAction();
286 :
287 : /* If there is no current selection do not auto complete on
288 : Tab/Shift-Tab since then we would not cycle to the next field.
289 : */
290 0 : if ( aSel.Len() ||
291 0 : ((eAction != AUTOCOMPLETE_TABFORWARD) && (eAction != AUTOCOMPLETE_TABBACKWARD)) )
292 : {
293 0 : OUString aFullText = pEdit->GetText();
294 0 : OUString aStartText = aFullText.copy( 0, (sal_Int32)aSel.Max() );
295 0 : sal_Int32 nStart = mpImplLB->GetCurrentPos();
296 :
297 0 : if ( nStart == LISTBOX_ENTRY_NOTFOUND )
298 0 : nStart = 0;
299 :
300 0 : bool bForward = true;
301 0 : if ( eAction == AUTOCOMPLETE_TABFORWARD )
302 0 : nStart++;
303 0 : else if ( eAction == AUTOCOMPLETE_TABBACKWARD )
304 : {
305 0 : bForward = false;
306 0 : nStart = nStart ? nStart - 1 : mpImplLB->GetEntryList()->GetEntryCount()-1;
307 : }
308 :
309 0 : sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
310 0 : if( ! mbMatchCase )
311 : {
312 : // Try match case insensitive from current position
313 0 : nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, nStart, bForward, true );
314 0 : if ( nPos == LISTBOX_ENTRY_NOTFOUND )
315 : // Try match case insensitive, but from start
316 0 : nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, bForward ? 0 : (mpImplLB->GetEntryList()->GetEntryCount()-1), bForward, true );
317 : }
318 :
319 0 : if ( nPos == LISTBOX_ENTRY_NOTFOUND )
320 : // Try match full from current position
321 0 : nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, nStart, bForward, false );
322 0 : if ( nPos == LISTBOX_ENTRY_NOTFOUND )
323 : // Match full, but from start
324 0 : nPos = mpImplLB->GetEntryList()->FindMatchingEntry( aStartText, bForward ? 0 : (mpImplLB->GetEntryList()->GetEntryCount()-1), bForward, false );
325 :
326 0 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
327 : {
328 0 : OUString aText = mpImplLB->GetEntryList()->GetEntryText( nPos );
329 0 : Selection aSelection( aText.getLength(), aStartText.getLength() );
330 0 : pEdit->SetText( aText, aSelection );
331 0 : }
332 : }
333 0 : }
334 :
335 0 : IMPL_LINK_NOARG(ComboBox, ImplSelectHdl)
336 : {
337 0 : bool bPopup = IsInDropDown();
338 0 : bool bCallSelect = false;
339 0 : if ( mpImplLB->IsSelectionChanged() || bPopup )
340 : {
341 0 : OUString aText;
342 0 : if ( IsMultiSelectionEnabled() )
343 : {
344 0 : aText = mpSubEdit->GetText();
345 :
346 : // remove all entries to which there is an entry, but which is not selected
347 0 : sal_Int32 nIndex = 0;
348 0 : while ( nIndex >= 0 )
349 : {
350 0 : sal_Int32 nPrevIndex = nIndex;
351 0 : OUString aToken = aText.getToken( 0, mcMultiSep, nIndex );
352 0 : sal_Int32 nTokenLen = aToken.getLength();
353 0 : aToken = comphelper::string::strip(aToken, ' ');
354 0 : sal_Int32 nP = mpImplLB->GetEntryList()->FindEntry( aToken );
355 0 : if ( (nP != LISTBOX_ENTRY_NOTFOUND) && (!mpImplLB->GetEntryList()->IsEntryPosSelected( nP )) )
356 : {
357 0 : aText = aText.replaceAt( nPrevIndex, nTokenLen, "" );
358 0 : nIndex = nIndex - nTokenLen;
359 0 : sal_Int32 nSepCount=0;
360 0 : if ( (nPrevIndex+nSepCount < aText.getLength()) && (aText[nPrevIndex+nSepCount] == mcMultiSep) )
361 : {
362 0 : nIndex--;
363 0 : ++nSepCount;
364 : }
365 0 : aText = aText.replaceAt( nPrevIndex, nSepCount, "" );
366 : }
367 0 : aText = comphelper::string::strip(aText, ' ');
368 0 : }
369 :
370 : // attach missing entries
371 0 : ::std::set< sal_Int32 > aSelInText;
372 0 : lcl_GetSelectedEntries( aSelInText, aText, mcMultiSep, mpImplLB->GetEntryList() );
373 0 : sal_Int32 nSelectedEntries = mpImplLB->GetEntryList()->GetSelectEntryCount();
374 0 : for ( sal_Int32 n = 0; n < nSelectedEntries; n++ )
375 : {
376 0 : sal_Int32 nP = mpImplLB->GetEntryList()->GetSelectEntryPos( n );
377 0 : if ( !aSelInText.count( nP ) )
378 : {
379 0 : if ( !aText.isEmpty() && (aText[ aText.getLength()-1 ] != mcMultiSep) )
380 0 : aText += OUString(mcMultiSep);
381 0 : if ( !aText.isEmpty() )
382 0 : aText += " "; // slightly loosen
383 0 : aText += mpImplLB->GetEntryList()->GetEntryText( nP );
384 0 : aText += OUString(mcMultiSep);
385 : }
386 : }
387 0 : aText = comphelper::string::stripEnd( aText, mcMultiSep );
388 : }
389 : else
390 : {
391 0 : aText = mpImplLB->GetEntryList()->GetSelectEntry( 0 );
392 : }
393 :
394 0 : mpSubEdit->SetText( aText );
395 :
396 0 : Selection aNewSelection( 0, aText.getLength() );
397 0 : if ( IsMultiSelectionEnabled() )
398 0 : aNewSelection.Min() = aText.getLength();
399 0 : mpSubEdit->SetSelection( aNewSelection );
400 :
401 0 : bCallSelect = true;
402 : }
403 :
404 : // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, but after changing the text
405 :
406 0 : if ( bPopup && !mpImplLB->IsTravelSelect() &&
407 0 : ( !IsMultiSelectionEnabled() || !mpImplLB->GetSelectModifier() ) )
408 : {
409 0 : mpFloatWin->EndPopupMode();
410 0 : GrabFocus();
411 : }
412 :
413 0 : if ( bCallSelect )
414 : {
415 0 : mpSubEdit->SetModifyFlag();
416 0 : mbSyntheticModify = true;
417 0 : Modify();
418 0 : mbSyntheticModify = false;
419 0 : Select();
420 : }
421 :
422 0 : return 0;
423 : }
424 :
425 0 : IMPL_LINK( ComboBox, ImplListItemSelectHdl, void*, EMPTYARG )
426 : {
427 0 : ImplCallEventListeners( VCLEVENT_DROPDOWN_SELECT );
428 0 : return 1;
429 : }
430 :
431 0 : IMPL_LINK_NOARG(ComboBox, ImplCancelHdl)
432 : {
433 0 : if( IsInDropDown() )
434 0 : mpFloatWin->EndPopupMode();
435 :
436 0 : return 1;
437 : }
438 :
439 0 : IMPL_LINK( ComboBox, ImplSelectionChangedHdl, void*, n )
440 : {
441 0 : if ( !mpImplLB->IsTrackingSelect() )
442 : {
443 0 : sal_Int32 nChanged = (sal_Int32)reinterpret_cast<sal_uLong>(n);
444 0 : if ( !mpSubEdit->IsReadOnly() && mpImplLB->GetEntryList()->IsEntryPosSelected( nChanged ) )
445 0 : mpSubEdit->SetText( mpImplLB->GetEntryList()->GetEntryText( nChanged ) );
446 : }
447 0 : return 1;
448 : }
449 :
450 0 : IMPL_LINK_NOARG(ComboBox, ImplDoubleClickHdl)
451 : {
452 0 : DoubleClick();
453 0 : return 0;
454 : }
455 :
456 6 : void ComboBox::ToggleDropDown()
457 : {
458 6 : if( IsDropDownBox() )
459 : {
460 6 : if( mpFloatWin->IsInPopupMode() )
461 2 : mpFloatWin->EndPopupMode();
462 : else
463 : {
464 4 : mpSubEdit->GrabFocus();
465 4 : if ( !mpImplLB->GetEntryList()->GetMRUCount() )
466 4 : ImplUpdateFloatSelection();
467 : else
468 0 : mpImplLB->SelectEntry( 0 , true );
469 4 : ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
470 4 : mpBtn->SetPressed( true );
471 4 : SetSelection( Selection( 0, SELECTION_MAX ) );
472 4 : mpFloatWin->StartFloat( true );
473 4 : ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
474 : }
475 : }
476 6 : }
477 :
478 0 : void ComboBox::Select()
479 : {
480 0 : ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_SELECT, maSelectHdl, this );
481 0 : }
482 :
483 0 : void ComboBox::DoubleClick()
484 : {
485 0 : ImplCallEventListenersAndHandler( VCLEVENT_COMBOBOX_DOUBLECLICK, maDoubleClickHdl, this );
486 0 : }
487 :
488 46 : void ComboBox::EnableAutoSize( bool bAuto )
489 : {
490 46 : mbDDAutoSize = bAuto;
491 46 : if ( mpFloatWin )
492 : {
493 18 : if ( bAuto && !mpFloatWin->GetDropDownLineCount() )
494 : {
495 : // Adapt to GetListBoxMaximumLineCount here; was on fixed number of five before
496 0 : AdaptDropDownLineCountToMaximum();
497 : }
498 18 : else if ( !bAuto )
499 : {
500 18 : mpFloatWin->SetDropDownLineCount( 0 );
501 : }
502 : }
503 46 : }
504 :
505 0 : void ComboBox::EnableDDAutoWidth( bool b )
506 : {
507 0 : if ( mpFloatWin )
508 0 : mpFloatWin->SetAutoWidth( b );
509 0 : }
510 :
511 8984 : void ComboBox::SetDropDownLineCount( sal_uInt16 nLines )
512 : {
513 8984 : if ( mpFloatWin )
514 8950 : mpFloatWin->SetDropDownLineCount( nLines );
515 8984 : }
516 :
517 0 : void ComboBox::AdaptDropDownLineCountToMaximum()
518 : {
519 : // adapt to maximum allowed number
520 0 : SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
521 0 : }
522 :
523 0 : sal_uInt16 ComboBox::GetDropDownLineCount() const
524 : {
525 0 : sal_uInt16 nLines = 0;
526 0 : if ( mpFloatWin )
527 0 : nLines = mpFloatWin->GetDropDownLineCount();
528 0 : return nLines;
529 : }
530 :
531 26288 : void ComboBox::setPosSizePixel( long nX, long nY, long nWidth, long nHeight,
532 : sal_uInt16 nFlags )
533 : {
534 26288 : if( IsDropDownBox() && ( nFlags & WINDOW_POSSIZE_SIZE ) )
535 : {
536 17984 : Size aPrefSz = mpFloatWin->GetPrefSize();
537 17984 : if ( ( nFlags & WINDOW_POSSIZE_HEIGHT ) && ( nHeight >= 2*mnDDHeight ) )
538 5682 : aPrefSz.Height() = nHeight-mnDDHeight;
539 17984 : if ( nFlags & WINDOW_POSSIZE_WIDTH )
540 17984 : aPrefSz.Width() = nWidth;
541 17984 : mpFloatWin->SetPrefSize( aPrefSz );
542 :
543 17984 : if ( IsAutoSizeEnabled() && ! (nFlags & WINDOW_POSSIZE_DROPDOWN) )
544 16000 : nHeight = mnDDHeight;
545 : }
546 :
547 26288 : Edit::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
548 26288 : }
549 :
550 9714 : void ComboBox::Resize()
551 : {
552 9714 : Control::Resize();
553 :
554 9714 : Size aOutSz = GetOutputSizePixel();
555 9714 : if( IsDropDownBox() )
556 : {
557 : ComboBoxBounds aBounds(calcComboBoxDropDownComponentBounds(aOutSz,
558 9458 : GetWindow(WINDOW_BORDER)->GetOutputSizePixel()));
559 9458 : mpSubEdit->SetPosSizePixel(aBounds.aSubEditPos, aBounds.aSubEditSize);
560 9458 : mpBtn->SetPosSizePixel(aBounds.aButtonPos, aBounds.aButtonSize);
561 : }
562 : else
563 : {
564 256 : mpSubEdit->SetSizePixel( Size( aOutSz.Width(), mnDDHeight ) );
565 256 : mpImplLB->setPosSizePixel( 0, mnDDHeight, aOutSz.Width(), aOutSz.Height() - mnDDHeight );
566 256 : if ( !GetText().isEmpty() )
567 0 : ImplUpdateFloatSelection();
568 : }
569 :
570 : // adjust the size of the FloatingWindow even when invisible
571 : // as KEY_PGUP/DOWN is being processed...
572 9714 : if ( mpFloatWin )
573 9458 : mpFloatWin->SetSizePixel( mpFloatWin->CalcFloatSize() );
574 9714 : }
575 :
576 0 : void ComboBox::FillLayoutData() const
577 : {
578 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
579 0 : AppendLayoutData( *mpSubEdit );
580 0 : mpSubEdit->SetLayoutDataParent( this );
581 0 : Control& rMainWindow = mpImplLB->GetMainWindow();
582 0 : if( mpFloatWin )
583 : {
584 : // dropdown mode
585 0 : if( mpFloatWin->IsReallyVisible() )
586 : {
587 0 : AppendLayoutData( rMainWindow );
588 0 : rMainWindow.SetLayoutDataParent( this );
589 : }
590 : }
591 : else
592 : {
593 0 : AppendLayoutData( rMainWindow );
594 0 : rMainWindow.SetLayoutDataParent( this );
595 : }
596 0 : }
597 :
598 62980 : void ComboBox::StateChanged( StateChangedType nType )
599 : {
600 62980 : Edit::StateChanged( nType );
601 :
602 62980 : if ( nType == StateChangedType::READONLY )
603 : {
604 36 : mpImplLB->SetReadOnly( IsReadOnly() );
605 36 : if ( mpBtn )
606 12 : mpBtn->Enable( IsEnabled() && !IsReadOnly() );
607 : }
608 62944 : else if ( nType == StateChangedType::ENABLE )
609 : {
610 142 : mpSubEdit->Enable( IsEnabled() );
611 142 : mpImplLB->Enable( IsEnabled() && !IsReadOnly() );
612 142 : if ( mpBtn )
613 130 : mpBtn->Enable( IsEnabled() && !IsReadOnly() );
614 142 : Invalidate();
615 : }
616 62802 : else if( nType == StateChangedType::UPDATEMODE )
617 : {
618 33436 : mpImplLB->SetUpdateMode( IsUpdateMode() );
619 : }
620 29366 : else if ( nType == StateChangedType::ZOOM )
621 : {
622 2 : mpImplLB->SetZoom( GetZoom() );
623 2 : mpSubEdit->SetZoom( GetZoom() );
624 2 : ImplCalcEditHeight();
625 2 : Resize();
626 : }
627 29364 : else if ( nType == StateChangedType::CONTROLFONT )
628 : {
629 326 : mpImplLB->SetControlFont( GetControlFont() );
630 326 : mpSubEdit->SetControlFont( GetControlFont() );
631 326 : ImplCalcEditHeight();
632 326 : Resize();
633 : }
634 29038 : else if ( nType == StateChangedType::CONTROLFOREGROUND )
635 : {
636 4 : mpImplLB->SetControlForeground( GetControlForeground() );
637 4 : mpSubEdit->SetControlForeground( GetControlForeground() );
638 : }
639 29034 : else if ( nType == StateChangedType::CONTROLBACKGROUND )
640 : {
641 4 : mpImplLB->SetControlBackground( GetControlBackground() );
642 4 : mpSubEdit->SetControlBackground( GetControlBackground() );
643 : }
644 29030 : else if ( nType == StateChangedType::STYLE )
645 : {
646 17940 : SetStyle( ImplInitStyle( GetStyle() ) );
647 17940 : mpImplLB->GetMainWindow().EnableSort( ( GetStyle() & WB_SORT ) ? true : false );
648 : }
649 11090 : else if( nType == StateChangedType::MIRRORING )
650 : {
651 108 : if( mpBtn )
652 : {
653 44 : mpBtn->EnableRTL( IsRTLEnabled() );
654 44 : ImplInitDropDownButton( mpBtn );
655 : }
656 108 : mpSubEdit->StateChanged( StateChangedType::MIRRORING );
657 108 : mpImplLB->EnableRTL( IsRTLEnabled() );
658 108 : Resize();
659 : }
660 62980 : }
661 :
662 296 : void ComboBox::DataChanged( const DataChangedEvent& rDCEvt )
663 : {
664 296 : Control::DataChanged( rDCEvt );
665 :
666 888 : if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
667 844 : (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
668 592 : ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
669 296 : (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
670 : {
671 252 : if ( mpBtn )
672 : {
673 170 : mpBtn->SetSettings( GetSettings() );
674 170 : ImplInitDropDownButton( mpBtn );
675 : }
676 252 : Resize();
677 252 : mpImplLB->Resize(); // not called by ComboBox::Resize() if ImplLB is unchanged
678 :
679 252 : SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
680 : // otherwise it will overpaint NWF drawn comboboxes
681 : }
682 296 : }
683 :
684 6 : bool ComboBox::PreNotify( NotifyEvent& rNEvt )
685 : {
686 :
687 6 : return Edit::PreNotify( rNEvt );
688 : }
689 :
690 12062 : bool ComboBox::Notify( NotifyEvent& rNEvt )
691 : {
692 12062 : bool nDone = false;
693 24124 : if( ( rNEvt.GetType() == EVENT_KEYINPUT ) && ( rNEvt.GetWindow() == mpSubEdit )
694 12062 : && !IsReadOnly() )
695 : {
696 0 : KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
697 0 : sal_uInt16 nKeyCode = aKeyEvt.GetKeyCode().GetCode();
698 0 : switch( nKeyCode )
699 : {
700 : case KEY_UP:
701 : case KEY_DOWN:
702 : case KEY_PAGEUP:
703 : case KEY_PAGEDOWN:
704 : {
705 0 : ImplUpdateFloatSelection();
706 0 : if( ( nKeyCode == KEY_DOWN ) && mpFloatWin && !mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() )
707 : {
708 0 : ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN );
709 0 : mpBtn->SetPressed( true );
710 0 : if ( mpImplLB->GetEntryList()->GetMRUCount() )
711 0 : mpImplLB->SelectEntry( 0 , true );
712 0 : SetSelection( Selection( 0, SELECTION_MAX ) );
713 0 : mpFloatWin->StartFloat( false );
714 0 : ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN );
715 0 : nDone = true;
716 : }
717 0 : else if( ( nKeyCode == KEY_UP ) && mpFloatWin && mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() )
718 : {
719 0 : mpFloatWin->EndPopupMode();
720 0 : nDone = true;
721 : }
722 : else
723 : {
724 0 : nDone = mpImplLB->ProcessKeyInput( aKeyEvt );
725 : }
726 : }
727 0 : break;
728 :
729 : case KEY_RETURN:
730 : {
731 0 : if( ( rNEvt.GetWindow() == mpSubEdit ) && IsInDropDown() )
732 : {
733 0 : mpImplLB->ProcessKeyInput( aKeyEvt );
734 0 : nDone = true;
735 : }
736 : }
737 0 : break;
738 : }
739 : }
740 12062 : else if ( (rNEvt.GetType() == EVENT_LOSEFOCUS) && mpFloatWin )
741 : {
742 2 : if( mpFloatWin->HasChildPathFocus() )
743 0 : mpSubEdit->GrabFocus();
744 2 : else if ( mpFloatWin->IsInPopupMode() && !HasChildPathFocus( true ) )
745 0 : mpFloatWin->EndPopupMode();
746 : }
747 24120 : else if( (rNEvt.GetType() == EVENT_COMMAND) &&
748 12060 : (rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL) &&
749 0 : (rNEvt.GetWindow() == mpSubEdit) )
750 : {
751 0 : sal_uInt16 nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
752 0 : if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
753 0 : || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
754 0 : && HasChildPathFocus()
755 : )
756 : )
757 : {
758 0 : nDone = mpImplLB->HandleWheelAsCursorTravel( *rNEvt.GetCommandEvent() );
759 : }
760 : else
761 : {
762 0 : nDone = false; // don't eat this event, let the default handling happen (i.e. scroll the context)
763 : }
764 : }
765 12060 : else if( ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) && ( rNEvt.GetWindow() == &mpImplLB->GetMainWindow() ) )
766 : {
767 0 : mpSubEdit->GrabFocus();
768 : }
769 :
770 12062 : return nDone || Edit::Notify( rNEvt );
771 : }
772 :
773 10870 : void ComboBox::SetText( const OUString& rStr )
774 : {
775 10870 : ImplCallEventListeners( VCLEVENT_COMBOBOX_SETTEXT );
776 :
777 10870 : Edit::SetText( rStr );
778 10870 : ImplUpdateFloatSelection();
779 10870 : }
780 :
781 17376 : void ComboBox::SetText( const OUString& rStr, const Selection& rNewSelection )
782 : {
783 17376 : ImplCallEventListeners( VCLEVENT_COMBOBOX_SETTEXT );
784 :
785 17376 : Edit::SetText( rStr, rNewSelection );
786 17376 : ImplUpdateFloatSelection();
787 17376 : }
788 :
789 112 : void ComboBox::Modify()
790 : {
791 112 : if ( !mbSyntheticModify )
792 112 : ImplUpdateFloatSelection();
793 :
794 112 : Edit::Modify();
795 112 : }
796 :
797 28362 : void ComboBox::ImplUpdateFloatSelection()
798 : {
799 : // move text in the ListBox into the visible region
800 28362 : mpImplLB->SetCallSelectionChangedHdl( false );
801 28362 : if ( !IsMultiSelectionEnabled() )
802 : {
803 28362 : OUString aSearchStr( mpSubEdit->GetText() );
804 28362 : sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND;
805 28362 : bool bSelect = true;
806 :
807 28362 : if ( mpImplLB->GetCurrentPos() != LISTBOX_ENTRY_NOTFOUND )
808 : {
809 3748 : OUString aCurrent = mpImplLB->GetEntryList()->GetEntryText( mpImplLB->GetCurrentPos() );
810 3748 : if ( aCurrent == aSearchStr )
811 3738 : nSelect = mpImplLB->GetCurrentPos();
812 : }
813 :
814 28362 : if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
815 24624 : nSelect = mpImplLB->GetEntryList()->FindEntry( aSearchStr );
816 28362 : if ( nSelect == LISTBOX_ENTRY_NOTFOUND )
817 : {
818 20408 : nSelect = mpImplLB->GetEntryList()->FindMatchingEntry( aSearchStr );
819 20408 : bSelect = false;
820 : }
821 :
822 28362 : if( nSelect != LISTBOX_ENTRY_NOTFOUND )
823 : {
824 11904 : if ( !mpImplLB->IsVisible( nSelect ) )
825 9602 : mpImplLB->ShowProminentEntry( nSelect );
826 11904 : mpImplLB->SelectEntry( nSelect, bSelect );
827 : }
828 : else
829 : {
830 16458 : nSelect = mpImplLB->GetEntryList()->GetSelectEntryPos( 0 );
831 16458 : if( nSelect != LISTBOX_ENTRY_NOTFOUND )
832 8 : mpImplLB->SelectEntry( nSelect, false );
833 16458 : mpImplLB->ResetCurrentPos();
834 28362 : }
835 : }
836 : else
837 : {
838 0 : ::std::set< sal_Int32 > aSelInText;
839 0 : lcl_GetSelectedEntries( aSelInText, mpSubEdit->GetText(), mcMultiSep, mpImplLB->GetEntryList() );
840 0 : for ( sal_Int32 n = 0; n < mpImplLB->GetEntryList()->GetEntryCount(); n++ )
841 0 : mpImplLB->SelectEntry( n, aSelInText.count( n ) );
842 : }
843 28362 : mpImplLB->SetCallSelectionChangedHdl( true );
844 28362 : }
845 :
846 233366 : sal_Int32 ComboBox::InsertEntry(const OUString& rStr, sal_Int32 const nPos)
847 : {
848 233366 : if (nPos < 0 || COMBOBOX_MAX_ENTRIES <= mpImplLB->GetEntryList()->GetEntryCount())
849 0 : return COMBOBOX_ERROR;
850 :
851 : sal_Int32 nRealPos;
852 233366 : if (nPos == COMBOBOX_APPEND)
853 103758 : nRealPos = nPos;
854 : else
855 : {
856 129608 : const sal_Int32 nMRUCount = mpImplLB->GetEntryList()->GetMRUCount();
857 129608 : if (nPos > COMBOBOX_MAX_ENTRIES - nMRUCount)
858 0 : return COMBOBOX_ERROR;
859 129608 : nRealPos = nPos + nMRUCount;
860 : }
861 :
862 233366 : nRealPos = mpImplLB->InsertEntry( nRealPos, rStr );
863 233366 : nRealPos -= mpImplLB->GetEntryList()->GetMRUCount();
864 233366 : CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED, reinterpret_cast<void*>(nRealPos) );
865 233366 : return nRealPos;
866 : }
867 :
868 118 : sal_Int32 ComboBox::InsertEntryWithImage(
869 : const OUString& rStr, const Image& rImage, sal_Int32 const nPos)
870 : {
871 118 : if (nPos < 0 || COMBOBOX_MAX_ENTRIES <= mpImplLB->GetEntryList()->GetEntryCount())
872 0 : return COMBOBOX_ERROR;
873 :
874 : sal_Int32 nRealPos;
875 118 : if (nPos == COMBOBOX_APPEND)
876 118 : nRealPos = nPos;
877 : else
878 : {
879 0 : const sal_Int32 nMRUCount = mpImplLB->GetEntryList()->GetMRUCount();
880 0 : if (nPos > COMBOBOX_MAX_ENTRIES - nMRUCount)
881 0 : return COMBOBOX_ERROR;
882 0 : nRealPos = nPos + nMRUCount;
883 : }
884 :
885 118 : nRealPos = mpImplLB->InsertEntry( nRealPos, rStr, rImage );
886 118 : nRealPos -= mpImplLB->GetEntryList()->GetMRUCount();
887 118 : CallEventListeners( VCLEVENT_COMBOBOX_ITEMADDED, reinterpret_cast<void*>(nRealPos) );
888 118 : return nRealPos;
889 : }
890 :
891 0 : void ComboBox::RemoveEntry( const OUString& rStr )
892 : {
893 0 : RemoveEntryAt(GetEntryPos(rStr));
894 0 : }
895 :
896 0 : void ComboBox::RemoveEntryAt(sal_Int32 const nPos)
897 : {
898 0 : const sal_Int32 nMRUCount = mpImplLB->GetEntryList()->GetMRUCount();
899 0 : if (nPos < 0 || nPos > COMBOBOX_MAX_ENTRIES - nMRUCount)
900 0 : return;
901 :
902 0 : mpImplLB->RemoveEntry( nPos + nMRUCount );
903 0 : CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED, reinterpret_cast<void*>(nPos) );
904 : }
905 :
906 16336 : void ComboBox::Clear()
907 : {
908 16336 : mpImplLB->Clear();
909 16336 : CallEventListeners( VCLEVENT_COMBOBOX_ITEMREMOVED, reinterpret_cast<void*>(-1) );
910 16336 : }
911 :
912 0 : Image ComboBox::GetEntryImage( sal_Int32 nPos ) const
913 : {
914 0 : if ( mpImplLB->GetEntryList()->HasEntryImage( nPos ) )
915 0 : return mpImplLB->GetEntryList()->GetEntryImage( nPos );
916 0 : return Image();
917 : }
918 :
919 0 : sal_Int32 ComboBox::GetEntryPos( const OUString& rStr ) const
920 : {
921 0 : sal_Int32 nPos = mpImplLB->GetEntryList()->FindEntry( rStr );
922 0 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
923 0 : nPos -= mpImplLB->GetEntryList()->GetMRUCount();
924 0 : return nPos;
925 : }
926 :
927 0 : sal_Int32 ComboBox::GetEntryPos( const void* pData ) const
928 : {
929 0 : sal_Int32 nPos = mpImplLB->GetEntryList()->FindEntry( pData );
930 0 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
931 0 : nPos = nPos - mpImplLB->GetEntryList()->GetMRUCount();
932 0 : return nPos;
933 : }
934 :
935 2921 : OUString ComboBox::GetEntry( sal_Int32 nPos ) const
936 : {
937 2921 : const sal_Int32 nMRUCount = mpImplLB->GetEntryList()->GetMRUCount();
938 2921 : if (nPos < 0 || nPos > COMBOBOX_MAX_ENTRIES - nMRUCount)
939 0 : return OUString();
940 :
941 2921 : return mpImplLB->GetEntryList()->GetEntryText( nPos + nMRUCount );
942 : }
943 :
944 29302 : sal_Int32 ComboBox::GetEntryCount() const
945 : {
946 29302 : return mpImplLB->GetEntryList()->GetEntryCount() - mpImplLB->GetEntryList()->GetMRUCount();
947 : }
948 :
949 0 : bool ComboBox::IsTravelSelect() const
950 : {
951 0 : return mpImplLB->IsTravelSelect();
952 : }
953 :
954 30 : bool ComboBox::IsInDropDown() const
955 : {
956 30 : return mpFloatWin && mpFloatWin->IsInPopupMode();
957 : }
958 :
959 0 : void ComboBox::EnableMultiSelection( bool bMulti )
960 : {
961 0 : mpImplLB->EnableMultiSelection( bMulti, false );
962 0 : mpImplLB->SetMultiSelectionSimpleMode( true );
963 0 : }
964 :
965 28388 : bool ComboBox::IsMultiSelectionEnabled() const
966 : {
967 28388 : return mpImplLB->IsMultiSelectionEnabled();
968 : }
969 :
970 542 : long ComboBox::CalcWindowSizePixel( sal_uInt16 nLines ) const
971 : {
972 542 : return mpImplLB->GetEntryHeight() * nLines;
973 : }
974 :
975 1948 : Size ComboBox::GetOptimalSize() const
976 : {
977 1948 : return CalcMinimumSize();
978 : }
979 :
980 1948 : long ComboBox::getMaxWidthScrollBarAndDownButton() const
981 : {
982 1948 : long nButtonDownWidth = 0;
983 :
984 1948 : vcl::Window *pBorder = GetWindow( WINDOW_BORDER );
985 1948 : ImplControlValue aControlValue;
986 1948 : Point aPoint;
987 1948 : Rectangle aContent, aBound;
988 :
989 : // use the full extent of the control
990 1948 : Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
991 :
992 3896 : if ( GetNativeControlRegion(CTRL_COMBOBOX, PART_BUTTON_DOWN,
993 3896 : aArea, 0, aControlValue, OUString(), aBound, aContent) )
994 : {
995 0 : nButtonDownWidth = aContent.getWidth();
996 : }
997 :
998 1948 : long nScrollBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
999 :
1000 1948 : return std::max(nScrollBarWidth, nButtonDownWidth);
1001 : }
1002 :
1003 1964 : Size ComboBox::CalcMinimumSize() const
1004 : {
1005 1964 : Size aSz;
1006 :
1007 1964 : if (!mpImplLB)
1008 0 : return aSz;
1009 :
1010 1964 : if (!IsDropDownBox())
1011 : {
1012 16 : aSz = mpImplLB->CalcSize( mpImplLB->GetEntryList()->GetEntryCount() );
1013 16 : aSz.Height() += mnDDHeight;
1014 : }
1015 : else
1016 : {
1017 1948 : aSz.Height() = Edit::CalcMinimumSizeForText(GetText()).Height();
1018 1948 : aSz.Width() = mpImplLB->GetMaxEntryWidth();
1019 : }
1020 :
1021 1964 : if (m_nMaxWidthChars != -1)
1022 : {
1023 0 : long nMaxWidth = m_nMaxWidthChars * approximate_char_width();
1024 0 : aSz.Width() = std::min(aSz.Width(), nMaxWidth);
1025 : }
1026 :
1027 1964 : if (IsDropDownBox())
1028 1948 : aSz.Width() += getMaxWidthScrollBarAndDownButton();
1029 :
1030 : ComboBoxBounds aBounds(calcComboBoxDropDownComponentBounds(
1031 1964 : Size(0xFFFF, 0xFFFF), Size(0xFFFF, 0xFFFF)));
1032 1964 : aSz.Width() += aBounds.aSubEditPos.X()*2;
1033 :
1034 1964 : aSz.Width() += ImplGetExtraOffset() * 2;
1035 :
1036 1964 : aSz = CalcWindowSize( aSz );
1037 1964 : return aSz;
1038 : }
1039 :
1040 4 : Size ComboBox::CalcAdjustedSize( const Size& rPrefSize ) const
1041 : {
1042 4 : Size aSz = rPrefSize;
1043 : sal_Int32 nLeft, nTop, nRight, nBottom;
1044 4 : ((vcl::Window*)this)->GetBorder( nLeft, nTop, nRight, nBottom );
1045 4 : aSz.Height() -= nTop+nBottom;
1046 4 : if ( !IsDropDownBox() )
1047 : {
1048 4 : long nEntryHeight = CalcBlockSize( 1, 1 ).Height();
1049 4 : long nLines = aSz.Height() / nEntryHeight;
1050 4 : if ( nLines < 1 )
1051 0 : nLines = 1;
1052 4 : aSz.Height() = nLines * nEntryHeight;
1053 4 : aSz.Height() += mnDDHeight;
1054 : }
1055 : else
1056 : {
1057 0 : aSz.Height() = mnDDHeight;
1058 : }
1059 4 : aSz.Height() += nTop+nBottom;
1060 :
1061 4 : aSz = CalcWindowSize( aSz );
1062 4 : return aSz;
1063 : }
1064 :
1065 8 : Size ComboBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
1066 : {
1067 : // show ScrollBars where appropriate
1068 8 : Size aMinSz = CalcMinimumSize();
1069 8 : Size aSz;
1070 :
1071 : // height
1072 8 : if ( nLines )
1073 : {
1074 4 : if ( !IsDropDownBox() )
1075 4 : aSz.Height() = mpImplLB->CalcSize( nLines ).Height() + mnDDHeight;
1076 : else
1077 0 : aSz.Height() = mnDDHeight;
1078 : }
1079 : else
1080 4 : aSz.Height() = aMinSz.Height();
1081 :
1082 : // width
1083 8 : if ( nColumns )
1084 4 : aSz.Width() = nColumns * approximate_char_width();
1085 : else
1086 4 : aSz.Width() = aMinSz.Width();
1087 :
1088 8 : if ( IsDropDownBox() )
1089 0 : aSz.Width() += getMaxWidthScrollBarAndDownButton();
1090 :
1091 8 : if ( !IsDropDownBox() )
1092 : {
1093 8 : if ( aSz.Width() < aMinSz.Width() )
1094 0 : aSz.Height() += GetSettings().GetStyleSettings().GetScrollBarSize();
1095 8 : if ( aSz.Height() < aMinSz.Height() )
1096 0 : aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1097 : }
1098 :
1099 8 : aSz.Width() += ImplGetExtraOffset() * 2;
1100 :
1101 8 : aSz = CalcWindowSize( aSz );
1102 8 : return aSz;
1103 : }
1104 :
1105 4 : void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
1106 : {
1107 4 : long nCharWidth = GetTextWidth(OUString(static_cast<sal_Unicode>('x')));
1108 4 : if ( !IsDropDownBox() )
1109 : {
1110 4 : Size aOutSz = mpImplLB->GetMainWindow().GetOutputSizePixel();
1111 4 : rnCols = (nCharWidth > 0) ? (sal_uInt16)(aOutSz.Width()/nCharWidth) : 1;
1112 4 : rnLines = (sal_uInt16)(aOutSz.Height()/mpImplLB->GetEntryHeight());
1113 : }
1114 : else
1115 : {
1116 0 : Size aOutSz = mpSubEdit->GetOutputSizePixel();
1117 0 : rnCols = (nCharWidth > 0) ? (sal_uInt16)(aOutSz.Width()/nCharWidth) : 1;
1118 0 : rnLines = 1;
1119 : }
1120 4 : }
1121 :
1122 0 : void ComboBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
1123 : {
1124 0 : mpImplLB->GetMainWindow().ImplInitSettings( true, true, true );
1125 :
1126 0 : Point aPos = pDev->LogicToPixel( rPos );
1127 0 : Size aSize = pDev->LogicToPixel( rSize );
1128 0 : vcl::Font aFont = mpImplLB->GetMainWindow().GetDrawPixelFont( pDev );
1129 0 : OutDevType eOutDevType = pDev->GetOutDevType();
1130 :
1131 0 : pDev->Push();
1132 0 : pDev->SetMapMode();
1133 0 : pDev->SetFont( aFont );
1134 0 : pDev->SetTextFillColor();
1135 :
1136 : // Border/Background
1137 0 : pDev->SetLineColor();
1138 0 : pDev->SetFillColor();
1139 0 : bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
1140 0 : bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
1141 0 : if ( bBorder || bBackground )
1142 : {
1143 0 : Rectangle aRect( aPos, aSize );
1144 : // aRect.Top() += nEditHeight;
1145 0 : if ( bBorder )
1146 : {
1147 0 : ImplDrawFrame( pDev, aRect );
1148 : }
1149 0 : if ( bBackground )
1150 : {
1151 0 : pDev->SetFillColor( GetControlBackground() );
1152 0 : pDev->DrawRect( aRect );
1153 : }
1154 : }
1155 :
1156 : // contents
1157 0 : if ( !IsDropDownBox() )
1158 : {
1159 0 : long nOnePixel = GetDrawPixel( pDev, 1 );
1160 0 : long nTextHeight = pDev->GetTextHeight();
1161 0 : long nEditHeight = nTextHeight + 6*nOnePixel;
1162 0 : sal_uInt16 nTextStyle = TEXT_DRAW_VCENTER;
1163 :
1164 : // First, draw the edit part
1165 0 : mpSubEdit->Draw( pDev, aPos, Size( aSize.Width(), nEditHeight ), nFlags );
1166 :
1167 : // Second, draw the listbox
1168 0 : if ( GetStyle() & WB_CENTER )
1169 0 : nTextStyle |= TEXT_DRAW_CENTER;
1170 0 : else if ( GetStyle() & WB_RIGHT )
1171 0 : nTextStyle |= TEXT_DRAW_RIGHT;
1172 : else
1173 0 : nTextStyle |= TEXT_DRAW_LEFT;
1174 :
1175 0 : if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1176 : {
1177 0 : pDev->SetTextColor( Color( COL_BLACK ) );
1178 : }
1179 : else
1180 : {
1181 0 : if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
1182 : {
1183 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1184 0 : pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1185 : }
1186 : else
1187 : {
1188 0 : pDev->SetTextColor( GetTextColor() );
1189 : }
1190 : }
1191 :
1192 0 : Rectangle aClip( aPos, aSize );
1193 0 : pDev->IntersectClipRegion( aClip );
1194 0 : sal_uInt16 nLines = (sal_uInt16) ( ( nTextHeight > 0 ) ? ( (aSize.Height()-nEditHeight) / nTextHeight ) : 1 );
1195 0 : if ( !nLines )
1196 0 : nLines = 1;
1197 0 : sal_uInt16 nTEntry = IsReallyVisible() ? mpImplLB->GetTopEntry() : 0;
1198 :
1199 0 : Rectangle aTextRect( aPos, aSize );
1200 :
1201 0 : aTextRect.Left() += 3*nOnePixel;
1202 0 : aTextRect.Right() -= 3*nOnePixel;
1203 0 : aTextRect.Top() += nEditHeight + nOnePixel;
1204 0 : aTextRect.Bottom() = aTextRect.Top() + nTextHeight;
1205 :
1206 : // the drawing starts here
1207 0 : for ( sal_uInt16 n = 0; n < nLines; n++ )
1208 : {
1209 0 : pDev->DrawText( aTextRect, mpImplLB->GetEntryList()->GetEntryText( n+nTEntry ), nTextStyle );
1210 0 : aTextRect.Top() += nTextHeight;
1211 0 : aTextRect.Bottom() += nTextHeight;
1212 : }
1213 : }
1214 :
1215 0 : pDev->Pop();
1216 :
1217 : // Call Edit::Draw after restoring the MapMode...
1218 0 : if ( IsDropDownBox() )
1219 : {
1220 0 : mpSubEdit->Draw( pDev, rPos, rSize, nFlags );
1221 : // DD-Button ?
1222 0 : }
1223 :
1224 0 : }
1225 :
1226 2576 : void::ComboBox::ImplUserDrawHandler( UserDrawEvent* pEvent )
1227 : {
1228 2576 : UserDraw( *pEvent );
1229 2576 : }
1230 :
1231 0 : void ComboBox::UserDraw( const UserDrawEvent& )
1232 : {
1233 0 : }
1234 :
1235 4854 : void ComboBox::SetUserItemSize( const Size& rSz )
1236 : {
1237 4854 : mpImplLB->GetMainWindow().SetUserItemSize( rSz );
1238 4854 : }
1239 :
1240 3170 : void ComboBox::EnableUserDraw( bool bUserDraw )
1241 : {
1242 3170 : mpImplLB->GetMainWindow().EnableUserDraw( bUserDraw );
1243 3170 : }
1244 :
1245 2576 : void ComboBox::DrawEntry( const UserDrawEvent& rEvt, bool bDrawImage, bool bDrawText, bool bDrawTextAtImagePos )
1246 : {
1247 : DBG_ASSERT( rEvt.GetDevice() == &mpImplLB->GetMainWindow(), "DrawEntry?!" );
1248 2576 : mpImplLB->GetMainWindow().DrawEntry( rEvt.GetItemId(), bDrawImage, bDrawText, bDrawTextAtImagePos );
1249 2576 : }
1250 :
1251 10116 : void ComboBox::SetSeparatorPos( sal_Int32 n )
1252 : {
1253 10116 : mpImplLB->SetSeparatorPos( n );
1254 10116 : }
1255 :
1256 0 : void ComboBox::SetMRUEntries( const OUString& rEntries, sal_Unicode cSep )
1257 : {
1258 0 : mpImplLB->SetMRUEntries( rEntries, cSep );
1259 0 : }
1260 :
1261 3638 : OUString ComboBox::GetMRUEntries( sal_Unicode cSep ) const
1262 : {
1263 3638 : return mpImplLB->GetMRUEntries( cSep );
1264 : }
1265 :
1266 1954 : void ComboBox::SetMaxMRUCount( sal_Int32 n )
1267 : {
1268 1954 : mpImplLB->SetMaxMRUCount( n );
1269 1954 : }
1270 :
1271 1956 : sal_Int32 ComboBox::GetMaxMRUCount() const
1272 : {
1273 1956 : return mpImplLB->GetMaxMRUCount();
1274 : }
1275 :
1276 356 : sal_uInt16 ComboBox::GetDisplayLineCount() const
1277 : {
1278 356 : return mpImplLB->GetDisplayLineCount();
1279 : }
1280 :
1281 58440 : void ComboBox::SetEntryData( sal_Int32 nPos, void* pNewData )
1282 : {
1283 58440 : mpImplLB->SetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount(), pNewData );
1284 58440 : }
1285 :
1286 0 : void* ComboBox::GetEntryData( sal_Int32 nPos ) const
1287 : {
1288 0 : return mpImplLB->GetEntryList()->GetEntryData( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1289 : }
1290 :
1291 340 : sal_Int32 ComboBox::GetTopEntry() const
1292 : {
1293 340 : sal_Int32 nPos = GetEntryCount() ? mpImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND;
1294 340 : if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
1295 0 : nPos = 0;
1296 340 : return nPos;
1297 : }
1298 :
1299 1948 : void ComboBox::SetProminentEntryType( ProminentEntry eType )
1300 : {
1301 1948 : mpImplLB->SetProminentEntryType( eType );
1302 1948 : }
1303 :
1304 0 : Rectangle ComboBox::GetDropDownPosSizePixel() const
1305 : {
1306 0 : return mpFloatWin ? mpFloatWin->GetWindowExtentsRelative( const_cast<ComboBox*>(this) ) : Rectangle();
1307 : }
1308 :
1309 0 : const Wallpaper& ComboBox::GetDisplayBackground() const
1310 : {
1311 0 : if( ! mpSubEdit->IsBackground() )
1312 0 : return Control::GetDisplayBackground();
1313 :
1314 0 : const Wallpaper& rBack = mpSubEdit->GetBackground();
1315 0 : if( ! rBack.IsBitmap() &&
1316 0 : ! rBack.IsGradient() &&
1317 0 : rBack.GetColor().GetColor() == COL_TRANSPARENT
1318 : )
1319 0 : return Control::GetDisplayBackground();
1320 0 : return rBack;
1321 : }
1322 :
1323 0 : sal_Int32 ComboBox::GetSelectEntryCount() const
1324 : {
1325 0 : return mpImplLB->GetEntryList()->GetSelectEntryCount();
1326 : }
1327 :
1328 862 : sal_Int32 ComboBox::GetSelectEntryPos( sal_Int32 nIndex ) const
1329 : {
1330 862 : sal_Int32 nPos = mpImplLB->GetEntryList()->GetSelectEntryPos( nIndex );
1331 862 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
1332 : {
1333 860 : if ( nPos < mpImplLB->GetEntryList()->GetMRUCount() )
1334 0 : nPos = mpImplLB->GetEntryList()->FindEntry( mpImplLB->GetEntryList()->GetEntryText( nPos ) );
1335 860 : nPos = sal::static_int_cast<sal_Int32>(nPos - mpImplLB->GetEntryList()->GetMRUCount());
1336 : }
1337 862 : return nPos;
1338 : }
1339 :
1340 340 : bool ComboBox::IsEntryPosSelected( sal_Int32 nPos ) const
1341 : {
1342 340 : return mpImplLB->GetEntryList()->IsEntryPosSelected( nPos + mpImplLB->GetEntryList()->GetMRUCount() );
1343 : }
1344 :
1345 0 : void ComboBox::SelectEntryPos( sal_Int32 nPos, bool bSelect)
1346 : {
1347 0 : if ( nPos < mpImplLB->GetEntryList()->GetEntryCount() )
1348 0 : mpImplLB->SelectEntry( nPos + mpImplLB->GetEntryList()->GetMRUCount(), bSelect );
1349 0 : }
1350 :
1351 0 : void ComboBox::SetNoSelection()
1352 : {
1353 0 : mpImplLB->SetNoSelection();
1354 0 : mpSubEdit->SetText( OUString() );
1355 0 : }
1356 :
1357 0 : Rectangle ComboBox::GetBoundingRectangle( sal_Int32 nItem ) const
1358 : {
1359 0 : Rectangle aRect = mpImplLB->GetMainWindow().GetBoundingRectangle( nItem );
1360 0 : Rectangle aOffset = mpImplLB->GetMainWindow().GetWindowExtentsRelative( (vcl::Window*)this );
1361 0 : aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
1362 0 : return aRect;
1363 : }
1364 :
1365 46 : void ComboBox::SetBorderStyle( WindowBorderStyle nBorderStyle )
1366 : {
1367 46 : Window::SetBorderStyle( nBorderStyle );
1368 46 : if ( !IsDropDownBox() )
1369 : {
1370 28 : mpSubEdit->SetBorderStyle( nBorderStyle );
1371 28 : mpImplLB->SetBorderStyle( nBorderStyle );
1372 : }
1373 46 : }
1374 :
1375 0 : long ComboBox::GetIndexForPoint( const Point& rPoint, sal_Int32& rPos ) const
1376 : {
1377 0 : if( !HasLayoutData() )
1378 0 : FillLayoutData();
1379 :
1380 : // check whether rPoint fits at all
1381 0 : long nIndex = Control::GetIndexForPoint( rPoint );
1382 0 : if( nIndex != -1 )
1383 : {
1384 : // point must be either in main list window
1385 : // or in impl window (dropdown case)
1386 0 : ImplListBoxWindow& rMain = mpImplLB->GetMainWindow();
1387 :
1388 : // convert coordinates to ImplListBoxWindow pixel coordinate space
1389 0 : Point aConvPoint = LogicToPixel( rPoint );
1390 0 : aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
1391 0 : aConvPoint = rMain.AbsoluteScreenToOutputPixel( aConvPoint );
1392 0 : aConvPoint = rMain.PixelToLogic( aConvPoint );
1393 :
1394 : // try to find entry
1395 0 : sal_Int32 nEntry = rMain.GetEntryPosForPoint( aConvPoint );
1396 0 : if( nEntry == LISTBOX_ENTRY_NOTFOUND )
1397 0 : nIndex = -1;
1398 : else
1399 0 : rPos = nEntry;
1400 : }
1401 :
1402 : // get line relative index
1403 0 : if( nIndex != -1 )
1404 0 : nIndex = ToRelativeLineIndex( nIndex );
1405 :
1406 0 : return nIndex;
1407 : }
1408 :
1409 11422 : ComboBox::ComboBoxBounds ComboBox::calcComboBoxDropDownComponentBounds(const Size &rOutSz,
1410 : const Size &rBorderOutSz) const
1411 : {
1412 11422 : ComboBoxBounds aBounds;
1413 :
1414 11422 : long nTop = 0;
1415 11422 : long nBottom = rOutSz.Height();
1416 :
1417 11422 : vcl::Window *pBorder = GetWindow( WINDOW_BORDER );
1418 11422 : ImplControlValue aControlValue;
1419 11422 : Point aPoint;
1420 11422 : Rectangle aContent, aBound;
1421 :
1422 : // use the full extent of the control
1423 11422 : Rectangle aArea( aPoint, rBorderOutSz );
1424 :
1425 22844 : if ( GetNativeControlRegion(CTRL_COMBOBOX, PART_BUTTON_DOWN,
1426 22844 : aArea, 0, aControlValue, OUString(), aBound, aContent) )
1427 : {
1428 : // convert back from border space to local coordinates
1429 0 : aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
1430 0 : aContent.Move(-aPoint.X(), -aPoint.Y());
1431 :
1432 0 : aBounds.aButtonPos = Point(aContent.Left(), nTop);
1433 0 : aBounds.aButtonSize = Size(aContent.getWidth(), (nBottom-nTop));
1434 :
1435 : // adjust the size of the edit field
1436 0 : if ( GetNativeControlRegion(CTRL_COMBOBOX, PART_SUB_EDIT,
1437 0 : aArea, 0, aControlValue, OUString(), aBound, aContent) )
1438 : {
1439 : // convert back from border space to local coordinates
1440 0 : aContent.Move(-aPoint.X(), -aPoint.Y());
1441 :
1442 : // use the themes drop down size
1443 0 : aBounds.aSubEditPos = aContent.TopLeft();
1444 0 : aBounds.aSubEditSize = aContent.GetSize();
1445 : }
1446 : else
1447 : {
1448 : // use the themes drop down size for the button
1449 0 : aBounds.aSubEditSize = Size(rOutSz.Width() - aContent.getWidth(), rOutSz.Height());
1450 : }
1451 : }
1452 : else
1453 : {
1454 11422 : long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
1455 11422 : nSBWidth = CalcZoom( nSBWidth );
1456 11422 : aBounds.aSubEditSize = Size(rOutSz.Width() - nSBWidth, rOutSz.Height());
1457 11422 : aBounds.aButtonPos = Point(rOutSz.Width() - nSBWidth, nTop);
1458 11422 : aBounds.aButtonSize = Size(nSBWidth, (nBottom-nTop));
1459 : }
1460 11422 : return aBounds;
1461 : }
1462 :
1463 0 : void ComboBox::setMaxWidthChars(sal_Int32 nWidth)
1464 : {
1465 0 : if (nWidth != m_nMaxWidthChars)
1466 : {
1467 0 : m_nMaxWidthChars = nWidth;
1468 0 : queue_resize();
1469 : }
1470 0 : }
1471 :
1472 0 : bool ComboBox::set_property(const OString &rKey, const OString &rValue)
1473 : {
1474 0 : if (rKey == "max-width-chars")
1475 0 : setMaxWidthChars(rValue.toInt32());
1476 : else
1477 0 : return Control::set_property(rKey, rValue);
1478 0 : return true;
1479 1233 : }
1480 :
1481 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|