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 55 #include <svx/svdotable.hxx> 56 #include <../table/cell.hxx> 57 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 //IAccessibility2 Implementation 2009-----, one EditSource object is created for each AccessibleCell, and it will monitor the hint. 393 // Once HINT_BEGEDIT is broadcast, each EditSource of AccessibleCell will handle it here and 394 // call below: mpView->GetTextEditOutliner()->SetNotifyHdl(), which will replace the Notifer for current 395 // editable cell. It is totally wrong. So add check here to avoid the incorrect replacement of notifer. 396 // To be safe, add accessibility check here because currently it only happen on the editsource of AccessibleCell 397 if (Application::IsAccessibilityEnabled()) 398 { 399 if (mpObject && mpText) 400 { 401 sdr::table::SdrTableObj* pTableObj = PTR_CAST( sdr::table::SdrTableObj, mpObject ); 402 if(pTableObj) 403 { 404 sdr::table::CellRef xCell = pTableObj->getActiveCell(); 405 if (xCell.is()) 406 { 407 sdr::table::Cell* pCellObj = dynamic_cast< sdr::table::Cell* >( mpText ); 408 if (pCellObj && xCell.get() != pCellObj) 409 break; 410 } 411 } 412 } 413 } 414 // invalidate old forwarder 415 if( !mbForwarderIsEditMode ) 416 { 417 delete mpTextForwarder; 418 mpTextForwarder = NULL; 419 } 420 421 // register as listener - need to broadcast state change messages 422 if( mpView && mpView->GetTextEditOutliner() ) 423 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 424 425 // #104157# Only now we're really in edit mode 426 mbShapeIsEditMode = sal_True; 427 428 Broadcast( *pSdrHint ); 429 } 430 break; 431 432 case HINT_ENDEDIT: 433 if( mpObject == pSdrHint->GetObject() ) 434 { 435 Broadcast( *pSdrHint ); 436 437 // #104157# We're no longer in edit mode 438 mbShapeIsEditMode = sal_False; 439 440 // remove as listener - outliner might outlive ourselves 441 if( mpView && mpView->GetTextEditOutliner() ) 442 mpView->GetTextEditOutliner()->SetNotifyHdl( Link() ); 443 444 // destroy view forwarder, OutlinerView no longer 445 // valid (no need for UpdateData(), it's been 446 // synched on SdrEndTextEdit) 447 delete mpViewForwarder; 448 mpViewForwarder = NULL; 449 450 // #100424# Invalidate text forwarder, we might 451 // not be called again before entering edit mode a 452 // second time! Then, the old outliner might be 453 // invalid. 454 if( mbForwarderIsEditMode ) 455 { 456 mbForwarderIsEditMode = sal_False; 457 delete mpTextForwarder; 458 mpTextForwarder = NULL; 459 } 460 } 461 break; 462 463 case HINT_MODELCLEARED: 464 dispose(); 465 break; 466 default: 467 break; 468 } 469 } 470 } 471 472 /* this is a callback from the attached SdrObject when it is actually deleted */ 473 void SvxTextEditSourceImpl::ObjectInDestruction(const SdrObject&) 474 { 475 mpObject = 0; 476 dispose(); 477 Broadcast( SfxSimpleHint( SFX_HINT_DYING ) ); 478 } 479 480 /* unregister at all objects and set all references to 0 */ 481 void SvxTextEditSourceImpl::dispose() 482 { 483 if( mpTextForwarder ) 484 { 485 delete mpTextForwarder; 486 mpTextForwarder = 0; 487 } 488 489 if( mpViewForwarder ) 490 { 491 delete mpViewForwarder; 492 mpViewForwarder = 0; 493 } 494 495 if( mpOutliner ) 496 { 497 if( mpModel ) 498 { 499 mpModel->disposeOutliner( mpOutliner ); 500 } 501 else 502 { 503 delete mpOutliner; 504 } 505 mpOutliner = 0; 506 } 507 508 if( mpModel ) 509 { 510 EndListening( *mpModel ); 511 mpModel = 0; 512 } 513 514 if( mpView ) 515 { 516 EndListening( *mpView ); 517 mpView = 0; 518 } 519 520 if( mpObject ) 521 { 522 mpObject->RemoveObjectUser( *this ); 523 mpObject = 0; 524 } 525 mpWindow = 0; 526 } 527 528 //------------------------------------------------------------------------ 529 530 void SvxTextEditSourceImpl::SetupOutliner() 531 { 532 // #101029# 533 // only for UAA edit source: setup outliner equivalently as in 534 // SdrTextObj::Paint(), such that formatting equals screen 535 // layout 536 if( mpObject && mpOutliner ) 537 { 538 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 539 Rectangle aPaintRect; 540 if( pTextObj ) 541 { 542 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 543 pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect ); 544 545 // #101029# calc text offset from shape anchor 546 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); 547 } 548 } 549 } 550 551 //------------------------------------------------------------------------ 552 553 void SvxTextEditSourceImpl::UpdateOutliner() 554 { 555 // #104157# 556 // only for UAA edit source: update outliner equivalently as in 557 // SdrTextObj::Paint(), such that formatting equals screen 558 // layout 559 if( mpObject && mpOutliner ) 560 { 561 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 562 Rectangle aPaintRect; 563 if( pTextObj ) 564 { 565 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 566 pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect ); 567 568 // #101029# calc text offset from shape anchor 569 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); 570 } 571 } 572 } 573 574 //------------------------------------------------------------------------ 575 576 577 578 SvxTextForwarder* SvxTextEditSourceImpl::GetBackgroundTextForwarder() 579 { 580 sal_Bool bCreated = sal_False; 581 582 // #99840#: prevent EE/Outliner notifications during setup 583 mbNotificationsDisabled = sal_True; 584 585 if (!mpTextForwarder) 586 { 587 if( mpOutliner == NULL ) 588 { 589 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 590 sal_uInt16 nOutlMode = OUTLINERMODE_TEXTOBJECT; 591 if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == OBJ_OUTLINETEXT ) 592 nOutlMode = OUTLINERMODE_OUTLINEOBJECT; 593 594 mpOutliner = mpModel->createOutliner( nOutlMode ); 595 596 // #109151# Do the setup after outliner creation, would be useless otherwise 597 if( HasView() ) 598 { 599 // #101029#, #104157# Setup outliner _before_ filling it 600 SetupOutliner(); 601 } 602 603 mpOutliner->SetTextObjNoInit( pTextObj ); 604 /* 605 mpOutliner = SdrMakeOutliner( nOutlMode, pModel ); 606 Outliner& aDrawOutliner = pModel->GetDrawOutliner(); 607 mpOutliner->SetCalcFieldValueHdl( aDrawOutliner.GetCalcFieldValueHdl() ); 608 */ 609 if( mbIsLocked ) 610 { 611 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); 612 mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); 613 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); 614 } 615 616 // - 617 if ( !m_xLinguServiceManager.is() ) 618 { 619 css::uno::Reference< css::lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); 620 m_xLinguServiceManager = css::uno::Reference< css::linguistic2::XLinguServiceManager >( 621 xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.linguistic2.LinguServiceManager" ))), css::uno::UNO_QUERY ); 622 } 623 624 if ( m_xLinguServiceManager.is() ) 625 { 626 css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator( m_xLinguServiceManager->getHyphenator(), css::uno::UNO_QUERY ); 627 if( xHyphenator.is() ) 628 mpOutliner->SetHyphenator( xHyphenator ); 629 } 630 // - 631 } 632 633 634 mpTextForwarder = new SvxOutlinerForwarder( *mpOutliner, (mpObject->GetObjInventor() == SdrInventor) && (mpObject->GetObjIdentifier() == OBJ_OUTLINETEXT) ); 635 // delay listener subscription and UAA initialization until Outliner is fully setup 636 bCreated = sal_True; 637 638 mbForwarderIsEditMode = sal_False; 639 } 640 641 if( mpObject && mpText && !mbDataValid && mpObject->IsInserted() && mpObject->GetPage() ) 642 { 643 mpTextForwarder->flushCache(); 644 645 OutlinerParaObject* pOutlinerParaObject = NULL; 646 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 647 if( pTextObj && pTextObj->getActiveText() == mpText ) 648 pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active 649 bool bOwnParaObj(false); 650 651 if( pOutlinerParaObject ) 652 bOwnParaObj = true; // text edit active 653 else 654 pOutlinerParaObject = mpText->GetOutlinerParaObject(); 655 656 if( pOutlinerParaObject && ( bOwnParaObj || !mpObject->IsEmptyPresObj() || mpObject->GetPage()->IsMasterPage() ) ) 657 { 658 mpOutliner->SetText( *pOutlinerParaObject ); 659 660 // #91254# put text to object and set EmptyPresObj to FALSE 661 if( mpText && bOwnParaObj && pOutlinerParaObject && mpObject->IsEmptyPresObj() && pTextObj->IsRealyEdited() ) 662 { 663 mpObject->SetEmptyPresObj( sal_False ); 664 static_cast< SdrTextObj* >( mpObject)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject, mpText ); 665 666 // #i103982# Here, due to mpObject->NbcSetOutlinerParaObjectForText, we LOSE ownership of the 667 // OPO, so do NOT delete it when leaving this method (!) 668 bOwnParaObj = false; 669 } 670 } 671 else 672 { 673 sal_Bool bVertical = pOutlinerParaObject ? pOutlinerParaObject->IsVertical() : sal_False; 674 675 // set objects style sheet on empty outliner 676 SfxStyleSheetPool* pPool = (SfxStyleSheetPool*)mpObject->GetModel()->GetStyleSheetPool(); 677 if( pPool ) 678 mpOutliner->SetStyleSheetPool( pPool ); 679 680 SfxStyleSheet* pStyleSheet = mpObject->GetPage()->GetTextStyleSheetForObject( mpObject ); 681 if( pStyleSheet ) 682 mpOutliner->SetStyleSheet( 0, pStyleSheet ); 683 684 if( bVertical ) 685 mpOutliner->SetVertical( sal_True ); 686 } 687 688 // evtually we have to set the border attributes 689 if (mpOutliner->GetParagraphCount()==1) 690 { 691 // if we only have one paragraph we check if it is empty 692 XubString aStr( mpOutliner->GetText( mpOutliner->GetParagraph( 0 ) ) ); 693 694 if(!aStr.Len()) 695 { 696 // its empty, so we have to force the outliner to initialise itself 697 mpOutliner->SetText( String(), mpOutliner->GetParagraph( 0 ) ); 698 699 if(mpObject->GetStyleSheet()) 700 mpOutliner->SetStyleSheet( 0, mpObject->GetStyleSheet()); 701 } 702 } 703 704 mbDataValid = sal_True; 705 706 if( bOwnParaObj ) 707 delete pOutlinerParaObject; 708 } 709 710 if( bCreated && mpOutliner && HasView() ) 711 { 712 // register as listener - need to broadcast state change messages 713 // registration delayed until outliner is completely set up 714 mpOutliner->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 715 } 716 717 // #99840#: prevent EE/Outliner notifications during setup 718 mbNotificationsDisabled = sal_False; 719 720 return mpTextForwarder; 721 } 722 723 //------------------------------------------------------------------------ 724 725 SvxTextForwarder* SvxTextEditSourceImpl::GetEditModeTextForwarder() 726 { 727 if( !mpTextForwarder && HasView() ) 728 { 729 SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner(); 730 731 if( pEditOutliner ) 732 { 733 mpTextForwarder = new SvxOutlinerForwarder( *pEditOutliner, (mpObject->GetObjInventor() == SdrInventor) && (mpObject->GetObjIdentifier() == OBJ_OUTLINETEXT) ); 734 mbForwarderIsEditMode = sal_True; 735 } 736 } 737 738 return mpTextForwarder; 739 } 740 741 //------------------------------------------------------------------------ 742 743 SvxTextForwarder* SvxTextEditSourceImpl::GetTextForwarder() 744 { 745 if( mbDestroyed || mpObject == NULL ) 746 return NULL; 747 748 if( mpModel == NULL ) 749 mpModel = mpObject->GetModel(); 750 751 if( mpModel == NULL ) 752 return NULL; 753 754 // distinguish the cases 755 // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner 756 // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code) 757 if( HasView() ) 758 { 759 if( IsEditMode() != mbForwarderIsEditMode ) 760 { 761 // forwarder mismatch - create new 762 delete mpTextForwarder; 763 mpTextForwarder = NULL; 764 } 765 766 if( IsEditMode() ) 767 return GetEditModeTextForwarder(); 768 else 769 return GetBackgroundTextForwarder(); 770 } 771 else 772 return GetBackgroundTextForwarder(); 773 } 774 775 //------------------------------------------------------------------------ 776 777 SvxDrawOutlinerViewForwarder* SvxTextEditSourceImpl::CreateViewForwarder() 778 { 779 if( mpView->GetTextEditOutlinerView() && mpObject ) 780 { 781 // register as listener - need to broadcast state change messages 782 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) ); 783 784 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 785 if( pTextObj ) 786 { 787 Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); 788 OutlinerView& rOutlView = *mpView->GetTextEditOutlinerView(); 789 790 return new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ); 791 } 792 } 793 794 return NULL; 795 } 796 797 SvxEditViewForwarder* SvxTextEditSourceImpl::GetEditViewForwarder( sal_Bool bCreate ) 798 { 799 if( mbDestroyed || mpObject == NULL ) 800 return NULL; 801 802 if( mpModel == NULL ) 803 mpModel = mpObject->GetModel(); 804 805 if( mpModel == NULL ) 806 return NULL; 807 808 // shall we delete? 809 if( mpViewForwarder ) 810 { 811 if( !IsEditMode() ) 812 { 813 // destroy all forwarders (no need for UpdateData(), 814 // it's been synched on SdrEndTextEdit) 815 delete mpViewForwarder; 816 mpViewForwarder = NULL; 817 } 818 } 819 // which to create? Directly in edit mode, create new, or none? 820 else if( mpView ) 821 { 822 if( IsEditMode() ) 823 { 824 // create new view forwarder 825 mpViewForwarder = CreateViewForwarder(); 826 } 827 else if( bCreate ) 828 { 829 // dispose old text forwarder 830 UpdateData(); 831 832 delete mpTextForwarder; 833 mpTextForwarder = NULL; 834 835 // enter edit mode 836 mpView->SdrEndTextEdit(); 837 838 if(mpView->SdrBeginTextEdit(mpObject, 0L, 0L, sal_False, (SdrOutliner*)0L, 0L, sal_False, sal_False)) 839 { 840 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 841 if( pTextObj->IsTextEditActive() ) 842 { 843 // create new view forwarder 844 mpViewForwarder = CreateViewForwarder(); 845 } 846 else 847 { 848 // failure. Somehow, SdrBeginTextEdit did not set 849 // our SdrTextObj into edit mode 850 mpView->SdrEndTextEdit(); 851 } 852 } 853 } 854 } 855 856 return mpViewForwarder; 857 } 858 859 //------------------------------------------------------------------------ 860 861 void SvxTextEditSourceImpl::UpdateData() 862 { 863 // if we have a view and in edit mode, we're working with the 864 // DrawOutliner. Thus, all changes made on the text forwarder are 865 // reflected on the view and committed to the model on 866 // SdrEndTextEdit(). Thus, no need for explicit updates here. 867 if( !HasView() || !IsEditMode() ) 868 { 869 if( mbIsLocked ) 870 { 871 mbNeedsUpdate = sal_True; 872 } 873 else 874 { 875 if( mpOutliner && mpObject && mpText && !mbDestroyed ) 876 { 877 SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject ); 878 if( pTextObj ) 879 { 880 if( mpOutliner->GetParagraphCount() != 1 || mpOutliner->GetEditEngine().GetTextLen( 0 ) ) 881 { 882 if( mpOutliner->GetParagraphCount() > 1 ) 883 { 884 if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == OBJ_TITLETEXT ) 885 { 886 while( mpOutliner->GetParagraphCount() > 1 ) 887 { 888 ESelection aSel( 0,mpOutliner->GetEditEngine().GetTextLen( 0 ), 1,0 ); 889 mpOutliner->QuickInsertLineBreak( aSel ); 890 } 891 } 892 } 893 894 pTextObj->NbcSetOutlinerParaObjectForText( mpOutliner->CreateParaObject(), mpText ); 895 } 896 else 897 { 898 pTextObj->NbcSetOutlinerParaObjectForText( NULL,mpText ); 899 } 900 } 901 902 if( mpObject->IsEmptyPresObj() ) 903 mpObject->SetEmptyPresObj(sal_False); 904 } 905 } 906 } 907 } 908 909 void SvxTextEditSourceImpl::lock() 910 { 911 mbIsLocked = sal_True; 912 if( mpOutliner ) 913 { 914 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); 915 mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); 916 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); 917 } 918 } 919 920 void SvxTextEditSourceImpl::unlock() 921 { 922 mbIsLocked = sal_False; 923 924 if( mbNeedsUpdate ) 925 { 926 UpdateData(); 927 mbNeedsUpdate = sal_False; 928 } 929 930 if( mpOutliner ) 931 { 932 ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_True ); 933 ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode ); 934 } 935 } 936 937 sal_Bool SvxTextEditSourceImpl::IsValid() const 938 { 939 return mpView && mpWindow ? sal_True : sal_False; 940 } 941 942 Rectangle SvxTextEditSourceImpl::GetVisArea() 943 { 944 if( IsValid() ) 945 { 946 SdrPaintWindow* pPaintWindow = mpView->FindPaintWindow(*mpWindow); 947 Rectangle aVisArea; 948 949 if(pPaintWindow) 950 { 951 aVisArea = pPaintWindow->GetVisibleArea(); 952 } 953 954 // offset vis area by edit engine left-top position 955 SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); 956 if( pTextObj ) 957 { 958 Rectangle aAnchorRect; 959 pTextObj->TakeTextAnchorRect( aAnchorRect ); 960 aVisArea.Move( -aAnchorRect.Left(), -aAnchorRect.Top() ); 961 962 MapMode aMapMode(mpWindow->GetMapMode()); 963 aMapMode.SetOrigin(Point()); 964 return mpWindow->LogicToPixel( aVisArea, aMapMode ); 965 } 966 } 967 968 return Rectangle(); 969 } 970 971 Point SvxTextEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) 972 { 973 // #101029#: The responsibilities of ViewForwarder happen to be 974 // somewhat mixed in this case. On the one hand, we need the 975 // different interface queries on the SvxEditSource interface, 976 // since we need both VisAreas. On the other hand, if an 977 // EditViewForwarder exists, maTextOffset does not remain static, 978 // but may change with every key press. 979 if( IsEditMode() ) 980 { 981 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); 982 983 if( pForwarder ) 984 return pForwarder->LogicToPixel( rPoint, rMapMode ); 985 } 986 else if( IsValid() && mpModel ) 987 { 988 // #101029# 989 Point aPoint1( rPoint ); 990 aPoint1.X() += maTextOffset.X(); 991 aPoint1.Y() += maTextOffset.Y(); 992 993 Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode, 994 MapMode(mpModel->GetScaleUnit()) ) ); 995 MapMode aMapMode(mpWindow->GetMapMode()); 996 aMapMode.SetOrigin(Point()); 997 return mpWindow->LogicToPixel( aPoint2, aMapMode ); 998 } 999 1000 return Point(); 1001 } 1002 1003 Point SvxTextEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) 1004 { 1005 // #101029#: The responsibilities of ViewForwarder happen to be 1006 // somewhat mixed in this case. On the one hand, we need the 1007 // different interface queries on the SvxEditSource interface, 1008 // since we need both VisAreas. On the other hand, if an 1009 // EditViewForwarder exists, maTextOffset does not remain static, 1010 // but may change with every key press. 1011 if( IsEditMode() ) 1012 { 1013 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); 1014 1015 if( pForwarder ) 1016 return pForwarder->PixelToLogic( rPoint, rMapMode ); 1017 } 1018 else if( IsValid() && mpModel ) 1019 { 1020 MapMode aMapMode(mpWindow->GetMapMode()); 1021 aMapMode.SetOrigin(Point()); 1022 Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) ); 1023 Point aPoint2( OutputDevice::LogicToLogic( aPoint1, 1024 MapMode(mpModel->GetScaleUnit()), 1025 rMapMode ) ); 1026 // #101029# 1027 aPoint2.X() -= maTextOffset.X(); 1028 aPoint2.Y() -= maTextOffset.Y(); 1029 1030 return aPoint2; 1031 } 1032 1033 return Point(); 1034 } 1035 1036 IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify*, aNotify) 1037 { 1038 if( aNotify && !mbNotificationsDisabled ) 1039 { 1040 ::std::auto_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( aNotify) ); 1041 1042 if( aHint.get() ) 1043 Broadcast( *aHint.get() ); 1044 } 1045 1046 return 0; 1047 } 1048 1049 //------------------------------------------------------------------------ 1050 1051 // -------------------------------------------------------------------- 1052 // SvxTextEditSource 1053 // -------------------------------------------------------------------- 1054 1055 SvxTextEditSource::SvxTextEditSource( SdrObject* pObject, SdrText* pText, XInterface* pOwner ) 1056 { 1057 mpImpl = new SvxTextEditSourceImpl( pObject, pText, pOwner ); 1058 mpImpl->acquire(); 1059 } 1060 1061 // -------------------------------------------------------------------- 1062 SvxTextEditSource::SvxTextEditSource( SdrObject& rObj, SdrText* pText, SdrView& rView, const Window& rWindow ) 1063 { 1064 mpImpl = new SvxTextEditSourceImpl( rObj, pText, rView, rWindow ); 1065 mpImpl->acquire(); 1066 } 1067 1068 // -------------------------------------------------------------------- 1069 1070 SvxTextEditSource::SvxTextEditSource( SvxTextEditSourceImpl* pImpl ) 1071 { 1072 mpImpl = pImpl; 1073 mpImpl->acquire(); 1074 } 1075 1076 //------------------------------------------------------------------------ 1077 SvxTextEditSource::~SvxTextEditSource() 1078 { 1079 OGuard aGuard( Application::GetSolarMutex() ); 1080 1081 mpImpl->release(); 1082 } 1083 1084 //------------------------------------------------------------------------ 1085 SvxEditSource* SvxTextEditSource::Clone() const 1086 { 1087 return new SvxTextEditSource( mpImpl ); 1088 } 1089 1090 //------------------------------------------------------------------------ 1091 SvxTextForwarder* SvxTextEditSource::GetTextForwarder() 1092 { 1093 return mpImpl->GetTextForwarder(); 1094 } 1095 1096 //------------------------------------------------------------------------ 1097 SvxEditViewForwarder* SvxTextEditSource::GetEditViewForwarder( sal_Bool bCreate ) 1098 { 1099 return mpImpl->GetEditViewForwarder( bCreate ); 1100 } 1101 1102 //------------------------------------------------------------------------ 1103 SvxViewForwarder* SvxTextEditSource::GetViewForwarder() 1104 { 1105 return this; 1106 } 1107 1108 //------------------------------------------------------------------------ 1109 void SvxTextEditSource::UpdateData() 1110 { 1111 mpImpl->UpdateData(); 1112 } 1113 1114 SfxBroadcaster& SvxTextEditSource::GetBroadcaster() const 1115 { 1116 return *mpImpl; 1117 } 1118 1119 SdrObject* SvxTextEditSource::GetSdrObject() const 1120 { 1121 return mpImpl->GetSdrObject(); 1122 } 1123 1124 void SvxTextEditSource::lock() 1125 { 1126 mpImpl->lock(); 1127 } 1128 1129 void SvxTextEditSource::unlock() 1130 { 1131 mpImpl->unlock(); 1132 } 1133 1134 sal_Bool SvxTextEditSource::IsValid() const 1135 { 1136 return mpImpl->IsValid(); 1137 } 1138 1139 Rectangle SvxTextEditSource::GetVisArea() const 1140 { 1141 return mpImpl->GetVisArea(); 1142 } 1143 1144 Point SvxTextEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const 1145 { 1146 return mpImpl->LogicToPixel( rPoint, rMapMode ); 1147 } 1148 1149 Point SvxTextEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const 1150 { 1151 return mpImpl->PixelToLogic( rPoint, rMapMode ); 1152 } 1153 1154 void SvxTextEditSource::addRange( SvxUnoTextRangeBase* pNewRange ) 1155 { 1156 mpImpl->addRange( pNewRange ); 1157 } 1158 1159 void SvxTextEditSource::removeRange( SvxUnoTextRangeBase* pOldRange ) 1160 { 1161 mpImpl->removeRange( pOldRange ); 1162 } 1163 1164 const SvxUnoTextRangeBaseList& SvxTextEditSource::getRanges() const 1165 { 1166 return mpImpl->getRanges(); 1167 } 1168 1169 void SvxTextEditSource::ChangeModel( SdrModel* pNewModel ) 1170 { 1171 mpImpl->ChangeModel( pNewModel ); 1172 } 1173 1174 void SvxTextEditSource::UpdateOutliner() 1175 { 1176 mpImpl->UpdateOutliner(); 1177 } 1178