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