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