Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / unodraw / unoshtxt.cxx
blob580b3c2f65a0115d58ab52c6b035113f1c9f54fc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <memory>
24 #include <vcl/svapp.hxx>
26 #include <svx/unoshtxt.hxx>
27 #include <editeng/unoedhlp.hxx>
28 #include <svl/lstner.hxx>
29 #include <rtl/ref.hxx>
30 #include <tools/debug.hxx>
31 #include <svl/hint.hxx>
32 #include <svl/style.hxx>
33 #include <svx/svdmodel.hxx>
34 #include <svx/svdoutl.hxx>
35 #include <svx/svdobj.hxx>
36 #include <svx/svdview.hxx>
37 #include <editeng/outliner.hxx>
38 #include <editeng/unoforou.hxx>
39 #include <editeng/unoviwou.hxx>
40 #include <editeng/outlobj.hxx>
41 #include <svx/svdotext.hxx>
42 #include <svx/svdpage.hxx>
43 #include <editeng/editeng.hxx>
45 #include <editeng/unotext.hxx>
46 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
47 #include <comphelper/processfactory.hxx>
48 #include <svx/svdotable.hxx>
49 #include <cell.hxx>
50 #include <unotools/configmgr.hxx>
53 // SvxTextEditSourceImpl
56 /** @descr
57 <p>This class essentially provides the text and view forwarders. If
58 no SdrView is given, this class handles the UNO objects, which are
59 currently not concerned with view issues. In this case,
60 GetViewForwarder() always returns NULL and the underlying
61 EditEngine of the SvxTextForwarder is a background one (i.e. not
62 the official DrawOutliner, but one created exclusively for this
63 object, with no relation to a view).
64 </p>
66 <p>If a SdrView is given at construction time, the caller is
67 responsible for destroying this object when the view becomes
68 invalid (the views cannot notify). If GetViewForwarder(sal_True)
69 is called, the underlying shape is put into edit mode, the view
70 forwarder returned encapsulates the OutlinerView and the next call
71 to GetTextForwarder() yields a forwarder encapsulating the actual
72 DrawOutliner. Thus, changes on that Outliner are immediately
73 reflected on the screen. If the object leaves edit mode, the old
74 behaviour is restored.</p>
76 class SvxTextEditSourceImpl : public SfxListener, public SfxBroadcaster, public sdr::ObjectUser
78 private:
79 oslInterlockedCount maRefCount;
81 SdrObject* mpObject; // TTTT could be reference (?)
82 SdrText* mpText;
83 SdrView* mpView;
84 VclPtr<const OutputDevice> mpWindow;
85 SdrModel* mpModel; // TTTT probably not needed -> use SdrModel from SdrObject (?)
86 std::unique_ptr<SdrOutliner> mpOutliner;
87 std::unique_ptr<SvxOutlinerForwarder> mpTextForwarder;
88 std::unique_ptr<SvxDrawOutlinerViewForwarder> mpViewForwarder; // if non-NULL, use GetViewModeTextForwarder text forwarder
89 css::uno::Reference< css::linguistic2::XLinguServiceManager2 > m_xLinguServiceManager;
90 Point maTextOffset;
91 bool mbDataValid;
92 bool mbIsLocked;
93 bool mbNeedsUpdate;
94 bool mbOldUndoMode;
95 bool mbForwarderIsEditMode; // have to reflect that, since ENDEDIT can happen more often
96 bool mbShapeIsEditMode; // only true, if SdrHintKind::BeginEdit was received
97 bool mbNotificationsDisabled; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder)
98 bool mbNotifyEditOutlinerSet;
100 SvxUnoTextRangeBaseVec mvTextRanges;
102 SvxTextForwarder* GetBackgroundTextForwarder();
103 SvxTextForwarder* GetEditModeTextForwarder();
104 std::unique_ptr<SvxDrawOutlinerViewForwarder> CreateViewForwarder();
106 void SetupOutliner();
108 bool HasView() const { return mpView != nullptr; }
109 bool IsEditMode() const
111 if (!mbShapeIsEditMode)
112 return false;
113 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
114 return pTextObj && pTextObj->IsTextEditActive();
117 void dispose();
119 public:
120 SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText );
121 SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const OutputDevice& rWindow );
122 virtual ~SvxTextEditSourceImpl() override;
124 void acquire();
125 void release();
127 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
129 SvxTextForwarder* GetTextForwarder();
130 SvxEditViewForwarder* GetEditViewForwarder( bool );
131 void UpdateData();
133 void addRange( SvxUnoTextRangeBase* pNewRange );
134 void removeRange( SvxUnoTextRangeBase* pOldRange );
135 const SvxUnoTextRangeBaseVec& getRanges() const { return mvTextRanges;}
137 void lock();
138 void unlock();
140 bool IsValid() const;
142 Point LogicToPixel( const Point&, const MapMode& rMapMode );
143 Point PixelToLogic( const Point&, const MapMode& rMapMode );
145 DECL_LINK( NotifyHdl, EENotify&, void );
147 virtual void ObjectInDestruction(const SdrObject& rObject) override;
149 void UpdateOutliner();
153 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText )
154 : maRefCount ( 0 ),
155 mpObject ( pObject ),
156 mpText ( pText ),
157 mpView ( nullptr ),
158 mpWindow ( nullptr ),
159 mpModel ( pObject ? &pObject->getSdrModelFromSdrObject() : nullptr ), // TTTT should be reference
160 mbDataValid ( false ),
161 mbIsLocked ( false ),
162 mbNeedsUpdate ( false ),
163 mbOldUndoMode ( false ),
164 mbForwarderIsEditMode ( false ),
165 mbShapeIsEditMode ( false ),
166 mbNotificationsDisabled ( false ),
167 mbNotifyEditOutlinerSet ( false )
169 DBG_ASSERT( mpObject, "invalid pObject!" );
171 if( !mpText )
173 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
174 if( pTextObj )
175 mpText = pTextObj->getText( 0 );
178 if( mpModel )
179 StartListening( *mpModel );
181 if( mpObject )
182 mpObject->AddObjectUser( *this );
186 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const OutputDevice& rWindow )
187 : maRefCount ( 0 ),
188 mpObject ( &rObject ),
189 mpText ( pText ),
190 mpView ( &rView ),
191 mpWindow ( &rWindow ),
192 mpModel ( &rObject.getSdrModelFromSdrObject() ), // TTTT should be reference
193 mbDataValid ( false ),
194 mbIsLocked ( false ),
195 mbNeedsUpdate ( false ),
196 mbOldUndoMode ( false ),
197 mbForwarderIsEditMode ( false ),
198 mbShapeIsEditMode ( true ),
199 mbNotificationsDisabled ( false ),
200 mbNotifyEditOutlinerSet ( false )
202 if( !mpText )
204 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
205 if( pTextObj )
206 mpText = pTextObj->getText( 0 );
209 StartListening( *mpModel );
210 StartListening( *mpView );
211 mpObject->AddObjectUser( *this );
213 // Init edit mode state from shape info (IsTextEditActive())
214 mbShapeIsEditMode = IsEditMode();
218 SvxTextEditSourceImpl::~SvxTextEditSourceImpl()
220 DBG_ASSERT( !mbIsLocked, "text edit source was not unlocked before dispose!" );
221 if( mpObject )
222 mpObject->RemoveObjectUser( *this );
224 dispose();
228 void SvxTextEditSourceImpl::addRange( SvxUnoTextRangeBase* pNewRange )
230 if( pNewRange )
231 if( std::find( mvTextRanges.begin(), mvTextRanges.end(), pNewRange ) == mvTextRanges.end() )
232 mvTextRanges.push_back( pNewRange );
236 void SvxTextEditSourceImpl::removeRange( SvxUnoTextRangeBase* pOldRange )
238 if( pOldRange )
239 mvTextRanges.erase( std::remove(mvTextRanges.begin(), mvTextRanges.end(), pOldRange), mvTextRanges.end() );
243 void SvxTextEditSourceImpl::acquire()
245 osl_atomic_increment( &maRefCount );
249 void SvxTextEditSourceImpl::release()
251 if( ! osl_atomic_decrement( &maRefCount ) )
252 delete this;
255 void SvxTextEditSourceImpl::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
257 // #i105988 keep reference to this object
258 rtl::Reference< SvxTextEditSourceImpl > xThis( this );
260 if (SfxHintId::Dying == rHint.GetId())
262 if (&rBC == mpView)
264 mpView = nullptr;
265 mpViewForwarder.reset();
268 else if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
270 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
271 switch( pSdrHint->GetKind() )
273 case SdrHintKind::ObjectChange:
275 mbDataValid = false; // Text has to be get again
277 if( HasView() )
279 // Update maTextOffset, object has changed
280 // Cannot call that here, since TakeTextRect() (called from there)
281 // changes outliner content.
282 // UpdateOutliner();
284 // Broadcast object changes, as they might change visible attributes
285 SvxViewChangedHint aHint;
286 Broadcast( aHint );
288 break;
291 case SdrHintKind::BeginEdit:
292 if( mpObject == pSdrHint->GetObject() )
294 // Once SdrHintKind::BeginEdit is broadcast, each EditSource of
295 // AccessibleCell will handle it here and call below:
296 // mpView->GetTextEditOutliner()->SetNotifyHdl(), which
297 // will replace the Notifier for current editable cell. It
298 // is totally wrong. So add check here to avoid the
299 // incorrect replacement of notifier.
301 // Currently it only happens on the editsource of
302 // AccessibleCell
303 if (mpObject && mpText)
305 sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( mpObject );
306 if(pTableObj)
308 const sdr::table::CellRef& xCell = pTableObj->getActiveCell();
309 if (xCell.is())
311 sdr::table::Cell* pCellObj = dynamic_cast< sdr::table::Cell* >( mpText );
312 if (pCellObj && xCell.get() != pCellObj)
313 break;
317 // invalidate old forwarder
318 if( !mbForwarderIsEditMode )
320 mpTextForwarder.reset();
323 // register as listener - need to broadcast state change messages
324 if( mpView && mpView->GetTextEditOutliner() )
326 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
327 mbNotifyEditOutlinerSet = true;
330 // Only now we're really in edit mode
331 mbShapeIsEditMode = true;
333 Broadcast( *pSdrHint );
335 break;
337 case SdrHintKind::EndEdit:
338 if( mpObject == pSdrHint->GetObject() )
340 Broadcast( *pSdrHint );
342 // We're no longer in edit mode
343 mbShapeIsEditMode = false;
345 // remove as listener - outliner might outlive ourselves
346 if( mpView && mpView->GetTextEditOutliner() )
348 mpView->GetTextEditOutliner()->SetNotifyHdl( Link<EENotify&,void>() );
349 mbNotifyEditOutlinerSet = false;
352 // destroy view forwarder, OutlinerView no longer
353 // valid (no need for UpdateData(), it's been
354 // synched on SdrEndTextEdit)
355 mpViewForwarder.reset();
357 // Invalidate text forwarder, we might
358 // not be called again before entering edit mode a
359 // second time! Then, the old outliner might be
360 // invalid.
361 if( mbForwarderIsEditMode )
363 mbForwarderIsEditMode = false;
364 mpTextForwarder.reset();
367 break;
369 case SdrHintKind::ModelCleared:
370 dispose();
371 break;
372 default:
373 break;
376 else if (rHint.GetId() == SfxHintId::SvxViewChanged)
378 const SvxViewChangedHint* pViewHint = static_cast<const SvxViewChangedHint*>(&rHint);
379 Broadcast( *pViewHint );
383 /* this is a callback from the attached SdrObject when it is actually deleted */
384 void SvxTextEditSourceImpl::ObjectInDestruction(const SdrObject&)
386 mpObject = nullptr;
387 dispose();
388 Broadcast( SfxHint( SfxHintId::Dying ) );
391 /* unregister at all objects and set all references to 0 */
392 void SvxTextEditSourceImpl::dispose()
394 mpTextForwarder.reset();
395 mpViewForwarder.reset();
397 if( mpOutliner )
399 if( mpModel )
401 mpModel->disposeOutliner( std::move(mpOutliner) );
403 else
405 mpOutliner.reset();
409 if( mpModel )
411 EndListening( *mpModel );
412 mpModel = nullptr;
415 if( mpView )
417 // remove as listener - outliner might outlive ourselves
418 if (mbNotifyEditOutlinerSet && mpView->GetTextEditOutliner())
420 mpView->GetTextEditOutliner()->SetNotifyHdl(Link<EENotify&,void>());
421 mbNotifyEditOutlinerSet = false;
423 EndListening( *mpView );
424 mpView = nullptr;
427 if( mpObject )
429 mpObject->RemoveObjectUser( *this );
430 mpObject = nullptr;
432 mpWindow = nullptr;
436 void SvxTextEditSourceImpl::SetupOutliner()
438 // only for UAA edit source: setup outliner equivalently as in
439 // SdrTextObj::Paint(), such that formatting equals screen
440 // layout
441 if( !(mpObject && mpOutliner) )
442 return;
444 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
445 if( pTextObj )
447 tools::Rectangle aPaintRect;
448 tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
449 pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect );
451 // calc text offset from shape anchor
452 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
457 void SvxTextEditSourceImpl::UpdateOutliner()
459 // only for UAA edit source: update outliner equivalently as in
460 // SdrTextObj::Paint(), such that formatting equals screen
461 // layout
462 if( !(mpObject && mpOutliner) )
463 return;
465 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
466 if( pTextObj )
468 tools::Rectangle aPaintRect;
469 tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
470 pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect );
472 // calc text offset from shape anchor
473 maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
478 SvxTextForwarder* SvxTextEditSourceImpl::GetBackgroundTextForwarder()
480 bool bCreated = false;
482 // prevent EE/Outliner notifications during setup
483 mbNotificationsDisabled = true;
485 if (!mpTextForwarder)
487 if( mpOutliner == nullptr )
489 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
490 OutlinerMode nOutlMode = OutlinerMode::TextObject;
491 if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == SdrObjKind::OutlineText )
492 nOutlMode = OutlinerMode::OutlineObject;
494 mpOutliner = mpModel->createOutliner( nOutlMode );
496 // Do the setup after outliner creation, would be useless otherwise
497 if( HasView() )
499 // Setup outliner _before_ filling it
500 SetupOutliner();
503 mpOutliner->SetTextObjNoInit( pTextObj );
504 if( mbIsLocked )
506 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
507 mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
508 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
511 if (!utl::ConfigManager::IsFuzzing())
513 if ( !m_xLinguServiceManager.is() )
515 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
516 m_xLinguServiceManager.set(css::linguistic2::LinguServiceManager::create(xContext));
519 css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator = m_xLinguServiceManager->getHyphenator();
520 if( xHyphenator.is() )
521 mpOutliner->SetHyphenator( xHyphenator );
526 mpTextForwarder.reset(new SvxOutlinerForwarder( *mpOutliner, (mpObject->GetObjInventor() == SdrInventor::Default) && (mpObject->GetObjIdentifier() == SdrObjKind::OutlineText) ));
527 // delay listener subscription and UAA initialization until Outliner is fully setup
528 bCreated = true;
530 mbForwarderIsEditMode = false;
531 mbDataValid = false;
534 if( mpObject && mpText && !mbDataValid && mpObject->IsInserted() && mpObject->getSdrPageFromSdrObject() )
536 mpTextForwarder->flushCache();
538 std::optional<OutlinerParaObject> pOutlinerParaObject;
539 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
540 if( pTextObj && pTextObj->getActiveText() == mpText )
541 pOutlinerParaObject = pTextObj->CreateEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
542 bool bTextEditActive(false);
544 if( pOutlinerParaObject )
545 bTextEditActive = true; // text edit active
546 else if (mpText->GetOutlinerParaObject())
547 pOutlinerParaObject = *mpText->GetOutlinerParaObject();
549 if( pOutlinerParaObject && ( bTextEditActive || !mpObject->IsEmptyPresObj() || mpObject->getSdrPageFromSdrObject()->IsMasterPage() ) )
551 mpOutliner->SetText( *pOutlinerParaObject );
553 // put text to object and set EmptyPresObj to FALSE
554 if (mpText && bTextEditActive && mpObject->IsEmptyPresObj() && pTextObj && pTextObj->IsReallyEdited())
556 mpObject->SetEmptyPresObj( false );
557 static_cast< SdrTextObj* >( mpObject)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject, mpText );
560 else
562 bool bVertical = pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical();
564 // set objects style sheet on empty outliner
565 SfxStyleSheetPool* pPool = static_cast<SfxStyleSheetPool*>(mpObject->getSdrModelFromSdrObject().GetStyleSheetPool());
566 if( pPool )
567 mpOutliner->SetStyleSheetPool( pPool );
569 SfxStyleSheet* pStyleSheet = mpObject->getSdrPageFromSdrObject()->GetTextStyleSheetForObject( mpObject );
570 if( pStyleSheet )
571 mpOutliner->SetStyleSheet( 0, pStyleSheet );
573 if( bVertical )
575 mpOutliner->SetVertical( pOutlinerParaObject->GetVertical());
576 mpOutliner->SetRotation( pOutlinerParaObject->GetRotation());
580 // maybe we have to set the border attributes
581 if (mpOutliner->GetParagraphCount()==1)
583 // if we only have one paragraph we check if it is empty
584 OUString aStr(mpOutliner->GetText(mpOutliner->GetParagraph(0)));
586 if (aStr.isEmpty())
588 // its empty, so we have to force the outliner to initialise itself
589 mpOutliner->SetText( "", mpOutliner->GetParagraph( 0 ) );
591 auto pCell = dynamic_cast<sdr::table::Cell*>(mpText);
592 if (pCell && pCell->GetStyleSheet())
593 mpOutliner->SetStyleSheet( 0, pCell->GetStyleSheet());
594 else if (mpObject->GetStyleSheet())
595 mpOutliner->SetStyleSheet( 0, mpObject->GetStyleSheet());
599 mbDataValid = true;
602 if( bCreated && mpOutliner && HasView() )
604 // register as listener - need to broadcast state change messages
605 // registration delayed until outliner is completely set up
606 mpOutliner->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
609 // prevent EE/Outliner notifications during setup
610 mbNotificationsDisabled = false;
612 return mpTextForwarder.get();
616 SvxTextForwarder* SvxTextEditSourceImpl::GetEditModeTextForwarder()
618 if( !mpTextForwarder && HasView() )
620 SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner();
622 if( pEditOutliner )
624 mpTextForwarder.reset(new SvxOutlinerForwarder( *pEditOutliner, (mpObject->GetObjInventor() == SdrInventor::Default) && (mpObject->GetObjIdentifier() == SdrObjKind::OutlineText) ));
625 mbForwarderIsEditMode = true;
629 return mpTextForwarder.get();
633 SvxTextForwarder* SvxTextEditSourceImpl::GetTextForwarder()
635 if( mpObject == nullptr )
636 return nullptr;
638 if( mpModel == nullptr )
639 mpModel = &mpObject->getSdrModelFromSdrObject();
641 // distinguish the cases
642 // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner
643 // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code)
644 if( HasView() )
646 if( IsEditMode() != mbForwarderIsEditMode )
648 // forwarder mismatch - create new
649 mpTextForwarder.reset();
652 if( IsEditMode() )
653 return GetEditModeTextForwarder();
654 else
655 return GetBackgroundTextForwarder();
657 else
659 // tdf#123470 if the text edit mode of the shape is active, then we
660 // cannot trust a previously cached TextForwarder state as the text may
661 // be out of date, so force a refetch in that case, unless locked against
662 // changes
663 if (IsEditMode() && mpTextForwarder && !mbIsLocked)
665 assert(!mbForwarderIsEditMode); // because without a view there is no other option except !mbForwarderIsEditMode
666 bool bTextEditActive = false;
667 SdrTextObj* pTextObj = DynCastSdrTextObj(mpObject);
668 // similar to the GetBackgroundTextForwarder check, see if the text edit is active
669 if (pTextObj && pTextObj->getActiveText() == mpText && pTextObj->CanCreateEditOutlinerParaObject())
670 bTextEditActive = true; // text edit active
671 if (bTextEditActive)
672 mbDataValid = false;
675 return GetBackgroundTextForwarder();
679 std::unique_ptr<SvxDrawOutlinerViewForwarder> SvxTextEditSourceImpl::CreateViewForwarder()
681 if( mpView->GetTextEditOutlinerView() && mpObject )
683 // register as listener - need to broadcast state change messages
684 mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
685 mbNotifyEditOutlinerSet = true;
687 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
688 if( pTextObj )
690 tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
691 OutlinerView& rOutlView = *mpView->GetTextEditOutlinerView();
693 return std::unique_ptr<SvxDrawOutlinerViewForwarder>(new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ));
697 return nullptr;
700 SvxEditViewForwarder* SvxTextEditSourceImpl::GetEditViewForwarder( bool bCreate )
702 if( mpObject == nullptr )
703 return nullptr;
705 if( mpModel == nullptr )
706 mpModel = &mpObject->getSdrModelFromSdrObject();
708 // shall we delete?
709 if( mpViewForwarder )
711 if( !IsEditMode() )
713 // destroy all forwarders (no need for UpdateData(),
714 // it's been synched on SdrEndTextEdit)
715 mpViewForwarder.reset();
718 // which to create? Directly in edit mode, create new, or none?
719 else if( mpView )
721 if( IsEditMode() )
723 // create new view forwarder
724 mpViewForwarder = CreateViewForwarder();
726 else if( bCreate )
728 // dispose old text forwarder
729 UpdateData();
731 mpTextForwarder.reset();
733 // enter edit mode
734 mpView->SdrEndTextEdit();
736 if(mpView->SdrBeginTextEdit(mpObject))
738 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
739 if (pTextObj && pTextObj->IsTextEditActive())
741 // create new view forwarder
742 mpViewForwarder = CreateViewForwarder();
744 else
746 // failure. Somehow, SdrBeginTextEdit did not set
747 // our SdrTextObj into edit mode
748 mpView->SdrEndTextEdit();
754 return mpViewForwarder.get();
758 void SvxTextEditSourceImpl::UpdateData()
760 // if we have a view and in edit mode, we're working with the
761 // DrawOutliner. Thus, all changes made on the text forwarder are
762 // reflected on the view and committed to the model on
763 // SdrEndTextEdit(). Thus, no need for explicit updates here.
764 if( HasView() && IsEditMode() )
765 return;
767 if( mbIsLocked )
769 mbNeedsUpdate = true;
771 else
773 if( mpOutliner && mpObject && mpText )
775 SdrTextObj* pTextObj = DynCastSdrTextObj( mpObject );
776 if( pTextObj )
778 if( (mpOutliner->GetParagraphCount() == 1 && mpOutliner->GetEditEngine().GetTextLen( 0 ) == 0 )
779 || (mpOutliner->GetParagraphCount() == 2 && mpOutliner->GetEditEngine().GetTextLen( 0 ) == 0
780 && mpOutliner->GetEditEngine().GetTextLen( 1 ) == 0) )
782 pTextObj->NbcSetOutlinerParaObjectForText( std::nullopt, mpText );
784 else
786 pTextObj->NbcSetOutlinerParaObjectForText( mpOutliner->CreateParaObject(), mpText );
790 if( mpObject->IsEmptyPresObj() )
791 mpObject->SetEmptyPresObj(false);
796 void SvxTextEditSourceImpl::lock()
798 // if this assert ever fires, we will need to make this a counter instead of a boolean
799 assert(!mbIsLocked && "cannot nest these loc() calls");
800 mbIsLocked = true;
801 if( mpOutliner )
803 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
804 mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
805 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
809 void SvxTextEditSourceImpl::unlock()
811 mbIsLocked = false;
813 if( mbNeedsUpdate )
815 UpdateData();
816 mbNeedsUpdate = false;
819 if( mpOutliner )
821 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( true );
822 const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode );
826 bool SvxTextEditSourceImpl::IsValid() const
828 return mpView && mpWindow;
831 Point SvxTextEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode )
833 // The responsibilities of ViewForwarder happen to be
834 // somewhat mixed in this case. On the one hand, we need the
835 // different interface queries on the SvxEditSource interface,
836 // since we need both VisAreas. On the other hand, if an
837 // EditViewForwarder exists, maTextOffset does not remain static,
838 // but may change with every key press.
839 if( IsEditMode() )
841 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
843 if( pForwarder )
844 return pForwarder->LogicToPixel( rPoint, rMapMode );
846 else if( IsValid() && mpModel )
848 Point aPoint1( rPoint );
849 aPoint1.AdjustX(maTextOffset.X() );
850 aPoint1.AdjustY(maTextOffset.Y() );
852 Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode,
853 MapMode(mpModel->GetScaleUnit()) ) );
854 MapMode aMapMode(mpWindow->GetMapMode());
855 aMapMode.SetOrigin(Point());
856 return mpWindow->LogicToPixel( aPoint2, aMapMode );
859 return Point();
862 Point SvxTextEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode )
864 // The responsibilities of ViewForwarder happen to be
865 // somewhat mixed in this case. On the one hand, we need the
866 // different interface queries on the SvxEditSource interface,
867 // since we need both VisAreas. On the other hand, if an
868 // EditViewForwarder exists, maTextOffset does not remain static,
869 // but may change with every key press.
870 if( IsEditMode() )
872 SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
874 if( pForwarder )
875 return pForwarder->PixelToLogic( rPoint, rMapMode );
877 else if( IsValid() && mpModel )
879 MapMode aMapMode(mpWindow->GetMapMode());
880 aMapMode.SetOrigin(Point());
881 Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) );
882 Point aPoint2( OutputDevice::LogicToLogic( aPoint1,
883 MapMode(mpModel->GetScaleUnit()),
884 rMapMode ) );
885 aPoint2.AdjustX( -(maTextOffset.X()) );
886 aPoint2.AdjustY( -(maTextOffset.Y()) );
888 return aPoint2;
891 return Point();
894 IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify&, rNotify, void)
896 if( !mbNotificationsDisabled )
898 std::unique_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( &rNotify) );
900 if (aHint)
901 Broadcast(*aHint);
905 SvxTextEditSource::SvxTextEditSource( SdrObject* pObject, SdrText* pText )
907 mpImpl = new SvxTextEditSourceImpl( pObject, pText );
911 SvxTextEditSource::SvxTextEditSource( SdrObject& rObj, SdrText* pText, SdrView& rView, const OutputDevice& rWindow )
913 mpImpl = new SvxTextEditSourceImpl( rObj, pText, rView, rWindow );
917 SvxTextEditSource::SvxTextEditSource( SvxTextEditSourceImpl* pImpl )
919 mpImpl = pImpl;
923 SvxTextEditSource::~SvxTextEditSource()
925 ::SolarMutexGuard aGuard;
926 mpImpl.clear();
930 std::unique_ptr<SvxEditSource> SvxTextEditSource::Clone() const
932 return std::unique_ptr<SvxEditSource>(new SvxTextEditSource( mpImpl.get() ));
936 SvxTextForwarder* SvxTextEditSource::GetTextForwarder()
938 return mpImpl->GetTextForwarder();
942 SvxEditViewForwarder* SvxTextEditSource::GetEditViewForwarder( bool bCreate )
944 return mpImpl->GetEditViewForwarder( bCreate );
948 SvxViewForwarder* SvxTextEditSource::GetViewForwarder()
950 return this;
954 void SvxTextEditSource::UpdateData()
956 mpImpl->UpdateData();
959 SfxBroadcaster& SvxTextEditSource::GetBroadcaster() const
961 return *mpImpl;
964 void SvxTextEditSource::lock()
966 mpImpl->lock();
969 void SvxTextEditSource::unlock()
971 mpImpl->unlock();
974 bool SvxTextEditSource::IsValid() const
976 return mpImpl->IsValid();
979 Point SvxTextEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
981 return mpImpl->LogicToPixel( rPoint, rMapMode );
984 Point SvxTextEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
986 return mpImpl->PixelToLogic( rPoint, rMapMode );
989 void SvxTextEditSource::addRange( SvxUnoTextRangeBase* pNewRange )
991 mpImpl->addRange( pNewRange );
994 void SvxTextEditSource::removeRange( SvxUnoTextRangeBase* pOldRange )
996 mpImpl->removeRange( pOldRange );
999 const SvxUnoTextRangeBaseVec& SvxTextEditSource::getRanges() const
1001 return mpImpl->getRanges();
1004 void SvxTextEditSource::UpdateOutliner()
1006 mpImpl->UpdateOutliner();
1009 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */