1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "richtextimplcontrol.hxx" 21 #include "textattributelistener.hxx" 22 #include "richtextengine.hxx" 23 #include <sal/log.hxx> 24 #include <osl/diagnose.h> 25 #include <i18nlangtag/languagetag.hxx> 26 #include <editeng/editids.hrc> 27 #include <editeng/editview.hxx> 28 #include <editeng/editstat.hxx> 29 #include <editeng/scripttypeitem.hxx> 30 31 #include <svl/itempool.hxx> 32 #include <svl/itemset.hxx> 33 #include <tools/mapunit.hxx> 34 #include <vcl/svapp.hxx> 35 #include <vcl/settings.hxx> 36 #include <vcl/commandevent.hxx> 37 38 #define EMPTY_PAPER_SIZE 0x7FFFFFFF 39 40 41 namespace frm 42 { 43 RichTextControlImpl(Control * _pAntiImpl,RichTextEngine * _pEngine,ITextAttributeListener * _pTextAttrListener,ITextSelectionListener * _pSelectionListener)44 RichTextControlImpl::RichTextControlImpl( Control* _pAntiImpl, RichTextEngine* _pEngine, ITextAttributeListener* _pTextAttrListener, ITextSelectionListener* _pSelectionListener ) 45 :m_pAntiImpl ( _pAntiImpl ) 46 ,m_pViewport ( nullptr ) 47 ,m_pHScroll ( nullptr ) 48 ,m_pVScroll ( nullptr ) 49 ,m_pScrollCorner ( nullptr ) 50 ,m_pEngine ( _pEngine ) 51 ,m_pTextAttrListener ( _pTextAttrListener ) 52 ,m_pSelectionListener ( _pSelectionListener ) 53 ,m_bHasEverBeenShown ( false ) 54 { 55 OSL_ENSURE( m_pAntiImpl, "RichTextControlImpl::RichTextControlImpl: invalid window!" ); 56 OSL_ENSURE( m_pEngine, "RichTextControlImpl::RichTextControlImpl: invalid edit engine! This will *definitely* crash!" ); 57 58 m_pViewport = VclPtr<RichTextViewPort>::Create( m_pAntiImpl ); 59 m_pViewport->setAttributeInvalidationHandler( LINK( this, RichTextControlImpl, OnInvalidateAllAttributes ) ); 60 m_pViewport->Show(); 61 62 // ensure that both the window and the reference device have the same map unit 63 MapMode aRefDeviceMapMode( m_pEngine->GetRefDevice()->GetMapMode() ); 64 m_pAntiImpl->SetMapMode( aRefDeviceMapMode ); 65 m_pViewport->SetMapMode( aRefDeviceMapMode ); 66 67 m_pView.reset(new EditView( m_pEngine, m_pViewport )); 68 m_pEngine->InsertView( m_pView.get() ); 69 m_pViewport->setView( *m_pView ); 70 71 m_pEngine->registerEngineStatusListener( this ); 72 73 { 74 EVControlBits nViewControlWord = m_pView->GetControlWord(); 75 nViewControlWord |= EVControlBits::AUTOSCROLL; 76 m_pView->SetControlWord( nViewControlWord ); 77 } 78 79 // ensure that it's initially scrolled to the upper left 80 m_pView->SetVisArea( tools::Rectangle( Point( ), m_pViewport->GetOutDev()->GetOutputSize() ) ); 81 82 ensureScrollbars(); 83 84 m_pAntiImpl->SetBackground( Wallpaper( m_pAntiImpl->GetSettings().GetStyleSettings().GetFieldColor() ) ); 85 } 86 87 ~RichTextControlImpl()88 RichTextControlImpl::~RichTextControlImpl( ) 89 { 90 m_pEngine->RemoveView( m_pView.get() ); 91 m_pEngine->revokeEngineStatusListener( this ); 92 m_pView.reset(); 93 m_pViewport.disposeAndClear(); 94 m_pHScroll.disposeAndClear(); 95 m_pVScroll.disposeAndClear(); 96 m_pScrollCorner.disposeAndClear(); 97 } 98 99 implUpdateAttribute(const AttributeHandlerPool::const_iterator & _pHandler)100 void RichTextControlImpl::implUpdateAttribute( const AttributeHandlerPool::const_iterator& _pHandler ) 101 { 102 if ( ( _pHandler->first == SID_ATTR_CHAR_WEIGHT ) 103 || ( _pHandler->first == SID_ATTR_CHAR_POSTURE ) 104 || ( _pHandler->first == SID_ATTR_CHAR_FONT ) 105 || ( _pHandler->first == SID_ATTR_CHAR_FONTHEIGHT ) 106 ) 107 { 108 // these are attributes whose value depends on the current script type. 109 // I.e., in real, there are *three* items in the ItemSet: One for each script 110 // type (Latin, Asian, Complex). However, if we have an observer who is interested 111 // in the state of this attribute, we have to kind of *merge* the three attributes 112 // to only one. 113 // This is useful in case the observer is for instance a toolbox which contains only 114 // an, e.g., "bold" slot, and thus not interested in the particular script type of the 115 // current selection. 116 SvxScriptSetItem aNormalizedSet( static_cast<WhichId>(_pHandler->first), *m_pView->GetAttribs().GetPool() ); 117 normalizeScriptDependentAttribute( aNormalizedSet ); 118 119 implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( aNormalizedSet.GetItemSet() ) ); 120 } 121 else 122 implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( m_pView->GetAttribs() ) ); 123 } 124 125 updateAttribute(AttributeId _nAttribute)126 void RichTextControlImpl::updateAttribute( AttributeId _nAttribute ) 127 { 128 AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.find( _nAttribute ); 129 if ( pHandler != m_aAttributeHandlers.end() ) 130 implUpdateAttribute( pHandler ); 131 } 132 133 updateAllAttributes()134 void RichTextControlImpl::updateAllAttributes( ) 135 { 136 for ( AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.begin(); 137 pHandler != m_aAttributeHandlers.end(); 138 ++pHandler 139 ) 140 { 141 implUpdateAttribute( pHandler ); 142 } 143 144 // notify changes of the selection, if necessary 145 if ( m_pSelectionListener && m_pView ) 146 { 147 ESelection aCurrentSelection = m_pView->GetSelection(); 148 if ( aCurrentSelection != m_aLastKnownSelection ) 149 { 150 m_aLastKnownSelection = aCurrentSelection; 151 m_pSelectionListener->onSelectionChanged(); 152 } 153 } 154 } 155 156 getAttributeState(AttributeId _nAttributeId) const157 AttributeState RichTextControlImpl::getAttributeState( AttributeId _nAttributeId ) const 158 { 159 StateCache::const_iterator aCachedStatePos = m_aLastKnownStates.find( _nAttributeId ); 160 if ( aCachedStatePos == m_aLastKnownStates.end() ) 161 { 162 OSL_FAIL( "RichTextControlImpl::getAttributeState: Don't ask for the state of an attribute which I never encountered!" ); 163 return AttributeState( eIndetermined ); 164 } 165 return aCachedStatePos->second; 166 } 167 168 executeAttribute(const SfxItemSet & _rCurrentAttribs,SfxItemSet & _rAttribs,AttributeId _nAttribute,const SfxPoolItem * _pArgument,SvtScriptType _nForScriptType)169 bool RichTextControlImpl::executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rAttribs, AttributeId _nAttribute, const SfxPoolItem* _pArgument, SvtScriptType _nForScriptType ) 170 { 171 // let's see whether we have a handler for this attribute 172 AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttribute ); 173 if ( aHandlerPos != m_aAttributeHandlers.end() ) 174 { 175 aHandlerPos->second->executeAttribute( _rCurrentAttribs, _rAttribs, _pArgument, _nForScriptType ); 176 return true; 177 } 178 return false; 179 } 180 181 enableAttributeNotification(AttributeId _nAttributeId,ITextAttributeListener * _pListener)182 void RichTextControlImpl::enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener ) 183 { 184 AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId ); 185 if ( aHandlerPos == m_aAttributeHandlers.end() ) 186 { 187 ::rtl::Reference< AttributeHandler > aHandler = AttributeHandlerFactory::getHandlerFor( _nAttributeId, *m_pEngine->GetEmptyItemSet().GetPool() ); 188 OSL_ENSURE( aHandler.is(), "RichTextControlImpl::enableAttributeNotification: no handler available for this attribute!" ); 189 if ( !aHandler.is() ) 190 return; 191 SAL_WARN_IF( _nAttributeId != aHandler->getAttributeId(), "forms.richtext", "RichTextControlImpl::enableAttributeNotification: suspicious handler!" ); 192 193 aHandlerPos = m_aAttributeHandlers.emplace( _nAttributeId , aHandler ).first; 194 } 195 196 // remember the listener 197 if ( _pListener ) 198 m_aAttributeListeners.emplace( _nAttributeId, _pListener ); 199 200 // update (and broadcast) the state of this attribute 201 updateAttribute( _nAttributeId ); 202 } 203 204 disableAttributeNotification(AttributeId _nAttributeId)205 void RichTextControlImpl::disableAttributeNotification( AttributeId _nAttributeId ) 206 { 207 // forget the handler for this attribute 208 AttributeHandlerPool::iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId ); 209 if ( aHandlerPos != m_aAttributeHandlers.end() ) 210 m_aAttributeHandlers.erase( aHandlerPos ); 211 212 // as well as the listener 213 AttributeListenerPool::iterator aListenerPos = m_aAttributeListeners.find( _nAttributeId ); 214 if ( aListenerPos != m_aAttributeListeners.end() ) 215 m_aAttributeListeners.erase( aListenerPos ); 216 } 217 218 normalizeScriptDependentAttribute(SvxScriptSetItem & _rScriptSetItem)219 void RichTextControlImpl::normalizeScriptDependentAttribute( SvxScriptSetItem& _rScriptSetItem ) 220 { 221 _rScriptSetItem.GetItemSet().Put( m_pView->GetAttribs(), false ); 222 const SfxPoolItem* pNormalizedItem = _rScriptSetItem.GetItemOfScript( getSelectedScriptType() ); 223 224 WhichId nNormalizedWhichId = _rScriptSetItem.GetItemSet().GetPool()->GetWhich( _rScriptSetItem.Which() ); 225 if ( pNormalizedItem ) 226 { 227 _rScriptSetItem.GetItemSet().Put( pNormalizedItem->CloneSetWhich(nNormalizedWhichId) ); 228 } 229 else 230 _rScriptSetItem.GetItemSet().InvalidateItem( nNormalizedWhichId ); 231 } 232 233 implCheckUpdateCache(AttributeId _nAttribute,const AttributeState & _rState)234 void RichTextControlImpl::implCheckUpdateCache( AttributeId _nAttribute, const AttributeState& _rState ) 235 { 236 StateCache::iterator aCachePos = m_aLastKnownStates.find( _nAttribute ); 237 if ( aCachePos == m_aLastKnownStates.end() ) 238 { // nothing known about this attribute, yet 239 m_aLastKnownStates.emplace( _nAttribute, _rState ); 240 } 241 else 242 { 243 if ( aCachePos->second == _rState ) 244 { 245 // nothing to do 246 return; 247 } 248 aCachePos->second = _rState; 249 } 250 251 // is there a dedicated listener for this particular attribute? 252 AttributeListenerPool::const_iterator aListenerPos = m_aAttributeListeners.find( _nAttribute ); 253 if ( aListenerPos != m_aAttributeListeners.end( ) ) 254 aListenerPos->second->onAttributeStateChanged( _nAttribute ); 255 256 // call our global listener, if there is one 257 if ( m_pTextAttrListener ) 258 m_pTextAttrListener->onAttributeStateChanged( _nAttribute ); 259 } 260 261 getSelectedScriptType() const262 SvtScriptType RichTextControlImpl::getSelectedScriptType() const 263 { 264 SvtScriptType nScript = m_pView->GetSelectedScriptType(); 265 if ( nScript == SvtScriptType::NONE ) 266 nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); 267 return nScript; 268 } 269 270 EditEngineStatusChanged(const EditStatus & _rStatus)271 void RichTextControlImpl::EditEngineStatusChanged( const EditStatus& _rStatus ) 272 { 273 EditStatusFlags nStatusWord( _rStatus.GetStatusWord() ); 274 if ( ( nStatusWord & EditStatusFlags::TEXTWIDTHCHANGED ) 275 || ( nStatusWord & EditStatusFlags::TextHeightChanged ) 276 ) 277 { 278 if ( ( nStatusWord & EditStatusFlags::TextHeightChanged ) && windowHasAutomaticLineBreak() ) 279 m_pEngine->SetPaperSize( Size( m_pEngine->GetPaperSize().Width(), m_pEngine->GetTextHeight() ) ); 280 281 updateScrollbars(); 282 } 283 284 bool bHScroll = bool( nStatusWord & EditStatusFlags::HSCROLL ); 285 bool bVScroll = bool( nStatusWord & EditStatusFlags::VSCROLL ); 286 287 // In case of *no* automatic line breaks, we also need to check for the *range* here. 288 // Normally, we would do this only after an EditStatusFlags::TEXTWIDTHCHANGED. However, due to a bug 289 // in the EditEngine (I believe so) this is not fired when the engine does not have 290 // the AutoPaperSize bits set. 291 // So in order to be properly notified, we would need the AutoPaperSize. But, with 292 // AutoPaperSize, other things do not work anymore: Either, when we set a MaxAutoPaperSize, 293 // then the view does automatic soft line breaks at the paper end - which we definitely do 294 // want. Or, if we did not set a MaxAutoPaperSize, then the view does not automatically scroll 295 // anymore in horizontal direction. 296 // So this is some kind of lose-lose situation ... :( 297 if ( !windowHasAutomaticLineBreak() && bHScroll ) 298 { 299 updateScrollbars(); 300 return; 301 } 302 303 if ( bHScroll && m_pHScroll ) 304 m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() ); 305 if ( bVScroll && m_pVScroll ) 306 m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() ); 307 } 308 309 IMPL_LINK_NOARG(RichTextControlImpl,OnInvalidateAllAttributes,LinkParamNone *,void)310 IMPL_LINK_NOARG( RichTextControlImpl, OnInvalidateAllAttributes, LinkParamNone*, void ) 311 { 312 updateAllAttributes(); 313 } 314 315 IMPL_LINK(RichTextControlImpl,OnHScroll,ScrollBar *,_pScrollbar,void)316 IMPL_LINK( RichTextControlImpl, OnHScroll, ScrollBar*, _pScrollbar, void ) 317 { 318 m_pView->Scroll( -_pScrollbar->GetDelta(), 0, ScrollRangeCheck::PaperWidthTextSize ); 319 } 320 321 IMPL_LINK(RichTextControlImpl,OnVScroll,ScrollBar *,_pScrollbar,void)322 IMPL_LINK( RichTextControlImpl, OnVScroll, ScrollBar*, _pScrollbar, void ) 323 { 324 m_pView->Scroll( 0, -_pScrollbar->GetDelta(), ScrollRangeCheck::PaperWidthTextSize ); 325 } 326 327 ensureScrollbars()328 void RichTextControlImpl::ensureScrollbars() 329 { 330 bool bNeedVScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_VSCROLL ); 331 bool bNeedHScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_HSCROLL ); 332 333 if ( ( bNeedVScroll == hasVScrollBar() ) && ( bNeedHScroll == hasHScrollBar( ) ) ) 334 // nothing to do 335 return; 336 337 // create or delete the scrollbars, as necessary 338 if ( !bNeedVScroll ) 339 { 340 m_pVScroll.disposeAndClear(); 341 } 342 else 343 { 344 m_pVScroll = VclPtr<ScrollBar>::Create( m_pAntiImpl, WB_VSCROLL | WB_DRAG | WB_REPEAT ); 345 m_pVScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnVScroll ) ); 346 m_pVScroll->Show(); 347 } 348 349 if ( !bNeedHScroll ) 350 { 351 m_pHScroll.disposeAndClear(); 352 } 353 else 354 { 355 m_pHScroll = VclPtr<ScrollBar>::Create( m_pAntiImpl, WB_HSCROLL | WB_DRAG | WB_REPEAT ); 356 m_pHScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnHScroll ) ); 357 m_pHScroll->Show(); 358 } 359 360 if ( m_pHScroll && m_pVScroll ) 361 { 362 m_pScrollCorner.disposeAndClear(); 363 m_pScrollCorner = VclPtr<ScrollBarBox>::Create( m_pAntiImpl ); 364 m_pScrollCorner->Show(); 365 } 366 else 367 { 368 m_pScrollCorner.disposeAndClear(); 369 } 370 371 layoutWindow(); 372 } 373 374 ensureLineBreakSetting()375 void RichTextControlImpl::ensureLineBreakSetting() 376 { 377 if ( !windowHasAutomaticLineBreak() ) 378 m_pEngine->SetPaperSize( Size( EMPTY_PAPER_SIZE, EMPTY_PAPER_SIZE ) ); 379 380 layoutWindow(); 381 } 382 383 layoutWindow()384 void RichTextControlImpl::layoutWindow() 385 { 386 if ( !m_bHasEverBeenShown ) 387 // no need to do anything. Especially, no need to set the paper size on the 388 // EditEngine to anything... 389 return; 390 391 const StyleSettings& rStyleSettings = m_pAntiImpl->GetSettings().GetStyleSettings(); 392 393 tools::Long nScrollBarWidth = m_pVScroll ? rStyleSettings.GetScrollBarSize() : 0; 394 tools::Long nScrollBarHeight = m_pHScroll ? rStyleSettings.GetScrollBarSize() : 0; 395 396 if ( m_pAntiImpl->IsZoom() ) 397 { 398 nScrollBarWidth = m_pAntiImpl->CalcZoom( nScrollBarWidth ); 399 nScrollBarHeight = m_pAntiImpl->CalcZoom( nScrollBarHeight ); 400 } 401 402 // the overall size we can use 403 Size aPlaygroundSizePixel( m_pAntiImpl->GetOutputSizePixel() ); 404 405 // the size of the viewport - note that the viewport does *not* occupy all the place 406 // which is left when subtracting the scrollbar width/height 407 Size aViewportPlaygroundPixel( aPlaygroundSizePixel ); 408 aViewportPlaygroundPixel.setWidth( ::std::max( tools::Long( 10 ), tools::Long( aViewportPlaygroundPixel.Width() - nScrollBarWidth ) ) ); 409 aViewportPlaygroundPixel.setHeight( ::std::max( tools::Long( 10 ), tools::Long( aViewportPlaygroundPixel.Height() - nScrollBarHeight ) ) ); 410 Size aViewportPlaygroundLogic( m_pViewport->PixelToLogic( aViewportPlaygroundPixel ) ); 411 412 const tools::Long nOffset = 2; 413 Size aViewportSizePixel( aViewportPlaygroundPixel.Width() - 2 * nOffset, aViewportPlaygroundPixel.Height() - 2 * nOffset ); 414 Size aViewportSizeLogic( m_pViewport->PixelToLogic( aViewportSizePixel ) ); 415 416 // position the viewport 417 m_pViewport->SetPosSizePixel( Point( nOffset, nOffset ), aViewportSizePixel ); 418 // position the scrollbars 419 if ( m_pVScroll ) 420 m_pVScroll->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), 0 ), Size( nScrollBarWidth, aViewportPlaygroundPixel.Height() ) ); 421 if ( m_pHScroll ) 422 m_pHScroll->SetPosSizePixel( Point( 0, aViewportPlaygroundPixel.Height() ), Size( aViewportPlaygroundPixel.Width(), nScrollBarHeight ) ); 423 if ( m_pScrollCorner ) 424 m_pScrollCorner->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), aViewportPlaygroundPixel.Height() ), Size( nScrollBarWidth, nScrollBarHeight ) ); 425 426 // paper size 427 if ( windowHasAutomaticLineBreak() ) 428 m_pEngine->SetPaperSize( Size( aViewportSizeLogic.Width(), m_pEngine->GetTextHeight() ) ); 429 430 // output area of the view 431 m_pView->SetOutputArea( tools::Rectangle( Point( ), aViewportSizeLogic ) ); 432 m_pView->SetVisArea( tools::Rectangle( Point( ), aViewportSizeLogic ) ); 433 434 if ( m_pVScroll ) 435 { 436 m_pVScroll->SetVisibleSize( aViewportPlaygroundLogic.Height() ); 437 438 // the default height of a text line... 439 tools::Long nFontHeight = m_pEngine->GetStandardFont(0).GetFontSize().Height(); 440 // ... is the scroll size for the vertical scrollbar 441 m_pVScroll->SetLineSize( nFontHeight ); 442 // the viewport width, minus one line, is the page scroll size 443 m_pVScroll->SetPageSize( ::std::max( nFontHeight, aViewportPlaygroundLogic.Height() - nFontHeight ) ); 444 } 445 446 // the font width 447 if ( m_pHScroll ) 448 { 449 m_pHScroll->SetVisibleSize( aViewportPlaygroundLogic.Width() ); 450 451 tools::Long nFontWidth = m_pEngine->GetStandardFont(0).GetFontSize().Width(); 452 if ( !nFontWidth ) 453 { 454 m_pViewport->GetOutDev()->Push( PushFlags::FONT ); 455 m_pViewport->SetFont( m_pEngine->GetStandardFont(0) ); 456 nFontWidth = m_pViewport->GetTextWidth( "x" ); 457 m_pViewport->GetOutDev()->Pop(); 458 } 459 // ... is the scroll size for the horizontal scrollbar 460 m_pHScroll->SetLineSize( 5 * nFontWidth ); 461 // the viewport height, minus one character, is the page scroll size 462 m_pHScroll->SetPageSize( ::std::max( nFontWidth, aViewportPlaygroundLogic.Width() - nFontWidth ) ); 463 } 464 465 // update range and position of the scrollbars 466 updateScrollbars(); 467 } 468 469 updateScrollbars()470 void RichTextControlImpl::updateScrollbars() 471 { 472 if ( m_pVScroll ) 473 { 474 tools::Long nOverallTextHeight = m_pEngine->GetTextHeight(); 475 m_pVScroll->SetRange( Range( 0, nOverallTextHeight ) ); 476 m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() ); 477 } 478 479 if ( m_pHScroll ) 480 { 481 Size aPaperSize( m_pEngine->GetPaperSize() ); 482 tools::Long nOverallTextWidth = ( aPaperSize.Width() == EMPTY_PAPER_SIZE ) ? m_pEngine->CalcTextWidth() : aPaperSize.Width(); 483 m_pHScroll->SetRange( Range( 0, nOverallTextWidth ) ); 484 m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() ); 485 } 486 } 487 488 notifyInitShow()489 void RichTextControlImpl::notifyInitShow() 490 { 491 if ( !m_bHasEverBeenShown ) 492 { 493 m_bHasEverBeenShown = true; 494 layoutWindow(); 495 } 496 } 497 498 notifyStyleChanged()499 void RichTextControlImpl::notifyStyleChanged() 500 { 501 ensureScrollbars(); 502 ensureLineBreakSetting(); 503 } 504 505 notifyZoomChanged()506 void RichTextControlImpl::notifyZoomChanged() 507 { 508 const Fraction& rZoom = m_pAntiImpl->GetZoom(); 509 510 MapMode aMapMode( m_pAntiImpl->GetMapMode() ); 511 aMapMode.SetScaleX( rZoom ); 512 aMapMode.SetScaleY( rZoom ); 513 m_pAntiImpl->SetMapMode( aMapMode ); 514 515 m_pViewport->SetZoom( rZoom ); 516 m_pViewport->SetMapMode( aMapMode ); 517 518 layoutWindow(); 519 } 520 521 windowHasAutomaticLineBreak()522 bool RichTextControlImpl::windowHasAutomaticLineBreak() 523 { 524 return ( m_pAntiImpl->GetStyle() & WB_WORDBREAK ) != 0; 525 } 526 527 SetReadOnly(bool _bReadOnly)528 void RichTextControlImpl::SetReadOnly( bool _bReadOnly ) 529 { 530 m_pView->SetReadOnly( _bReadOnly ); 531 } 532 533 IsReadOnly() const534 bool RichTextControlImpl::IsReadOnly() const 535 { 536 return m_pView->IsReadOnly( ); 537 } 538 539 540 namespace 541 { lcl_inflate(tools::Rectangle & _rRect,tools::Long _nInflateX,tools::Long _nInflateY)542 void lcl_inflate( tools::Rectangle& _rRect, tools::Long _nInflateX, tools::Long _nInflateY ) 543 { 544 _rRect.AdjustLeft( -_nInflateX ); 545 _rRect.AdjustRight(_nInflateX ); 546 _rRect.AdjustTop( -_nInflateY ); 547 _rRect.AdjustBottom(_nInflateY ); 548 } 549 } 550 HandleCommand(const CommandEvent & _rEvent)551 bool RichTextControlImpl::HandleCommand( const CommandEvent& _rEvent ) 552 { 553 if ( ( _rEvent.GetCommand() == CommandEventId::Wheel ) 554 || ( _rEvent.GetCommand() == CommandEventId::StartAutoScroll ) 555 || ( _rEvent.GetCommand() == CommandEventId::AutoScroll ) 556 ) 557 { 558 m_pAntiImpl->HandleScrollCommand( _rEvent, m_pHScroll, m_pVScroll ); 559 return true; 560 } 561 return false; 562 } 563 564 Draw(OutputDevice * _pDev,const Point & _rPos,const Size & _rSize)565 void RichTextControlImpl::Draw( OutputDevice* _pDev, const Point& _rPos, const Size& _rSize ) 566 { 567 // need to normalize the map mode of the device - every paint operation on any device needs 568 // to use the same map mode 569 _pDev->Push( PushFlags::MAPMODE | PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); 570 571 // enforce our "normalize map mode" on the device 572 MapMode aRefMapMode( m_pEngine->GetRefDevice()->GetMapMode() ); 573 MapMode aOriginalMapMode( _pDev->GetMapMode() ); 574 MapMode aNormalizedMapMode( aRefMapMode.GetMapUnit(), aRefMapMode.GetOrigin(), aOriginalMapMode.GetScaleX(), aOriginalMapMode.GetScaleY() ); 575 _pDev->SetMapMode( aNormalizedMapMode ); 576 577 // translate coordinates 578 Point aPos( _rPos ); 579 Size aSize( _rSize ); 580 if ( aOriginalMapMode.GetMapUnit() == MapUnit::MapPixel ) 581 { 582 aPos = _pDev->PixelToLogic( _rPos, aNormalizedMapMode ); 583 aSize = _pDev->PixelToLogic( _rSize, aNormalizedMapMode ); 584 } 585 else 586 { 587 aPos = OutputDevice::LogicToLogic( _rPos, aOriginalMapMode, aNormalizedMapMode ); 588 aSize = OutputDevice::LogicToLogic( _rSize, aOriginalMapMode, aNormalizedMapMode ); 589 } 590 591 tools::Rectangle aPlayground( aPos, aSize ); 592 Size aOnePixel( _pDev->PixelToLogic( Size( 1, 1 ) ) ); 593 aPlayground.AdjustRight( -(aOnePixel.Width()) ); 594 aPlayground.AdjustBottom( -(aOnePixel.Height()) ); 595 596 // background 597 _pDev->SetLineColor(); 598 _pDev->DrawRect( aPlayground ); 599 600 // do we need to draw a border? 601 bool bBorder = ( m_pAntiImpl->GetStyle() & WB_BORDER ); 602 if ( bBorder ) 603 _pDev->SetLineColor( m_pAntiImpl->GetSettings().GetStyleSettings().GetMonoColor() ); 604 else 605 _pDev->SetLineColor(); 606 _pDev->SetFillColor( m_pAntiImpl->GetBackground().GetColor() ); 607 _pDev->DrawRect( aPlayground ); 608 609 if ( bBorder ) 610 // don't draw the text over the border 611 lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() ); 612 613 // leave a space of two pixels between the "surroundings" of the control 614 // and the content 615 lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() ); 616 lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() ); 617 618 // actually draw the content 619 m_pEngine->Draw(*_pDev, aPlayground, Point(), true); 620 621 _pDev->Pop(); 622 } 623 624 SetBackgroundColor()625 void RichTextControlImpl::SetBackgroundColor( ) 626 { 627 SetBackgroundColor( Application::GetSettings().GetStyleSettings().GetFieldColor() ); 628 } 629 630 SetBackgroundColor(const Color & _rColor)631 void RichTextControlImpl::SetBackgroundColor( const Color& _rColor ) 632 { 633 Wallpaper aWallpaper( _rColor ); 634 m_pAntiImpl->SetBackground( aWallpaper ); 635 m_pViewport->SetBackground( aWallpaper ); 636 } 637 638 SetHideInactiveSelection(bool _bHide)639 void RichTextControlImpl::SetHideInactiveSelection( bool _bHide ) 640 { 641 m_pViewport->SetHideInactiveSelection( _bHide ); 642 } 643 644 GetHideInactiveSelection() const645 bool RichTextControlImpl::GetHideInactiveSelection() const 646 { 647 return m_pViewport->GetHideInactiveSelection( ); 648 } 649 650 651 } // namespace frm 652 653 654 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 655