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