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