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_svx.hxx" 26 #include <com/sun/star/uno/XInterface.hpp> 27 #include <vcl/svapp.hxx> 28 29 #include <svx/unoshtxt.hxx> 30 #include <editeng/unoedhlp.hxx> 31 #include <svl/lstner.hxx> 32 #include <rtl/ref.hxx> 33 #include <osl/mutex.hxx> 34 #include <svl/hint.hxx> 35 #include <svl/style.hxx> 36 #include <svx/svdmodel.hxx> 37 #include <svx/svdoutl.hxx> 38 #include <svx/svdobj.hxx> 39 #include <svx/svdview.hxx> 40 #include <svx/svdetc.hxx> 41 #include <editeng/outliner.hxx> 42 #include <editeng/unoforou.hxx> 43 #include <editeng/unoviwou.hxx> 44 #include <editeng/outlobj.hxx> 45 #include <svx/svdotext.hxx> 46 #include <svx/svdpage.hxx> 47 #include <editeng/editeng.hxx> 48 #include <editeng/editobj.hxx> 49 50 #include <editeng/unotext.hxx> 51 #include <com/sun/star/linguistic2/XLinguServiceManager.hpp> 52 #include <comphelper/processfactory.hxx> 53 #include <vos/mutex.hxx> 54 #include <svx/sdrpaintwindow.hxx> 55 56 using namespace ::osl; 57 using namespace ::vos; 58 using namespace ::rtl; 59 60 using ::com::sun::star::uno::XInterface; 61 62 namespace css = ::com::sun::star; 63 64 65 //------------------------------------------------------------------------ 66 // SvxTextEditSourceImpl 67 //------------------------------------------------------------------------ 68 69 /** @descr 70 <p>This class essentially provides the text and view forwarders. If 71 no SdrView is given, this class handles the UNO objects, which are 72 currently not concerned with view issues. In this case, 73 GetViewForwarder() always returns NULL and the underlying 74 EditEngine of the SvxTextForwarder is a background one (i.e. not 75 the official DrawOutliner, but one created exclusively for this 76 object, with no relation to a view). 77 </p> 78 79 <p>If a SdrView is given at construction time, the caller is 80 responsible for destroying this object when the view becomes 81 invalid (the views cannot notify). If GetViewForwarder(sal_True) 82 is called, the underlying shape is put into edit mode, the view 83 forwarder returned encapsulates the OutlinerView and the next call 84 to GetTextForwarder() yields a forwarder encapsulating the actual 85 DrawOutliner. Thus, changes on that Outliner are immediately 86 reflected on the screen. If the object leaves edit mode, the old 87 behaviour is restored.</p> 88 */ 89 class SvxTextEditSourceImpl : public SfxListener, public SfxBroadcaster, public sdr::ObjectUser 90 { 91 private: 92 oslInterlockedCount maRefCount; 93 94 SdrObject* mpObject; 95 SdrText* mpText; 96 SdrView* mpView; 97 const Window* mpWindow; 98 SdrModel* mpModel; 99 SdrOutliner* mpOutliner; 100 SvxOutlinerForwarder* mpTextForwarder; 101 SvxDrawOutlinerViewForwarder* mpViewForwarder; // if non-NULL, use GetViewModeTextForwarder text forwarder 102 css::uno::Reference< css::linguistic2::XLinguServiceManager > m_xLinguServiceManager; 103 Point maTextOffset; 104 sal_Bool mbDataValid; 105 sal_Bool mbDestroyed; 106 sal_Bool mbIsLocked; 107 sal_Bool mbNeedsUpdate; 108 sal_Bool mbOldUndoMode; 109 sal_Bool mbForwarderIsEditMode; // have to reflect that, since ENDEDIT can happen more often 110 sal_Bool mbShapeIsEditMode; // #104157# only true, if HINT_BEGEDIT was received 111 sal_Bool mbNotificationsDisabled; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder) 112 113 XInterface* mpOwner; 114 SvxUnoTextRangeBaseList maTextRanges; 115 116 SvxTextForwarder* GetBackgroundTextForwarder(); 117 SvxTextForwarder* GetEditModeTextForwarder(); 118 SvxDrawOutlinerViewForwarder* CreateViewForwarder(); 119 120 void SetupOutliner(); 121 122 sal_Bool HasView() const { return mpView ? sal_True : sal_False; } 123 sal_Bool IsEditMode() const 124 { 125 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 126 return mbShapeIsEditMode && pTextObj && pTextObj->IsTextEditActive() ? sal_True : sal_False; 127 } 128 129 void dispose(); 130 131 public: 132 SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText, XInterface* pOwner ); 133 SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const Window& rWindow ); 134 ~SvxTextEditSourceImpl(); 135 136 void SAL_CALL acquire(); 137 void SAL_CALL release(); 138 139 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); 140 141 SvxEditSource* Clone() const; 142 SvxTextForwarder* GetTextForwarder(); 143 SvxEditViewForwarder* GetEditViewForwarder( sal_Bool ); 144 void UpdateData(); 145 146 void addRange( SvxUnoTextRangeBase* pNewRange ); 147 void removeRange( SvxUnoTextRangeBase* pOldRange ); 148 const SvxUnoTextRangeBaseList& getRanges() const; 149 150 SdrObject* GetSdrObject() const { return mpObject; } 151 152 void lock(); 153 void unlock(); 154 155 sal_Bool IsValid() const; 156 157 Rectangle GetVisArea(); 158 Point LogicToPixel( const Point&, const MapMode& rMapMode ); 159 Point PixelToLogic( const Point&, const MapMode& rMapMode ); 160 161 DECL_LINK( NotifyHdl, EENotify* ); 162 163 virtual void ObjectInDestruction(const SdrObject& rObject); 164 165 void ChangeModel( SdrModel* pNewModel ); 166 167 void UpdateOutliner(); 168 }; 169 170 //------------------------------------------------------------------------ 171 172 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText, XInterface* pOwner ) 173 : maRefCount ( 0 ), 174 mpObject ( pObject ), 175 mpText ( pText ), 176 mpView ( NULL ), 177 mpWindow ( NULL ), 178 mpModel ( pObject ? pObject->GetModel() : NULL ), 179 mpOutliner ( NULL ), 180 mpTextForwarder ( NULL ), 181 mpViewForwarder ( NULL ), 182 mbDataValid ( sal_False ), 183 mbDestroyed ( sal_False ), 184 mbIsLocked ( sal_False ), 185 mbNeedsUpdate ( sal_False ), 186 mbOldUndoMode ( sal_False ), 187 mbForwarderIsEditMode ( sal_False ), 188 mbShapeIsEditMode ( sal_False ), 189 mbNotificationsDisabled ( sal_False ), 190 mpOwner( pOwner ) 191 { 192 DBG_ASSERT( mpObject, "invalid pObject!" ); 193 194 if( !mpText ) 195 { 196 SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject ); 197 if( pTextObj ) 198 mpText = pTextObj->getText( 0 ); 199 } 200 201 if( mpModel ) 202 StartListening( *mpModel ); 203 204 if( mpObject ) 205 mpObject->AddObjectUser( *this ); 206 } 207 208 //------------------------------------------------------------------------ 209 210 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const Window& rWindow ) 211 : maRefCount ( 0 ), 212 mpObject ( &rObject ), 213 mpText ( pText ), 214 mpView ( &rView ), 215 mpWindow ( &rWindow ), 216 mpModel ( rObject.GetModel() ), 217 mpOutliner ( NULL ), 218 mpTextForwarder ( NULL ), 219 mpViewForwarder ( NULL ), 220 mbDataValid ( sal_False ), 221 mbDestroyed ( sal_False ), 222 mbIsLocked ( sal_False ), 223 mbNeedsUpdate ( sal_False ), 224 mbOldUndoMode ( sal_False ), 225 mbForwarderIsEditMode ( sal_False ), 226 mbShapeIsEditMode ( sal_True ), 227 mbNotificationsDisabled ( sal_False ), 228 mpOwner(0) 229 { 230 if( !mpText ) 231 { 232 SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject ); 233 if( pTextObj ) 234 mpText = pTextObj->getText( 0 ); 235 } 236 237 if( mpModel ) 238 StartListening( *mpModel ); 239 if( mpView ) 240 StartListening( *mpView ); 241 if( mpObject ) 242 mpObject->AddObjectUser( *this ); 243 244 // #104157# Init edit mode state from shape info (IsTextEditActive()) 245 mbShapeIsEditMode = IsEditMode(); 246 } 247 248 //------------------------------------------------------------------------ 249 250 SvxTextEditSourceImpl::~SvxTextEditSourceImpl() 251 { 252 DBG_ASSERT( mbIsLocked == sal_False, "text edit source was not unlocked before dispose!" ); 253 if( mpObject ) 254 mpObject->RemoveObjectUser( *this ); 255 256 dispose(); 257 } 258 259 //------------------------------------------------------------------------ 260 261 void SvxTextEditSourceImpl::addRange( SvxUnoTextRangeBase* pNewRange ) 262 { 263 if( pNewRange ) 264 if( std::find( maTextRanges.begin(), maTextRanges.end(), pNewRange ) == maTextRanges.end() ) 265 maTextRanges.push_back( pNewRange ); 266 } 267 268 //------------------------------------------------------------------------ 269 270 void SvxTextEditSourceImpl::removeRange( SvxUnoTextRangeBase* pOldRange ) 271 { 272 if( pOldRange ) 273 maTextRanges.remove( pOldRange ); 274 } 275 276 //------------------------------------------------------------------------ 277 278 const SvxUnoTextRangeBaseList& SvxTextEditSourceImpl::getRanges() const 279 { 280 return maTextRanges; 281 } 282 283 //------------------------------------------------------------------------ 284 285 void SAL_CALL SvxTextEditSourceImpl::acquire() 286 { 287 osl_incrementInterlockedCount( &maRefCount ); 288 } 289 290 //------------------------------------------------------------------------ 291 292 void SAL_CALL SvxTextEditSourceImpl::release() 293 { 294 if( ! osl_decrementInterlockedCount( &maRefCount ) ) 295 delete this; 296 } 297 298 void SvxTextEditSourceImpl::ChangeModel( SdrModel* pNewModel ) 299 { 300 if( mpModel != pNewModel ) 301 { 302 if( mpModel ) 303 EndListening( *mpModel ); 304 305 if( mpOutliner ) 306 { 307 if( mpModel ) 308 mpModel->disposeOutliner( mpOutliner ); 309 else 310 delete mpOutliner; 311 mpOutliner = 0; 312 } 313 314 if( mpView ) 315 { 316 EndListening( *mpView ); 317 mpView = 0; 318 } 319 320 mpWindow = 0; 321 m_xLinguServiceManager.clear(); 322 mpOwner = 0; 323 324 mpModel = pNewModel; 325 326 if( mpTextForwarder ) 327 { 328 delete mpTextForwarder; 329 mpTextForwarder = 0; 330 } 331 332 if( mpViewForwarder ) 333 { 334 delete mpViewForwarder; 335 mpViewForwarder = 0; 336 } 337 338 if( mpModel ) 339 StartListening( *mpModel ); 340 } 341 } 342 343 //------------------------------------------------------------------------ 344 345 void SvxTextEditSourceImpl::Notify( SfxBroadcaster&, const SfxHint& rHint ) 346 { 347 // #i105988 keep reference to this object 348 rtl::Reference< SvxTextEditSourceImpl > xThis( this ); 349 350 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); 351 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint ); 352 353 if( pViewHint ) 354 { 355 switch( pViewHint->GetHintType() ) 356 { 357 case SvxViewHint::SVX_HINT_VIEWCHANGED: 358 Broadcast( *pViewHint ); 359 break; 360 } 361 } 362 else if( pSdrHint ) 363 { 364 switch( pSdrHint->GetKind() ) 365 { 366 case HINT_OBJCHG: 367 { 368 mbDataValid = sal_False; // Text muss neu geholt werden 369 370 if( HasView() ) 371 { 372 // #104157# Update maTextOffset, object has changed 373 // #105196#, #105203#: Cannot call that // here, 374 // since TakeTextRect() (called from there) // 375 // changes outliner content. 376 // UpdateOutliner(); 377 378 // #101029# Broadcast object changes, as they might change visible attributes 379 SvxViewHint aHint(SvxViewHint::SVX_HINT_VIEWCHANGED); 380 Broadcast( aHint ); 381 } 382 break; 383 } 384 385 case HINT_BEGEDIT: 386 if( mpObject == pSdrHint->GetObject() ) 387 { 388 // invalidate old forwarder 389 if( !mbForwarderIsEditMode ) 390 { 391 delete mpTextForwarder; 392 mpTextForwarder = NULL; 393 } 394 395 // register as listener - need to broadcast state change messages 396 if( mpView && mpView->GetTextEditOutliner() ) 397 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 398 399 // #104157# Only now we're really in edit mode 400 mbShapeIsEditMode = sal_True; 401 402 Broadcast( *pSdrHint ); 403 } 404 break; 405 406 case HINT_ENDEDIT: 407 if( mpObject == pSdrHint->GetObject() ) 408 { 409 Broadcast( *pSdrHint ); 410 411 // #104157# We're no longer in edit mode 412 mbShapeIsEditMode = sal_False; 413 414 // remove as listener - outliner might outlive ourselves 415 if( mpView && mpView->GetTextEditOutliner() ) 416 mpView->GetTextEditOutliner()->SetNotifyHdl( Link() ); 417 418 // destroy view forwarder, OutlinerView no longer 419 // valid (no need for UpdateData(), it's been 420 // synched on SdrEndTextEdit) 421 delete mpViewForwarder; 422 mpViewForwarder = NULL; 423 424 // #100424# Invalidate text forwarder, we might 425 // not be called again before entering edit mode a 426 // second time! Then, the old outliner might be 427 // invalid. 428 if( mbForwarderIsEditMode ) 429 { 430 mbForwarderIsEditMode = sal_False; 431 delete mpTextForwarder; 432 mpTextForwarder = NULL; 433 } 434 } 435 break; 436 437 case HINT_MODELCLEARED: 438 dispose(); 439 break; 440 default: 441 break; 442 } 443 } 444 } 445 446 /* this is a callback from the attached SdrObject when it is actually deleted */ 447 void SvxTextEditSourceImpl::ObjectInDestruction(const SdrObject&) 448 { 449 mpObject = 0; 450 dispose(); 451 Broadcast( SfxSimpleHint( SFX_HINT_DYING ) ); 452 } 453 454 /* unregister at all objects and set all references to 0 */ 455 void SvxTextEditSourceImpl::dispose() 456 { 457 if( mpTextForwarder ) 458 { 459 delete mpTextForwarder; 460 mpTextForwarder = 0; 461 } 462 463 if( mpViewForwarder ) 464 { 465 delete mpViewForwarder; 466 mpViewForwarder = 0; 467 } 468 469 if( mpOutliner ) 470 { 471 if( mpModel ) 472 { 473 mpModel->disposeOutliner( mpOutliner ); 474 } 475 else 476 { 477 delete mpOutliner; 478 } 479 mpOutliner = 0; 480 } 481 482 if( mpModel ) 483 { 484 EndListening( *mpModel ); 485 mpModel = 0; 486 } 487 488 if( mpView ) 489 { 490 EndListening( *mpView ); 491 mpView = 0; 492 } 493 494 if( mpObject ) 495 { 496 mpObject->RemoveObjectUser( *this ); 497 mpObject = 0; 498 } 499 mpWindow = 0; 500 } 501 502 //------------------------------------------------------------------------ 503 504 void SvxTextEditSourceImpl::SetupOutliner() 505 { 506 // #101029# 507 // only for UAA edit source: setup outliner equivalently as in 508 // SdrTextObj::Paint(), such that formatting equals screen 509 // layout 510 if( mpObject && mpOutliner ) 511 { 512 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 513 Rectangle aPaintRect; 514 if( pTextObj ) 515 { 516 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 517 pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect ); 518 519 // #101029# calc text offset from shape anchor 520 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); 521 } 522 } 523 } 524 525 //------------------------------------------------------------------------ 526 527 void SvxTextEditSourceImpl::UpdateOutliner() 528 { 529 // #104157# 530 // only for UAA edit source: update outliner equivalently as in 531 // SdrTextObj::Paint(), such that formatting equals screen 532 // layout 533 if( mpObject && mpOutliner ) 534 { 535 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 536 Rectangle aPaintRect; 537 if( pTextObj ) 538 { 539 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 540 pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect ); 541 542 // #101029# calc text offset from shape anchor 543 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); 544 } 545 } 546 } 547 548 //------------------------------------------------------------------------ 549 550 551 552 SvxTextForwarder* SvxTextEditSourceImpl::GetBackgroundTextForwarder() 553 { 554 sal_Bool bCreated = sal_False; 555 556 // #99840#: prevent EE/Outliner notifications during setup 557 mbNotificationsDisabled = sal_True; 558 559 if (!mpTextForwarder) 560 { 561 if( mpOutliner == NULL ) 562 { 563 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 564 sal_uInt16 nOutlMode = OUTLINERMODE_TEXTOBJECT; 565 if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == OBJ_OUTLINETEXT ) 566 nOutlMode = OUTLINERMODE_OUTLINEOBJECT; 567 568 mpOutliner = mpModel->createOutliner( nOutlMode ); 569 570 // #109151# Do the setup after outliner creation, would be useless otherwise 571 if( HasView() ) 572 { 573 // #101029#, #104157# Setup outliner _before_ filling it 574 SetupOutliner(); 575 } 576 577 mpOutliner->SetTextObjNoInit( pTextObj ); 578 /* 579 mpOutliner = SdrMakeOutliner( nOutlMode, pModel ); 580 Outliner& aDrawOutliner = pModel->GetDrawOutliner(); 581 mpOutliner->SetCalcFieldValueHdl( aDrawOutliner.GetCalcFieldValueHdl() ); 582 */ 583 if( mbIsLocked ) 584 { 585 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); 586 mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); 587 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); 588 } 589 590 // - 591 if ( !m_xLinguServiceManager.is() ) 592 { 593 css::uno::Reference< css::lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); 594 m_xLinguServiceManager = css::uno::Reference< css::linguistic2::XLinguServiceManager >( 595 xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.linguistic2.LinguServiceManager" ))), css::uno::UNO_QUERY ); 596 } 597 598 if ( m_xLinguServiceManager.is() ) 599 { 600 css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator( m_xLinguServiceManager->getHyphenator(), css::uno::UNO_QUERY ); 601 if( xHyphenator.is() ) 602 mpOutliner->SetHyphenator( xHyphenator ); 603 } 604 // - 605 } 606 607 608 mpTextForwarder = new SvxOutlinerForwarder( *mpOutliner, (mpObject->GetObjInventor() == SdrInventor) && (mpObject->GetObjIdentifier() == OBJ_OUTLINETEXT) ); 609 // delay listener subscription and UAA initialization until Outliner is fully setup 610 bCreated = sal_True; 611 612 mbForwarderIsEditMode = sal_False; 613 } 614 615 if( mpObject && mpText && !mbDataValid && mpObject->IsInserted() && mpObject->GetPage() ) 616 { 617 mpTextForwarder->flushCache(); 618 619 OutlinerParaObject* pOutlinerParaObject = NULL; 620 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 621 if( pTextObj && pTextObj->getActiveText() == mpText ) 622 pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active 623 bool bOwnParaObj(false); 624 625 if( pOutlinerParaObject ) 626 bOwnParaObj = true; // text edit active 627 else 628 pOutlinerParaObject = mpText->GetOutlinerParaObject(); 629 630 if( pOutlinerParaObject && ( bOwnParaObj || !mpObject->IsEmptyPresObj() || mpObject->GetPage()->IsMasterPage() ) ) 631 { 632 mpOutliner->SetText( *pOutlinerParaObject ); 633 634 // #91254# put text to object and set EmptyPresObj to FALSE 635 if( mpText && bOwnParaObj && pOutlinerParaObject && mpObject->IsEmptyPresObj() && pTextObj->IsRealyEdited() ) 636 { 637 mpObject->SetEmptyPresObj( sal_False ); 638 static_cast< SdrTextObj* >( mpObject)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject, mpText ); 639 640 // #i103982# Here, due to mpObject->NbcSetOutlinerParaObjectForText, we LOSE ownership of the 641 // OPO, so do NOT delete it when leaving this method (!) 642 bOwnParaObj = false; 643 } 644 } 645 else 646 { 647 sal_Bool bVertical = pOutlinerParaObject ? pOutlinerParaObject->IsVertical() : sal_False; 648 649 // set objects style sheet on empty outliner 650 SfxStyleSheetPool* pPool = (SfxStyleSheetPool*)mpObject->GetModel()->GetStyleSheetPool(); 651 if( pPool ) 652 mpOutliner->SetStyleSheetPool( pPool ); 653 654 SfxStyleSheet* pStyleSheet = mpObject->GetPage()->GetTextStyleSheetForObject( mpObject ); 655 if( pStyleSheet ) 656 mpOutliner->SetStyleSheet( 0, pStyleSheet ); 657 658 if( bVertical ) 659 mpOutliner->SetVertical( sal_True ); 660 } 661 662 // evtually we have to set the border attributes 663 if (mpOutliner->GetParagraphCount()==1) 664 { 665 // if we only have one paragraph we check if it is empty 666 XubString aStr( mpOutliner->GetText( mpOutliner->GetParagraph( 0 ) ) ); 667 668 if(!aStr.Len()) 669 { 670 // its empty, so we have to force the outliner to initialise itself 671 mpOutliner->SetText( String(), mpOutliner->GetParagraph( 0 ) ); 672 673 if(mpObject->GetStyleSheet()) 674 mpOutliner->SetStyleSheet( 0, mpObject->GetStyleSheet()); 675 } 676 } 677 678 mbDataValid = sal_True; 679 680 if( bOwnParaObj ) 681 delete pOutlinerParaObject; 682 } 683 684 if( bCreated && mpOutliner && HasView() ) 685 { 686 // register as listener - need to broadcast state change messages 687 // registration delayed until outliner is completely set up 688 mpOutliner->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 689 } 690 691 // #99840#: prevent EE/Outliner notifications during setup 692 mbNotificationsDisabled = sal_False; 693 694 return mpTextForwarder; 695 } 696 697 //------------------------------------------------------------------------ 698 699 SvxTextForwarder* SvxTextEditSourceImpl::GetEditModeTextForwarder() 700 { 701 if( !mpTextForwarder && HasView() ) 702 { 703 SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner(); 704 705 if( pEditOutliner ) 706 { 707 mpTextForwarder = new SvxOutlinerForwarder( *pEditOutliner, (mpObject->GetObjInventor() == SdrInventor) && (mpObject->GetObjIdentifier() == OBJ_OUTLINETEXT) ); 708 mbForwarderIsEditMode = sal_True; 709 } 710 } 711 712 return mpTextForwarder; 713 } 714 715 //------------------------------------------------------------------------ 716 717 SvxTextForwarder* SvxTextEditSourceImpl::GetTextForwarder() 718 { 719 if( mbDestroyed || mpObject == NULL ) 720 return NULL; 721 722 if( mpModel == NULL ) 723 mpModel = mpObject->GetModel(); 724 725 if( mpModel == NULL ) 726 return NULL; 727 728 // distinguish the cases 729 // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner 730 // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code) 731 if( HasView() ) 732 { 733 if( IsEditMode() != mbForwarderIsEditMode ) 734 { 735 // forwarder mismatch - create new 736 delete mpTextForwarder; 737 mpTextForwarder = NULL; 738 } 739 740 if( IsEditMode() ) 741 return GetEditModeTextForwarder(); 742 else 743 return GetBackgroundTextForwarder(); 744 } 745 else 746 return GetBackgroundTextForwarder(); 747 } 748 749 //------------------------------------------------------------------------ 750 751 SvxDrawOutlinerViewForwarder* SvxTextEditSourceImpl::CreateViewForwarder() 752 { 753 if( mpView->GetTextEditOutlinerView() && mpObject ) 754 { 755 // register as listener - need to broadcast state change messages 756 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 757 758 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 759 if( pTextObj ) 760 { 761 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 762 OutlinerView& rOutlView = *mpView->GetTextEditOutlinerView(); 763 764 return new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ); 765 } 766 } 767 768 return NULL; 769 } 770 771 SvxEditViewForwarder* SvxTextEditSourceImpl::GetEditViewForwarder( sal_Bool bCreate ) 772 { 773 if( mbDestroyed || mpObject == NULL ) 774 return NULL; 775 776 if( mpModel == NULL ) 777 mpModel = mpObject->GetModel(); 778 779 if( mpModel == NULL ) 780 return NULL; 781 782 // shall we delete? 783 if( mpViewForwarder ) 784 { 785 if( !IsEditMode() ) 786 { 787 // destroy all forwarders (no need for UpdateData(), 788 // it's been synched on SdrEndTextEdit) 789 delete mpViewForwarder; 790 mpViewForwarder = NULL; 791 } 792 } 793 // which to create? Directly in edit mode, create new, or none? 794 else if( mpView ) 795 { 796 if( IsEditMode() ) 797 { 798 // create new view forwarder 799 mpViewForwarder = CreateViewForwarder(); 800 } 801 else if( bCreate ) 802 { 803 // dispose old text forwarder 804 UpdateData(); 805 806 delete mpTextForwarder; 807 mpTextForwarder = NULL; 808 809 // enter edit mode 810 mpView->SdrEndTextEdit(); 811 812 if(mpView->SdrBeginTextEdit(mpObject, 0L, 0L, sal_False, (SdrOutliner*)0L, 0L, sal_False, sal_False)) 813 { 814 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 815 if( pTextObj->IsTextEditActive() ) 816 { 817 // create new view forwarder 818 mpViewForwarder = CreateViewForwarder(); 819 } 820 else 821 { 822 // failure. Somehow, SdrBeginTextEdit did not set 823 // our SdrTextObj into edit mode 824 mpView->SdrEndTextEdit(); 825 } 826 } 827 } 828 } 829 830 return mpViewForwarder; 831 } 832 833 //------------------------------------------------------------------------ 834 835 void SvxTextEditSourceImpl::UpdateData() 836 { 837 // if we have a view and in edit mode, we're working with the 838 // DrawOutliner. Thus, all changes made on the text forwarder are 839 // reflected on the view and committed to the model on 840 // SdrEndTextEdit(). Thus, no need for explicit updates here. 841 if( !HasView() || !IsEditMode() ) 842 { 843 if( mbIsLocked ) 844 { 845 mbNeedsUpdate = sal_True; 846 } 847 else 848 { 849 if( mpOutliner && mpObject && mpText && !mbDestroyed ) 850 { 851 SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject ); 852 if( pTextObj ) 853 { 854 if( mpOutliner->GetParagraphCount() != 1 || mpOutliner->GetEditEngine().GetTextLen( 0 ) ) 855 { 856 if( mpOutliner->GetParagraphCount() > 1 ) 857 { 858 if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == OBJ_TITLETEXT ) 859 { 860 while( mpOutliner->GetParagraphCount() > 1 ) 861 { 862 ESelection aSel( 0,mpOutliner->GetEditEngine().GetTextLen( 0 ), 1,0 ); 863 mpOutliner->QuickInsertLineBreak( aSel ); 864 } 865 } 866 } 867 868 pTextObj->NbcSetOutlinerParaObjectForText( mpOutliner->CreateParaObject(), mpText ); 869 } 870 else 871 { 872 pTextObj->NbcSetOutlinerParaObjectForText( NULL,mpText ); 873 } 874 } 875 876 if( mpObject->IsEmptyPresObj() ) 877 mpObject->SetEmptyPresObj(sal_False); 878 } 879 } 880 } 881 } 882 883 void SvxTextEditSourceImpl::lock() 884 { 885 mbIsLocked = sal_True; 886 if( mpOutliner ) 887 { 888 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); 889 mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); 890 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); 891 } 892 } 893 894 void SvxTextEditSourceImpl::unlock() 895 { 896 mbIsLocked = sal_False; 897 898 if( mbNeedsUpdate ) 899 { 900 UpdateData(); 901 mbNeedsUpdate = sal_False; 902 } 903 904 if( mpOutliner ) 905 { 906 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_True ); 907 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode ); 908 } 909 } 910 911 sal_Bool SvxTextEditSourceImpl::IsValid() const 912 { 913 return mpView && mpWindow ? sal_True : sal_False; 914 } 915 916 Rectangle SvxTextEditSourceImpl::GetVisArea() 917 { 918 if( IsValid() ) 919 { 920 SdrPaintWindow* pPaintWindow = mpView->FindPaintWindow(*mpWindow); 921 Rectangle aVisArea; 922 923 if(pPaintWindow) 924 { 925 aVisArea = pPaintWindow->GetVisibleArea(); 926 } 927 928 // offset vis area by edit engine left-top position 929 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 930 if( pTextObj ) 931 { 932 Rectangle aAnchorRect; 933 pTextObj->TakeTextAnchorRect( aAnchorRect ); 934 aVisArea.Move( -aAnchorRect.Left(), -aAnchorRect.Top() ); 935 936 MapMode aMapMode(mpWindow->GetMapMode()); 937 aMapMode.SetOrigin(Point()); 938 return mpWindow->LogicToPixel( aVisArea, aMapMode ); 939 } 940 } 941 942 return Rectangle(); 943 } 944 945 Point SvxTextEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) 946 { 947 // #101029#: The responsibilities of ViewForwarder happen to be 948 // somewhat mixed in this case. On the one hand, we need the 949 // different interface queries on the SvxEditSource interface, 950 // since we need both VisAreas. On the other hand, if an 951 // EditViewForwarder exists, maTextOffset does not remain static, 952 // but may change with every key press. 953 if( IsEditMode() ) 954 { 955 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); 956 957 if( pForwarder ) 958 return pForwarder->LogicToPixel( rPoint, rMapMode ); 959 } 960 else if( IsValid() && mpModel ) 961 { 962 // #101029# 963 Point aPoint1( rPoint ); 964 aPoint1.X() += maTextOffset.X(); 965 aPoint1.Y() += maTextOffset.Y(); 966 967 Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode, 968 MapMode(mpModel->GetScaleUnit()) ) ); 969 MapMode aMapMode(mpWindow->GetMapMode()); 970 aMapMode.SetOrigin(Point()); 971 return mpWindow->LogicToPixel( aPoint2, aMapMode ); 972 } 973 974 return Point(); 975 } 976 977 Point SvxTextEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) 978 { 979 // #101029#: The responsibilities of ViewForwarder happen to be 980 // somewhat mixed in this case. On the one hand, we need the 981 // different interface queries on the SvxEditSource interface, 982 // since we need both VisAreas. On the other hand, if an 983 // EditViewForwarder exists, maTextOffset does not remain static, 984 // but may change with every key press. 985 if( IsEditMode() ) 986 { 987 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); 988 989 if( pForwarder ) 990 return pForwarder->PixelToLogic( rPoint, rMapMode ); 991 } 992 else if( IsValid() && mpModel ) 993 { 994 MapMode aMapMode(mpWindow->GetMapMode()); 995 aMapMode.SetOrigin(Point()); 996 Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) ); 997 Point aPoint2( OutputDevice::LogicToLogic( aPoint1, 998 MapMode(mpModel->GetScaleUnit()), 999 rMapMode ) ); 1000 // #101029# 1001 aPoint2.X() -= maTextOffset.X(); 1002 aPoint2.Y() -= maTextOffset.Y(); 1003 1004 return aPoint2; 1005 } 1006 1007 return Point(); 1008 } 1009 1010 IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify*, aNotify) 1011 { 1012 if( aNotify && !mbNotificationsDisabled ) 1013 { 1014 ::std::auto_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( aNotify) ); 1015 1016 if( aHint.get() ) 1017 Broadcast( *aHint.get() ); 1018 } 1019 1020 return 0; 1021 } 1022 1023 //------------------------------------------------------------------------ 1024 1025 // -------------------------------------------------------------------- 1026 // SvxTextEditSource 1027 // -------------------------------------------------------------------- 1028 1029 SvxTextEditSource::SvxTextEditSource( SdrObject* pObject, SdrText* pText, XInterface* pOwner ) 1030 { 1031 mpImpl = new SvxTextEditSourceImpl( pObject, pText, pOwner ); 1032 mpImpl->acquire(); 1033 } 1034 1035 // -------------------------------------------------------------------- 1036 SvxTextEditSource::SvxTextEditSource( SdrObject& rObj, SdrText* pText, SdrView& rView, const Window& rWindow ) 1037 { 1038 mpImpl = new SvxTextEditSourceImpl( rObj, pText, rView, rWindow ); 1039 mpImpl->acquire(); 1040 } 1041 1042 // -------------------------------------------------------------------- 1043 1044 SvxTextEditSource::SvxTextEditSource( SvxTextEditSourceImpl* pImpl ) 1045 { 1046 mpImpl = pImpl; 1047 mpImpl->acquire(); 1048 } 1049 1050 //------------------------------------------------------------------------ 1051 SvxTextEditSource::~SvxTextEditSource() 1052 { 1053 OGuard aGuard( Application::GetSolarMutex() ); 1054 1055 mpImpl->release(); 1056 } 1057 1058 //------------------------------------------------------------------------ 1059 SvxEditSource* SvxTextEditSource::Clone() const 1060 { 1061 return new SvxTextEditSource( mpImpl ); 1062 } 1063 1064 //------------------------------------------------------------------------ 1065 SvxTextForwarder* SvxTextEditSource::GetTextForwarder() 1066 { 1067 return mpImpl->GetTextForwarder(); 1068 } 1069 1070 //------------------------------------------------------------------------ 1071 SvxEditViewForwarder* SvxTextEditSource::GetEditViewForwarder( sal_Bool bCreate ) 1072 { 1073 return mpImpl->GetEditViewForwarder( bCreate ); 1074 } 1075 1076 //------------------------------------------------------------------------ 1077 SvxViewForwarder* SvxTextEditSource::GetViewForwarder() 1078 { 1079 return this; 1080 } 1081 1082 //------------------------------------------------------------------------ 1083 void SvxTextEditSource::UpdateData() 1084 { 1085 mpImpl->UpdateData(); 1086 } 1087 1088 SfxBroadcaster& SvxTextEditSource::GetBroadcaster() const 1089 { 1090 return *mpImpl; 1091 } 1092 1093 SdrObject* SvxTextEditSource::GetSdrObject() const 1094 { 1095 return mpImpl->GetSdrObject(); 1096 } 1097 1098 void SvxTextEditSource::lock() 1099 { 1100 mpImpl->lock(); 1101 } 1102 1103 void SvxTextEditSource::unlock() 1104 { 1105 mpImpl->unlock(); 1106 } 1107 1108 sal_Bool SvxTextEditSource::IsValid() const 1109 { 1110 return mpImpl->IsValid(); 1111 } 1112 1113 Rectangle SvxTextEditSource::GetVisArea() const 1114 { 1115 return mpImpl->GetVisArea(); 1116 } 1117 1118 Point SvxTextEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const 1119 { 1120 return mpImpl->LogicToPixel( rPoint, rMapMode ); 1121 } 1122 1123 Point SvxTextEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const 1124 { 1125 return mpImpl->PixelToLogic( rPoint, rMapMode ); 1126 } 1127 1128 void SvxTextEditSource::addRange( SvxUnoTextRangeBase* pNewRange ) 1129 { 1130 mpImpl->addRange( pNewRange ); 1131 } 1132 1133 void SvxTextEditSource::removeRange( SvxUnoTextRangeBase* pOldRange ) 1134 { 1135 mpImpl->removeRange( pOldRange ); 1136 } 1137 1138 const SvxUnoTextRangeBaseList& SvxTextEditSource::getRanges() const 1139 { 1140 return mpImpl->getRanges(); 1141 } 1142 1143 void SvxTextEditSource::ChangeModel( SdrModel* pNewModel ) 1144 { 1145 mpImpl->ChangeModel( pNewModel ); 1146 } 1147 1148 void SvxTextEditSource::UpdateOutliner() 1149 { 1150 mpImpl->UpdateOutliner(); 1151 } 1152