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