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