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 <comphelper/processfactory.hxx> 32 33 #include <tools/diagnose_ex.h> 34 #include <tools/rc.h> 35 36 #include <vcl/svapp.hxx> 37 #include <vcl/event.hxx> 38 #include <vcl/ctrl.hxx> 39 #include <vcl/decoview.hxx> 40 #include <vcl/salnativewidgets.hxx> 41 42 #include <textlayout.hxx> 43 #include <svdata.hxx> 44 #include <controldata.hxx> 45 46 47 using namespace vcl; 48 49 // ======================================================================= 50 51 void Control::ImplInitControlData() 52 { 53 mbHasControlFocus = sal_False; 54 mpControlData = new ImplControlData; 55 } 56 57 // ----------------------------------------------------------------------- 58 59 Control::Control( WindowType nType ) : 60 Window( nType ) 61 { 62 ImplInitControlData(); 63 } 64 65 // ----------------------------------------------------------------------- 66 67 Control::Control( Window* pParent, WinBits nStyle ) : 68 Window( WINDOW_CONTROL ) 69 { 70 ImplInitControlData(); 71 Window::ImplInit( pParent, nStyle, NULL ); 72 } 73 74 // ----------------------------------------------------------------------- 75 76 Control::Control( Window* pParent, const ResId& rResId ) : 77 Window( WINDOW_CONTROL ) 78 { 79 ImplInitControlData(); 80 rResId.SetRT( RSC_CONTROL ); 81 WinBits nStyle = ImplInitRes( rResId ); 82 ImplInit( pParent, nStyle, NULL ); 83 ImplLoadRes( rResId ); 84 85 if ( !(nStyle & WB_HIDE) ) 86 Show(); 87 } 88 89 // ----------------------------------------------------------------------- 90 91 Control::~Control() 92 { 93 delete mpControlData, mpControlData = NULL; 94 } 95 96 // ----------------------------------------------------------------------- 97 98 void Control::GetFocus() 99 { 100 Window::GetFocus(); 101 } 102 103 // ----------------------------------------------------------------------- 104 105 void Control::LoseFocus() 106 { 107 Window::LoseFocus(); 108 } 109 110 // ----------------------------------------------------------------------- 111 112 void Control::Resize() 113 { 114 ImplClearLayoutData(); 115 Window::Resize(); 116 } 117 118 // ----------------------------------------------------------------------- 119 120 void Control::FillLayoutData() const 121 { 122 } 123 124 // ----------------------------------------------------------------------- 125 126 void Control::CreateLayoutData() const 127 { 128 DBG_ASSERT( !mpControlData->mpLayoutData, "Control::CreateLayoutData: should be called with non-existent layout data only!" ); 129 mpControlData->mpLayoutData = new ::vcl::ControlLayoutData(); 130 } 131 132 // ----------------------------------------------------------------------- 133 134 bool Control::HasLayoutData() const 135 { 136 return mpControlData->mpLayoutData != NULL; 137 } 138 139 // ----------------------------------------------------------------------- 140 141 ::vcl::ControlLayoutData* Control::GetLayoutData() const 142 { 143 return mpControlData->mpLayoutData; 144 } 145 146 // ----------------------------------------------------------------------- 147 148 void Control::SetText( const String& rStr ) 149 { 150 ImplClearLayoutData(); 151 Window::SetText( rStr ); 152 } 153 154 // ----------------------------------------------------------------------- 155 156 Rectangle ControlLayoutData::GetCharacterBounds( long nIndex ) const 157 { 158 return (nIndex >= 0 && nIndex < (long) m_aUnicodeBoundRects.size()) ? m_aUnicodeBoundRects[ nIndex ] : Rectangle(); 159 } 160 161 162 // ----------------------------------------------------------------------- 163 164 Rectangle Control::GetCharacterBounds( long nIndex ) const 165 { 166 if( !HasLayoutData() ) 167 FillLayoutData(); 168 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetCharacterBounds( nIndex ) : Rectangle(); 169 } 170 171 // ----------------------------------------------------------------------- 172 173 long ControlLayoutData::GetIndexForPoint( const Point& rPoint ) const 174 { 175 long nIndex = -1; 176 for( long i = m_aUnicodeBoundRects.size()-1; i >= 0; i-- ) 177 { 178 if( m_aUnicodeBoundRects[ i ].IsInside( rPoint ) ) 179 { 180 nIndex = i; 181 break; 182 } 183 } 184 return nIndex; 185 } 186 187 // ----------------------------------------------------------------------- 188 189 long Control::GetIndexForPoint( const Point& rPoint ) const 190 { 191 if( ! HasLayoutData() ) 192 FillLayoutData(); 193 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetIndexForPoint( rPoint ) : -1; 194 } 195 196 // ----------------------------------------------------------------------- 197 198 long ControlLayoutData::GetLineCount() const 199 { 200 long nLines = m_aLineIndices.size(); 201 if( nLines == 0 && m_aDisplayText.Len() ) 202 nLines = 1; 203 return nLines; 204 } 205 206 // ----------------------------------------------------------------------- 207 208 long Control::GetLineCount() const 209 { 210 if( !HasLayoutData() ) 211 FillLayoutData(); 212 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineCount() : 0; 213 } 214 215 // ----------------------------------------------------------------------- 216 217 Pair ControlLayoutData::GetLineStartEnd( long nLine ) const 218 { 219 Pair aPair( -1, -1 ); 220 221 int nDisplayLines = m_aLineIndices.size(); 222 if( nLine >= 0 && nLine < nDisplayLines ) 223 { 224 aPair.A() = m_aLineIndices[nLine]; 225 if( nLine+1 < nDisplayLines ) 226 aPair.B() = m_aLineIndices[nLine+1]-1; 227 else 228 aPair.B() = m_aDisplayText.Len()-1; 229 } 230 else if( nLine == 0 && nDisplayLines == 0 && m_aDisplayText.Len() ) 231 { 232 // special case for single line controls so the implementations 233 // in that case do not have to fill in the line indices 234 aPair.A() = 0; 235 aPair.B() = m_aDisplayText.Len()-1; 236 } 237 return aPair; 238 } 239 240 // ----------------------------------------------------------------------- 241 242 Pair Control::GetLineStartEnd( long nLine ) const 243 { 244 if( !HasLayoutData() ) 245 FillLayoutData(); 246 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 ); 247 } 248 249 // ----------------------------------------------------------------------- 250 251 long ControlLayoutData::ToRelativeLineIndex( long nIndex ) const 252 { 253 // is the index sensible at all ? 254 if( nIndex >= 0 && nIndex < m_aDisplayText.Len() ) 255 { 256 int nDisplayLines = m_aLineIndices.size(); 257 // if only 1 line exists, then absolute and relative index are 258 // identical -> do nothing 259 if( nDisplayLines > 1 ) 260 { 261 int nLine; 262 for( nLine = nDisplayLines-1; nLine >= 0; nLine-- ) 263 { 264 if( m_aLineIndices[nLine] <= nIndex ) 265 { 266 nIndex -= m_aLineIndices[nLine]; 267 break; 268 } 269 } 270 if( nLine < 0 ) 271 { 272 DBG_ASSERT( nLine >= 0, "ToRelativeLineIndex failed" ); 273 nIndex = -1; 274 } 275 } 276 } 277 else 278 nIndex = -1; 279 280 return nIndex; 281 } 282 283 // ----------------------------------------------------------------------- 284 285 long Control::ToRelativeLineIndex( long nIndex ) const 286 { 287 if( !HasLayoutData() ) 288 FillLayoutData(); 289 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->ToRelativeLineIndex( nIndex ) : -1; 290 } 291 292 // ----------------------------------------------------------------------- 293 294 String Control::GetDisplayText() const 295 { 296 if( !HasLayoutData() ) 297 FillLayoutData(); 298 return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->m_aDisplayText : GetText(); 299 } 300 301 // ----------------------------------------------------------------------- 302 303 long Control::Notify( NotifyEvent& rNEvt ) 304 { 305 if ( rNEvt.GetType() == EVENT_GETFOCUS ) 306 { 307 if ( !mbHasControlFocus ) 308 { 309 mbHasControlFocus = sal_True; 310 StateChanged( STATE_CHANGE_CONTROL_FOCUS ); 311 if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) ) 312 // been destroyed within the handler 313 return sal_True; 314 } 315 } 316 else 317 { 318 if ( rNEvt.GetType() == EVENT_LOSEFOCUS ) 319 { 320 Window* pFocusWin = Application::GetFocusWindow(); 321 if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) ) 322 { 323 mbHasControlFocus = sal_False; 324 StateChanged( STATE_CHANGE_CONTROL_FOCUS ); 325 if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) ) 326 // been destroyed within the handler 327 return sal_True; 328 } 329 } 330 } 331 332 return Window::Notify( rNEvt ); 333 } 334 335 // ----------------------------------------------------------------------- 336 337 void Control::StateChanged( StateChangedType nStateChange ) 338 { 339 if( nStateChange == STATE_CHANGE_INITSHOW || 340 nStateChange == STATE_CHANGE_VISIBLE || 341 nStateChange == STATE_CHANGE_FORMAT || 342 nStateChange == STATE_CHANGE_ZOOM || 343 nStateChange == STATE_CHANGE_BORDER || 344 nStateChange == STATE_CHANGE_CONTROLFONT 345 ) 346 { 347 ImplClearLayoutData(); 348 } 349 Window::StateChanged( nStateChange ); 350 } 351 352 // ----------------------------------------------------------------------- 353 354 void Control::AppendLayoutData( const Control& rSubControl ) const 355 { 356 if( !rSubControl.HasLayoutData() ) 357 rSubControl.FillLayoutData(); 358 if( !rSubControl.HasLayoutData() || !rSubControl.mpControlData->mpLayoutData->m_aDisplayText.Len() ) 359 return; 360 361 long nCurrentIndex = mpControlData->mpLayoutData->m_aDisplayText.Len(); 362 mpControlData->mpLayoutData->m_aDisplayText.Append( rSubControl.mpControlData->mpLayoutData->m_aDisplayText ); 363 int nLines = rSubControl.mpControlData->mpLayoutData->m_aLineIndices.size(); 364 int n; 365 mpControlData->mpLayoutData->m_aLineIndices.push_back( nCurrentIndex ); 366 for( n = 1; n < nLines; n++ ) 367 mpControlData->mpLayoutData->m_aLineIndices.push_back( rSubControl.mpControlData->mpLayoutData->m_aLineIndices[n] + nCurrentIndex ); 368 int nRectangles = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects.size(); 369 Rectangle aRel = const_cast<Control&>(rSubControl).GetWindowExtentsRelative( const_cast<Control*>(this) ); 370 for( n = 0; n < nRectangles; n++ ) 371 { 372 Rectangle aRect = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects[n]; 373 aRect.Move( aRel.Left(), aRel.Top() ); 374 mpControlData->mpLayoutData->m_aUnicodeBoundRects.push_back( aRect ); 375 } 376 } 377 378 // ----------------------------------------------------------------- 379 380 sal_Bool Control::ImplCallEventListenersAndHandler( sal_uLong nEvent, const Link& rHandler, void* pCaller ) 381 { 382 ImplDelData aCheckDelete; 383 ImplAddDel( &aCheckDelete ); 384 385 ImplCallEventListeners( nEvent ); 386 if ( !aCheckDelete.IsDelete() ) 387 { 388 rHandler.Call( pCaller ); 389 390 if ( !aCheckDelete.IsDelete() ) 391 { 392 ImplRemoveDel( &aCheckDelete ); 393 return sal_False; 394 } 395 } 396 return sal_True; 397 } 398 399 // ----------------------------------------------------------------- 400 401 void Control::SetLayoutDataParent( const Control* pParent ) const 402 { 403 if( HasLayoutData() ) 404 mpControlData->mpLayoutData->m_pParent = pParent; 405 } 406 407 // ----------------------------------------------------------------- 408 409 void Control::ImplClearLayoutData() const 410 { 411 delete mpControlData->mpLayoutData, mpControlData->mpLayoutData = NULL; 412 } 413 414 // ----------------------------------------------------------------------- 415 416 void Control::ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect ) 417 { 418 // use a deco view to draw the frame 419 // However, since there happens a lot of magic there, we need to fake some (style) settings 420 // on the device 421 AllSettings aOriginalSettings( pDev->GetSettings() ); 422 423 AllSettings aNewSettings( aOriginalSettings ); 424 StyleSettings aStyle( aNewSettings.GetStyleSettings() ); 425 426 // The *only known* clients of the Draw methods of the various VCL-controls are form controls: 427 // During print preview, and during printing, Draw is called. Thus, drawing always happens with a 428 // mono (colored) border 429 aStyle.SetOptions( aStyle.GetOptions() | STYLE_OPTION_MONO ); 430 aStyle.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() ); 431 432 aNewSettings.SetStyleSettings( aStyle ); 433 // #i67023# do not call data changed listeners for this fake 434 // since they may understandably invalidate on settings changed 435 pDev->OutputDevice::SetSettings( aNewSettings ); 436 437 DecorationView aDecoView( pDev ); 438 rRect = aDecoView.DrawFrame( rRect, FRAME_DRAW_WINDOWBORDER ); 439 440 pDev->OutputDevice::SetSettings( aOriginalSettings ); 441 } 442 443 // ----------------------------------------------------------------------- 444 445 void Control::DataChanged( const DataChangedEvent& rDCEvt) 446 { 447 // we don't want to loose some style settings for controls created with the 448 // toolkit 449 if ( IsCreatedWithToolkit() && 450 (rDCEvt.GetType() == DATACHANGED_SETTINGS) && 451 (rDCEvt.GetFlags() & SETTINGS_STYLE) ) 452 { 453 AllSettings aSettings = GetSettings(); 454 StyleSettings aStyleSettings = aSettings.GetStyleSettings(); 455 sal_uLong nOldOptions = rDCEvt.GetOldSettings()->GetStyleSettings().GetOptions(); 456 sal_uLong nNewOptions = aStyleSettings.GetOptions(); 457 458 if ( !(nNewOptions & STYLE_OPTION_MONO) && ( nOldOptions & STYLE_OPTION_MONO ) ) 459 { 460 nNewOptions |= STYLE_OPTION_MONO; 461 aStyleSettings.SetOptions( nNewOptions ); 462 aStyleSettings.SetMonoColor( rDCEvt.GetOldSettings()->GetStyleSettings().GetMonoColor() ); 463 aSettings.SetStyleSettings( aStyleSettings ); 464 SetSettings( aSettings ); 465 } 466 } 467 } 468 469 // ----------------------------------------------------------------- 470 471 ControlLayoutData::~ControlLayoutData() 472 { 473 if( m_pParent ) 474 m_pParent->ImplClearLayoutData(); 475 } 476 477 // ----------------------------------------------------------------- 478 479 Size Control::GetOptimalSize(WindowSizeType eType) const 480 { 481 switch (eType) { 482 case WINDOWSIZE_MINIMUM: 483 return Size( GetTextWidth( GetText() ) + 2 * 12, 484 GetTextHeight() + 2 * 6 ); 485 case WINDOWSIZE_PREFERRED: 486 return GetOptimalSize( WINDOWSIZE_MINIMUM ); 487 case WINDOWSIZE_MAXIMUM: 488 default: 489 return Size( LONG_MAX, LONG_MAX ); 490 } 491 } 492 493 // ----------------------------------------------------------------- 494 495 void Control::SetReferenceDevice( OutputDevice* _referenceDevice ) 496 { 497 if ( mpControlData->mpReferenceDevice == _referenceDevice ) 498 return; 499 500 mpControlData->mpReferenceDevice = _referenceDevice; 501 Invalidate(); 502 } 503 504 // ----------------------------------------------------------------- 505 506 OutputDevice* Control::GetReferenceDevice() const 507 { 508 return mpControlData->mpReferenceDevice; 509 } 510 511 // ----------------------------------------------------------------- 512 513 const Font& Control::GetCanonicalFont( const StyleSettings& _rStyle ) const 514 { 515 return _rStyle.GetLabelFont(); 516 } 517 518 // ----------------------------------------------------------------- 519 const Color& Control::GetCanonicalTextColor( const StyleSettings& _rStyle ) const 520 { 521 return _rStyle.GetLabelTextColor(); 522 } 523 524 // ----------------------------------------------------------------- 525 void Control::ImplInitSettings( const sal_Bool _bFont, const sal_Bool _bForeground ) 526 { 527 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); 528 529 if ( _bFont ) 530 { 531 Font aFont( GetCanonicalFont( rStyleSettings ) ); 532 if ( IsControlFont() ) 533 aFont.Merge( GetControlFont() ); 534 SetZoomedPointFont( aFont ); 535 } 536 537 if ( _bForeground || _bFont ) 538 { 539 Color aColor; 540 if ( IsControlForeground() ) 541 aColor = GetControlForeground(); 542 else 543 aColor = GetCanonicalTextColor( rStyleSettings ); 544 SetTextColor( aColor ); 545 SetTextFillColor(); 546 } 547 } 548 549 // ----------------------------------------------------------------- 550 551 void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr, 552 sal_uInt16 _nStyle, MetricVector* _pVector, String* _pDisplayText ) const 553 { 554 #ifdef FS_DEBUG 555 if ( !_pVector ) 556 { 557 static MetricVector aCharRects; 558 static String sDisplayText; 559 aCharRects.clear(); 560 sDisplayText = String(); 561 _pVector = &aCharRects; 562 _pDisplayText = &sDisplayText; 563 } 564 #endif 565 566 if ( !mpControlData->mpReferenceDevice || ( mpControlData->mpReferenceDevice == &_rTargetDevice ) ) 567 { 568 _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle ); 569 _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText ); 570 } 571 else 572 { 573 ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice ); 574 _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText ); 575 } 576 577 #ifdef FS_DEBUG 578 _rTargetDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); 579 _rTargetDevice.SetLineColor( COL_LIGHTRED ); 580 _rTargetDevice.SetFillColor(); 581 for ( MetricVector::const_iterator cr = _pVector->begin(); 582 cr != _pVector->end(); 583 ++cr 584 ) 585 { 586 _rTargetDevice.DrawRect( *cr ); 587 } 588 _rTargetDevice.Pop(); 589 #endif 590 } 591