1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
50 #include <unotools/configmgr.hxx>
53 // SvxTextEditSourceImpl
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).
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
79 oslInterlockedCount maRefCount
;
81 SdrObject
* mpObject
; // TTTT could be reference (?)
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
;
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
)
113 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
114 return pTextObj
&& pTextObj
->IsTextEditActive();
120 SvxTextEditSourceImpl( SdrObject
* pObject
, SdrText
* pText
);
121 SvxTextEditSourceImpl( SdrObject
& rObject
, SdrText
* pText
, SdrView
& rView
, const OutputDevice
& rWindow
);
122 virtual ~SvxTextEditSourceImpl() override
;
127 virtual void Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
) override
;
129 SvxTextForwarder
* GetTextForwarder();
130 SvxEditViewForwarder
* GetEditViewForwarder( bool );
133 void addRange( SvxUnoTextRangeBase
* pNewRange
);
134 void removeRange( SvxUnoTextRangeBase
* pOldRange
);
135 const SvxUnoTextRangeBaseVec
& getRanges() const { return mvTextRanges
;}
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
)
155 mpObject ( pObject
),
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!" );
173 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
175 mpText
= pTextObj
->getText( 0 );
179 StartListening( *mpModel
);
182 mpObject
->AddObjectUser( *this );
186 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject
& rObject
, SdrText
* pText
, SdrView
& rView
, const OutputDevice
& rWindow
)
188 mpObject ( &rObject
),
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 )
204 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
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!" );
222 mpObject
->RemoveObjectUser( *this );
228 void SvxTextEditSourceImpl::addRange( SvxUnoTextRangeBase
* pNewRange
)
231 if( std::find( mvTextRanges
.begin(), mvTextRanges
.end(), pNewRange
) == mvTextRanges
.end() )
232 mvTextRanges
.push_back( pNewRange
);
236 void SvxTextEditSourceImpl::removeRange( SvxUnoTextRangeBase
* 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
) )
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())
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
279 // Update maTextOffset, object has changed
280 // Cannot call that here, since TakeTextRect() (called from there)
281 // changes outliner content.
284 // Broadcast object changes, as they might change visible attributes
285 SvxViewChangedHint aHint
;
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
303 if (mpObject
&& mpText
)
305 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mpObject
);
308 const sdr::table::CellRef
& xCell
= pTableObj
->getActiveCell();
311 sdr::table::Cell
* pCellObj
= dynamic_cast< sdr::table::Cell
* >( mpText
);
312 if (pCellObj
&& xCell
.get() != pCellObj
)
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
);
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
361 if( mbForwarderIsEditMode
)
363 mbForwarderIsEditMode
= false;
364 mpTextForwarder
.reset();
369 case SdrHintKind::ModelCleared
:
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
&)
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();
401 mpModel
->disposeOutliner( std::move(mpOutliner
) );
411 EndListening( *mpModel
);
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
);
429 mpObject
->RemoveObjectUser( *this );
436 void SvxTextEditSourceImpl::SetupOutliner()
438 // only for UAA edit source: setup outliner equivalently as in
439 // SdrTextObj::Paint(), such that formatting equals screen
441 if( !(mpObject
&& mpOutliner
) )
444 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
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
462 if( !(mpObject
&& mpOutliner
) )
465 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
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
499 // Setup outliner _before_ filling it
503 mpOutliner
->SetTextObjNoInit( pTextObj
);
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
530 mbForwarderIsEditMode
= 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
);
562 bool bVertical
= pOutlinerParaObject
&& pOutlinerParaObject
->IsEffectivelyVertical();
564 // set objects style sheet on empty outliner
565 SfxStyleSheetPool
* pPool
= static_cast<SfxStyleSheetPool
*>(mpObject
->getSdrModelFromSdrObject().GetStyleSheetPool());
567 mpOutliner
->SetStyleSheetPool( pPool
);
569 SfxStyleSheet
* pStyleSheet
= mpObject
->getSdrPageFromSdrObject()->GetTextStyleSheetForObject( mpObject
);
571 mpOutliner
->SetStyleSheet( 0, pStyleSheet
);
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)));
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());
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();
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 )
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)
646 if( IsEditMode() != mbForwarderIsEditMode
)
648 // forwarder mismatch - create new
649 mpTextForwarder
.reset();
653 return GetEditModeTextForwarder();
655 return GetBackgroundTextForwarder();
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
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
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
);
690 tools::Rectangle
aBoundRect( pTextObj
->GetCurrentBoundRect() );
691 OutlinerView
& rOutlView
= *mpView
->GetTextEditOutlinerView();
693 return std::unique_ptr
<SvxDrawOutlinerViewForwarder
>(new SvxDrawOutlinerViewForwarder( rOutlView
, aBoundRect
.TopLeft() ));
700 SvxEditViewForwarder
* SvxTextEditSourceImpl::GetEditViewForwarder( bool bCreate
)
702 if( mpObject
== nullptr )
705 if( mpModel
== nullptr )
706 mpModel
= &mpObject
->getSdrModelFromSdrObject();
709 if( mpViewForwarder
)
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?
723 // create new view forwarder
724 mpViewForwarder
= CreateViewForwarder();
728 // dispose old text forwarder
731 mpTextForwarder
.reset();
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();
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() )
769 mbNeedsUpdate
= true;
773 if( mpOutliner
&& mpObject
&& mpText
)
775 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mpObject
);
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
);
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");
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()
816 mbNeedsUpdate
= false;
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.
841 SvxEditViewForwarder
* pForwarder
= GetEditViewForwarder(false);
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
);
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.
872 SvxEditViewForwarder
* pForwarder
= GetEditViewForwarder(false);
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()),
885 aPoint2
.AdjustX( -(maTextOffset
.X()) );
886 aPoint2
.AdjustY( -(maTextOffset
.Y()) );
894 IMPL_LINK(SvxTextEditSourceImpl
, NotifyHdl
, EENotify
&, rNotify
, void)
896 if( !mbNotificationsDisabled
)
898 std::unique_ptr
< SfxHint
> aHint( SvxEditSourceHelper::EENotification2Hint( &rNotify
) );
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
)
923 SvxTextEditSource::~SvxTextEditSource()
925 ::SolarMutexGuard aGuard
;
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()
954 void SvxTextEditSource::UpdateData()
956 mpImpl
->UpdateData();
959 SfxBroadcaster
& SvxTextEditSource::GetBroadcaster() const
964 void SvxTextEditSource::lock()
969 void SvxTextEditSource::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: */