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