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 <com/sun/star/uno/XInterface.hpp>
25 #include <vcl/svapp.hxx>
27 #include <svx/unoshtxt.hxx>
28 #include <editeng/unoedhlp.hxx>
29 #include <svl/lstner.hxx>
30 #include <rtl/ref.hxx>
31 #include <osl/mutex.hxx>
32 #include <svl/hint.hxx>
33 #include <svl/style.hxx>
34 #include <svx/svdmodel.hxx>
35 #include <svx/svdoutl.hxx>
36 #include <svx/svdobj.hxx>
37 #include <svx/svdview.hxx>
38 #include <svx/svdetc.hxx>
39 #include <editeng/outliner.hxx>
40 #include <editeng/unoforou.hxx>
41 #include <editeng/unoviwou.hxx>
42 #include <editeng/outlobj.hxx>
43 #include <svx/svdotext.hxx>
44 #include <svx/svdpage.hxx>
45 #include <editeng/editeng.hxx>
46 #include <editeng/editobj.hxx>
48 #include <editeng/unotext.hxx>
49 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
50 #include <comphelper/processfactory.hxx>
51 #include <svx/svdotable.hxx>
52 #include "../table/cell.hxx"
53 #include <svx/sdrpaintwindow.hxx>
55 using namespace ::osl
;
57 using ::com::sun::star::uno::XInterface
;
60 // SvxTextEditSourceImpl
64 <p>This class essentially provides the text and view forwarders. If
65 no SdrView is given, this class handles the UNO objects, which are
66 currently not concerned with view issues. In this case,
67 GetViewForwarder() always returns NULL and the underlying
68 EditEngine of the SvxTextForwarder is a background one (i.e. not
69 the official DrawOutliner, but one created exclusively for this
70 object, with no relation to a view).
73 <p>If a SdrView is given at construction time, the caller is
74 responsible for destroying this object when the view becomes
75 invalid (the views cannot notify). If GetViewForwarder(sal_True)
76 is called, the underlying shape is put into edit mode, the view
77 forwarder returned encapsulates the OutlinerView and the next call
78 to GetTextForwarder() yields a forwarder encapsulating the actual
79 DrawOutliner. Thus, changes on that Outliner are immediately
80 reflected on the screen. If the object leaves edit mode, the old
81 behaviour is restored.</p>
83 class SvxTextEditSourceImpl
: public SfxListener
, public SfxBroadcaster
, public sdr::ObjectUser
86 oslInterlockedCount maRefCount
;
91 VclPtr
<const vcl::Window
> mpWindow
;
93 SdrOutliner
* mpOutliner
;
94 SvxOutlinerForwarder
* mpTextForwarder
;
95 SvxDrawOutlinerViewForwarder
* mpViewForwarder
; // if non-NULL, use GetViewModeTextForwarder text forwarder
96 css::uno::Reference
< css::linguistic2::XLinguServiceManager2
> m_xLinguServiceManager
;
103 bool mbForwarderIsEditMode
; // have to reflect that, since ENDEDIT can happen more often
104 bool mbShapeIsEditMode
; // #104157# only true, if HINT_BEGEDIT was received
105 bool mbNotificationsDisabled
; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder)
107 SvxUnoTextRangeBaseList maTextRanges
;
109 SvxTextForwarder
* GetBackgroundTextForwarder();
110 SvxTextForwarder
* GetEditModeTextForwarder();
111 SvxDrawOutlinerViewForwarder
* CreateViewForwarder();
113 void SetupOutliner();
115 bool HasView() const { return mpView
!= nullptr; }
116 bool IsEditMode() const
118 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
119 return mbShapeIsEditMode
&& pTextObj
&& pTextObj
->IsTextEditActive();
125 SvxTextEditSourceImpl( SdrObject
* pObject
, SdrText
* pText
);
126 SvxTextEditSourceImpl( SdrObject
& rObject
, SdrText
* pText
, SdrView
& rView
, const vcl::Window
& rWindow
);
127 virtual ~SvxTextEditSourceImpl();
129 void SAL_CALL
acquire();
130 void SAL_CALL
release();
132 virtual void Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
) SAL_OVERRIDE
;
134 SvxTextForwarder
* GetTextForwarder();
135 SvxEditViewForwarder
* GetEditViewForwarder( bool );
138 void addRange( SvxUnoTextRangeBase
* pNewRange
);
139 void removeRange( SvxUnoTextRangeBase
* pOldRange
);
140 const SvxUnoTextRangeBaseList
& getRanges() const { return maTextRanges
;}
145 bool IsValid() const;
147 Rectangle
GetVisArea();
148 Point
LogicToPixel( const Point
&, const MapMode
& rMapMode
);
149 Point
PixelToLogic( const Point
&, const MapMode
& rMapMode
);
151 DECL_LINK( NotifyHdl
, EENotify
* );
153 virtual void ObjectInDestruction(const SdrObject
& rObject
) SAL_OVERRIDE
;
155 void ChangeModel( SdrModel
* pNewModel
);
157 void UpdateOutliner();
162 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject
* pObject
, SdrText
* pText
)
164 mpObject ( pObject
),
168 mpModel ( pObject
? pObject
->GetModel() : NULL
),
170 mpTextForwarder ( NULL
),
171 mpViewForwarder ( NULL
),
172 mbDataValid ( false ),
173 mbDestroyed ( false ),
174 mbIsLocked ( false ),
175 mbNeedsUpdate ( false ),
176 mbOldUndoMode ( false ),
177 mbForwarderIsEditMode ( false ),
178 mbShapeIsEditMode ( false ),
179 mbNotificationsDisabled ( false )
181 DBG_ASSERT( mpObject
, "invalid pObject!" );
185 SdrTextObj
* pTextObj
= dynamic_cast< SdrTextObj
* >( mpObject
);
187 mpText
= pTextObj
->getText( 0 );
191 StartListening( *mpModel
);
194 mpObject
->AddObjectUser( *this );
199 SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject
& rObject
, SdrText
* pText
, SdrView
& rView
, const vcl::Window
& rWindow
)
201 mpObject ( &rObject
),
204 mpWindow ( &rWindow
),
205 mpModel ( rObject
.GetModel() ),
207 mpTextForwarder ( NULL
),
208 mpViewForwarder ( NULL
),
209 mbDataValid ( false ),
210 mbDestroyed ( false ),
211 mbIsLocked ( false ),
212 mbNeedsUpdate ( false ),
213 mbOldUndoMode ( false ),
214 mbForwarderIsEditMode ( false ),
215 mbShapeIsEditMode ( true ),
216 mbNotificationsDisabled ( false )
220 SdrTextObj
* pTextObj
= dynamic_cast< SdrTextObj
* >( mpObject
);
222 mpText
= pTextObj
->getText( 0 );
226 StartListening( *mpModel
);
228 StartListening( *mpView
);
230 mpObject
->AddObjectUser( *this );
232 // #104157# Init edit mode state from shape info (IsTextEditActive())
233 mbShapeIsEditMode
= IsEditMode();
238 SvxTextEditSourceImpl::~SvxTextEditSourceImpl()
240 DBG_ASSERT( !mbIsLocked
, "text edit source was not unlocked before dispose!" );
242 mpObject
->RemoveObjectUser( *this );
249 void SvxTextEditSourceImpl::addRange( SvxUnoTextRangeBase
* pNewRange
)
252 if( std::find( maTextRanges
.begin(), maTextRanges
.end(), pNewRange
) == maTextRanges
.end() )
253 maTextRanges
.push_back( pNewRange
);
258 void SvxTextEditSourceImpl::removeRange( SvxUnoTextRangeBase
* pOldRange
)
261 maTextRanges
.remove( pOldRange
);
269 void SAL_CALL
SvxTextEditSourceImpl::acquire()
271 osl_atomic_increment( &maRefCount
);
276 void SAL_CALL
SvxTextEditSourceImpl::release()
278 if( ! osl_atomic_decrement( &maRefCount
) )
282 void SvxTextEditSourceImpl::ChangeModel( SdrModel
* pNewModel
)
284 if( mpModel
!= pNewModel
)
287 EndListening( *mpModel
);
292 mpModel
->disposeOutliner( mpOutliner
);
300 EndListening( *mpView
);
305 m_xLinguServiceManager
.clear();
309 if( mpTextForwarder
)
311 delete mpTextForwarder
;
315 if( mpViewForwarder
)
317 delete mpViewForwarder
;
322 StartListening( *mpModel
);
328 void SvxTextEditSourceImpl::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
330 // #i105988 keep reference to this object
331 rtl::Reference
< SvxTextEditSourceImpl
> xThis( this );
333 const SdrHint
* pSdrHint
= dynamic_cast<const SdrHint
*>(&rHint
);
334 const SvxViewHint
* pViewHint
= dynamic_cast<const SvxViewHint
*>(&rHint
);
335 const SfxSimpleHint
* pSimpleHint
= dynamic_cast<const SfxSimpleHint
*>(&rHint
);
339 if (SFX_HINT_DYING
== pSimpleHint
->GetId())
346 delete mpViewForwarder
;
354 switch( pViewHint
->GetHintType() )
356 case SvxViewHint::SVX_HINT_VIEWCHANGED
:
357 Broadcast( *pViewHint
);
363 switch( pSdrHint
->GetKind() )
367 mbDataValid
= false; // Text muss neu geholt werden
371 // #104157# Update maTextOffset, object has changed
372 // #105196#, #105203#: Cannot call that // here,
373 // since TakeTextRect() (called from there)
374 // changes outliner content.
377 // #101029# Broadcast object changes, as they might change visible attributes
378 SvxViewHint
aHint(SvxViewHint::SVX_HINT_VIEWCHANGED
);
385 if( mpObject
== pSdrHint
->GetObject() )
387 // Once HINT_BEGEDIT is broadcast, each EditSource of
388 // AccessibleCell will handle it here and call below:
389 // mpView->GetTextEditOutliner()->SetNotifyHdl(), which
390 // will replace the Notifer for current editable cell. It
391 // is totally wrong. So add check here to avoid the
392 // incorrect replacement of notifer.
394 // Currently it only happens on the editsource of
396 if (mpObject
&& mpText
)
398 sdr::table::SdrTableObj
* pTableObj
= PTR_CAST( sdr::table::SdrTableObj
, mpObject
);
401 sdr::table::CellRef xCell
= pTableObj
->getActiveCell();
404 sdr::table::Cell
* pCellObj
= dynamic_cast< sdr::table::Cell
* >( mpText
);
405 if (pCellObj
&& xCell
.get() != pCellObj
)
410 // invalidate old forwarder
411 if( !mbForwarderIsEditMode
)
413 delete mpTextForwarder
;
414 mpTextForwarder
= NULL
;
417 // register as listener - need to broadcast state change messages
418 if( mpView
&& mpView
->GetTextEditOutliner() )
419 mpView
->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl
, NotifyHdl
) );
421 // #104157# Only now we're really in edit mode
422 mbShapeIsEditMode
= true;
424 Broadcast( *pSdrHint
);
429 if( mpObject
== pSdrHint
->GetObject() )
431 Broadcast( *pSdrHint
);
433 // #104157# We're no longer in edit mode
434 mbShapeIsEditMode
= false;
436 // remove as listener - outliner might outlive ourselves
437 if( mpView
&& mpView
->GetTextEditOutliner() )
438 mpView
->GetTextEditOutliner()->SetNotifyHdl( Link
<>() );
440 // destroy view forwarder, OutlinerView no longer
441 // valid (no need for UpdateData(), it's been
442 // synched on SdrEndTextEdit)
443 delete mpViewForwarder
;
444 mpViewForwarder
= NULL
;
446 // #100424# Invalidate text forwarder, we might
447 // not be called again before entering edit mode a
448 // second time! Then, the old outliner might be
450 if( mbForwarderIsEditMode
)
452 mbForwarderIsEditMode
= false;
453 delete mpTextForwarder
;
454 mpTextForwarder
= NULL
;
459 case HINT_MODELCLEARED
:
468 /* this is a callback from the attached SdrObject when it is actually deleted */
469 void SvxTextEditSourceImpl::ObjectInDestruction(const SdrObject
&)
473 Broadcast( SfxSimpleHint( SFX_HINT_DYING
) );
476 /* unregister at all objects and set all references to 0 */
477 void SvxTextEditSourceImpl::dispose()
479 if( mpTextForwarder
)
481 delete mpTextForwarder
;
485 if( mpViewForwarder
)
487 delete mpViewForwarder
;
495 mpModel
->disposeOutliner( mpOutliner
);
506 EndListening( *mpModel
);
512 EndListening( *mpView
);
518 mpObject
->RemoveObjectUser( *this );
526 void SvxTextEditSourceImpl::SetupOutliner()
529 // only for UAA edit source: setup outliner equivalently as in
530 // SdrTextObj::Paint(), such that formatting equals screen
532 if( mpObject
&& mpOutliner
)
534 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
535 Rectangle aPaintRect
;
538 Rectangle
aBoundRect( pTextObj
->GetCurrentBoundRect() );
539 pTextObj
->SetupOutlinerFormatting( *mpOutliner
, aPaintRect
);
541 // #101029# calc text offset from shape anchor
542 maTextOffset
= aPaintRect
.TopLeft() - aBoundRect
.TopLeft();
549 void SvxTextEditSourceImpl::UpdateOutliner()
552 // only for UAA edit source: update outliner equivalently as in
553 // SdrTextObj::Paint(), such that formatting equals screen
555 if( mpObject
&& mpOutliner
)
557 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
558 Rectangle aPaintRect
;
561 Rectangle
aBoundRect( pTextObj
->GetCurrentBoundRect() );
562 pTextObj
->UpdateOutlinerFormatting( *mpOutliner
, aPaintRect
);
564 // #101029# calc text offset from shape anchor
565 maTextOffset
= aPaintRect
.TopLeft() - aBoundRect
.TopLeft();
574 SvxTextForwarder
* SvxTextEditSourceImpl::GetBackgroundTextForwarder()
576 bool bCreated
= false;
578 // #99840#: prevent EE/Outliner notifications during setup
579 mbNotificationsDisabled
= true;
581 if (!mpTextForwarder
)
583 if( mpOutliner
== NULL
)
585 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
586 sal_uInt16 nOutlMode
= OUTLINERMODE_TEXTOBJECT
;
587 if( pTextObj
&& pTextObj
->IsTextFrame() && pTextObj
->GetTextKind() == OBJ_OUTLINETEXT
)
588 nOutlMode
= OUTLINERMODE_OUTLINEOBJECT
;
590 mpOutliner
= mpModel
->createOutliner( nOutlMode
);
592 // #109151# Do the setup after outliner creation, would be useless otherwise
595 // #101029#, #104157# Setup outliner _before_ filling it
599 mpOutliner
->SetTextObjNoInit( pTextObj
);
602 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->SetUpdateMode( false );
603 mbOldUndoMode
= const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->IsUndoEnabled();
604 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->EnableUndo( false );
607 if ( !m_xLinguServiceManager
.is() )
609 css::uno::Reference
< css::uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
610 m_xLinguServiceManager
.set(css::linguistic2::LinguServiceManager::create(xContext
));
613 css::uno::Reference
< css::linguistic2::XHyphenator
> xHyphenator( m_xLinguServiceManager
->getHyphenator(), css::uno::UNO_QUERY
);
614 if( xHyphenator
.is() )
615 mpOutliner
->SetHyphenator( xHyphenator
);
619 mpTextForwarder
= new SvxOutlinerForwarder( *mpOutliner
, (mpObject
->GetObjInventor() == SdrInventor
) && (mpObject
->GetObjIdentifier() == OBJ_OUTLINETEXT
) );
620 // delay listener subscription and UAA initialization until Outliner is fully setup
623 mbForwarderIsEditMode
= false;
626 if( mpObject
&& mpText
&& !mbDataValid
&& mpObject
->IsInserted() && mpObject
->GetPage() )
628 mpTextForwarder
->flushCache();
630 OutlinerParaObject
* pOutlinerParaObject
= NULL
;
631 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
632 if( pTextObj
&& pTextObj
->getActiveText() == mpText
)
633 pOutlinerParaObject
= pTextObj
->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
634 bool bOwnParaObj(false);
636 if( pOutlinerParaObject
)
637 bOwnParaObj
= true; // text edit active
639 pOutlinerParaObject
= mpText
->GetOutlinerParaObject();
641 if( pOutlinerParaObject
&& ( bOwnParaObj
|| !mpObject
->IsEmptyPresObj() || mpObject
->GetPage()->IsMasterPage() ) )
643 mpOutliner
->SetText( *pOutlinerParaObject
);
645 // #91254# put text to object and set EmptyPresObj to FALSE
646 if( mpText
&& bOwnParaObj
&& pOutlinerParaObject
&& mpObject
->IsEmptyPresObj() && pTextObj
->IsReallyEdited() )
648 mpObject
->SetEmptyPresObj( false );
649 static_cast< SdrTextObj
* >( mpObject
)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject
, mpText
);
651 // #i103982# Here, due to mpObject->NbcSetOutlinerParaObjectForText, we LOSE ownership of the
652 // OPO, so do NOT delete it when leaving this method (!)
658 bool bVertical
= pOutlinerParaObject
&& pOutlinerParaObject
->IsVertical();
660 // set objects style sheet on empty outliner
661 SfxStyleSheetPool
* pPool
= static_cast<SfxStyleSheetPool
*>(mpObject
->GetModel()->GetStyleSheetPool());
663 mpOutliner
->SetStyleSheetPool( pPool
);
665 SfxStyleSheet
* pStyleSheet
= mpObject
->GetPage()->GetTextStyleSheetForObject( mpObject
);
667 mpOutliner
->SetStyleSheet( 0, pStyleSheet
);
670 mpOutliner
->SetVertical( true );
673 // evtually we have to set the border attributes
674 if (mpOutliner
->GetParagraphCount()==1)
676 // if we only have one paragraph we check if it is empty
677 OUString
aStr(mpOutliner
->GetText(mpOutliner
->GetParagraph(0)));
681 // its empty, so we have to force the outliner to initialise itself
682 mpOutliner
->SetText( "", mpOutliner
->GetParagraph( 0 ) );
684 if(mpObject
->GetStyleSheet())
685 mpOutliner
->SetStyleSheet( 0, mpObject
->GetStyleSheet());
692 delete pOutlinerParaObject
;
695 if( bCreated
&& mpOutliner
&& HasView() )
697 // register as listener - need to broadcast state change messages
698 // registration delayed until outliner is completely set up
699 mpOutliner
->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl
, NotifyHdl
) );
702 // #99840#: prevent EE/Outliner notifications during setup
703 mbNotificationsDisabled
= false;
705 return mpTextForwarder
;
710 SvxTextForwarder
* SvxTextEditSourceImpl::GetEditModeTextForwarder()
712 if( !mpTextForwarder
&& HasView() )
714 SdrOutliner
* pEditOutliner
= mpView
->GetTextEditOutliner();
718 mpTextForwarder
= new SvxOutlinerForwarder( *pEditOutliner
, (mpObject
->GetObjInventor() == SdrInventor
) && (mpObject
->GetObjIdentifier() == OBJ_OUTLINETEXT
) );
719 mbForwarderIsEditMode
= true;
723 return mpTextForwarder
;
728 SvxTextForwarder
* SvxTextEditSourceImpl::GetTextForwarder()
730 if( mbDestroyed
|| mpObject
== NULL
)
733 if( mpModel
== NULL
)
734 mpModel
= mpObject
->GetModel();
736 if( mpModel
== NULL
)
739 // distinguish the cases
740 // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner
741 // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code)
744 if( IsEditMode() != mbForwarderIsEditMode
)
746 // forwarder mismatch - create new
747 delete mpTextForwarder
;
748 mpTextForwarder
= NULL
;
752 return GetEditModeTextForwarder();
754 return GetBackgroundTextForwarder();
757 return GetBackgroundTextForwarder();
762 SvxDrawOutlinerViewForwarder
* SvxTextEditSourceImpl::CreateViewForwarder()
764 if( mpView
->GetTextEditOutlinerView() && mpObject
)
766 // register as listener - need to broadcast state change messages
767 mpView
->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl
, NotifyHdl
) );
769 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
772 Rectangle
aBoundRect( pTextObj
->GetCurrentBoundRect() );
773 OutlinerView
& rOutlView
= *mpView
->GetTextEditOutlinerView();
775 return new SvxDrawOutlinerViewForwarder( rOutlView
, aBoundRect
.TopLeft() );
782 SvxEditViewForwarder
* SvxTextEditSourceImpl::GetEditViewForwarder( bool bCreate
)
784 if( mbDestroyed
|| mpObject
== NULL
)
787 if( mpModel
== NULL
)
788 mpModel
= mpObject
->GetModel();
790 if( mpModel
== NULL
)
794 if( mpViewForwarder
)
798 // destroy all forwarders (no need for UpdateData(),
799 // it's been synched on SdrEndTextEdit)
800 delete mpViewForwarder
;
801 mpViewForwarder
= NULL
;
804 // which to create? Directly in edit mode, create new, or none?
809 // create new view forwarder
810 mpViewForwarder
= CreateViewForwarder();
814 // dispose old text forwarder
817 delete mpTextForwarder
;
818 mpTextForwarder
= NULL
;
821 mpView
->SdrEndTextEdit();
823 if(mpView
->SdrBeginTextEdit(mpObject
, 0L, 0L, false, (SdrOutliner
*)0L, 0L, false, false))
825 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
826 if (pTextObj
&& pTextObj
->IsTextEditActive())
828 // create new view forwarder
829 mpViewForwarder
= CreateViewForwarder();
833 // failure. Somehow, SdrBeginTextEdit did not set
834 // our SdrTextObj into edit mode
835 mpView
->SdrEndTextEdit();
841 return mpViewForwarder
;
846 void SvxTextEditSourceImpl::UpdateData()
848 // if we have a view and in edit mode, we're working with the
849 // DrawOutliner. Thus, all changes made on the text forwarder are
850 // reflected on the view and committed to the model on
851 // SdrEndTextEdit(). Thus, no need for explicit updates here.
852 if( !HasView() || !IsEditMode() )
856 mbNeedsUpdate
= true;
860 if( mpOutliner
&& mpObject
&& mpText
&& !mbDestroyed
)
862 SdrTextObj
* pTextObj
= dynamic_cast< SdrTextObj
* >( mpObject
);
865 if( mpOutliner
->GetParagraphCount() != 1 || mpOutliner
->GetEditEngine().GetTextLen( 0 ) )
867 if( mpOutliner
->GetParagraphCount() > 1 )
869 if( pTextObj
&& pTextObj
->IsTextFrame() && pTextObj
->GetTextKind() == OBJ_TITLETEXT
)
871 while( mpOutliner
->GetParagraphCount() > 1 )
873 ESelection
aSel( 0,mpOutliner
->GetEditEngine().GetTextLen( 0 ), 1,0 );
874 mpOutliner
->QuickInsertLineBreak( aSel
);
879 pTextObj
->NbcSetOutlinerParaObjectForText( mpOutliner
->CreateParaObject(), mpText
);
883 pTextObj
->NbcSetOutlinerParaObjectForText( NULL
,mpText
);
887 if( mpObject
->IsEmptyPresObj() )
888 mpObject
->SetEmptyPresObj(false);
894 void SvxTextEditSourceImpl::lock()
899 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->SetUpdateMode( false );
900 mbOldUndoMode
= const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->IsUndoEnabled();
901 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->EnableUndo( false );
905 void SvxTextEditSourceImpl::unlock()
912 mbNeedsUpdate
= false;
917 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->SetUpdateMode( true );
918 const_cast<EditEngine
*>(&(mpOutliner
->GetEditEngine()))->EnableUndo( mbOldUndoMode
);
922 bool SvxTextEditSourceImpl::IsValid() const
924 return mpView
&& mpWindow
;
927 Rectangle
SvxTextEditSourceImpl::GetVisArea()
931 SdrPaintWindow
* pPaintWindow
= mpView
->FindPaintWindow(*mpWindow
);
936 aVisArea
= pPaintWindow
->GetVisibleArea();
939 // offset vis area by edit engine left-top position
940 SdrTextObj
* pTextObj
= PTR_CAST( SdrTextObj
, mpObject
);
943 Rectangle aAnchorRect
;
944 pTextObj
->TakeTextAnchorRect( aAnchorRect
);
945 aVisArea
.Move( -aAnchorRect
.Left(), -aAnchorRect
.Top() );
947 MapMode
aMapMode(mpWindow
->GetMapMode());
948 aMapMode
.SetOrigin(Point());
949 return mpWindow
->LogicToPixel( aVisArea
, aMapMode
);
956 Point
SvxTextEditSourceImpl::LogicToPixel( const Point
& rPoint
, const MapMode
& rMapMode
)
958 // #101029#: The responsibilities of ViewForwarder happen to be
959 // somewhat mixed in this case. On the one hand, we need the
960 // different interface queries on the SvxEditSource interface,
961 // since we need both VisAreas. On the other hand, if an
962 // EditViewForwarder exists, maTextOffset does not remain static,
963 // but may change with every key press.
966 SvxEditViewForwarder
* pForwarder
= GetEditViewForwarder(false);
969 return pForwarder
->LogicToPixel( rPoint
, rMapMode
);
971 else if( IsValid() && mpModel
)
974 Point
aPoint1( rPoint
);
975 aPoint1
.X() += maTextOffset
.X();
976 aPoint1
.Y() += maTextOffset
.Y();
978 Point
aPoint2( OutputDevice::LogicToLogic( aPoint1
, rMapMode
,
979 MapMode(mpModel
->GetScaleUnit()) ) );
980 MapMode
aMapMode(mpWindow
->GetMapMode());
981 aMapMode
.SetOrigin(Point());
982 return mpWindow
->LogicToPixel( aPoint2
, aMapMode
);
988 Point
SvxTextEditSourceImpl::PixelToLogic( const Point
& rPoint
, const MapMode
& rMapMode
)
990 // #101029#: The responsibilities of ViewForwarder happen to be
991 // somewhat mixed in this case. On the one hand, we need the
992 // different interface queries on the SvxEditSource interface,
993 // since we need both VisAreas. On the other hand, if an
994 // EditViewForwarder exists, maTextOffset does not remain static,
995 // but may change with every key press.
998 SvxEditViewForwarder
* pForwarder
= GetEditViewForwarder(false);
1001 return pForwarder
->PixelToLogic( rPoint
, rMapMode
);
1003 else if( IsValid() && mpModel
)
1005 MapMode
aMapMode(mpWindow
->GetMapMode());
1006 aMapMode
.SetOrigin(Point());
1007 Point
aPoint1( mpWindow
->PixelToLogic( rPoint
, aMapMode
) );
1008 Point
aPoint2( OutputDevice::LogicToLogic( aPoint1
,
1009 MapMode(mpModel
->GetScaleUnit()),
1012 aPoint2
.X() -= maTextOffset
.X();
1013 aPoint2
.Y() -= maTextOffset
.Y();
1021 IMPL_LINK(SvxTextEditSourceImpl
, NotifyHdl
, EENotify
*, aNotify
)
1023 if( aNotify
&& !mbNotificationsDisabled
)
1025 std::unique_ptr
< SfxHint
> aHint( SvxEditSourceHelper::EENotification2Hint( aNotify
) );
1028 Broadcast( *aHint
.get() );
1034 SvxTextEditSource::SvxTextEditSource( SdrObject
* pObject
, SdrText
* pText
)
1036 mpImpl
= new SvxTextEditSourceImpl( pObject
, pText
);
1041 SvxTextEditSource::SvxTextEditSource( SdrObject
& rObj
, SdrText
* pText
, SdrView
& rView
, const vcl::Window
& rWindow
)
1043 mpImpl
= new SvxTextEditSourceImpl( rObj
, pText
, rView
, rWindow
);
1049 SvxTextEditSource::SvxTextEditSource( SvxTextEditSourceImpl
* pImpl
)
1056 SvxTextEditSource::~SvxTextEditSource()
1058 ::SolarMutexGuard aGuard
;
1064 SvxEditSource
* SvxTextEditSource::Clone() const
1066 return new SvxTextEditSource( mpImpl
);
1070 SvxTextForwarder
* SvxTextEditSource::GetTextForwarder()
1072 return mpImpl
->GetTextForwarder();
1076 SvxEditViewForwarder
* SvxTextEditSource::GetEditViewForwarder( bool bCreate
)
1078 return mpImpl
->GetEditViewForwarder( bCreate
);
1082 SvxViewForwarder
* SvxTextEditSource::GetViewForwarder()
1088 void SvxTextEditSource::UpdateData()
1090 mpImpl
->UpdateData();
1093 SfxBroadcaster
& SvxTextEditSource::GetBroadcaster() const
1098 void SvxTextEditSource::lock()
1103 void SvxTextEditSource::unlock()
1108 bool SvxTextEditSource::IsValid() const
1110 return mpImpl
->IsValid();
1113 Rectangle
SvxTextEditSource::GetVisArea() const
1115 return mpImpl
->GetVisArea();
1118 Point
SvxTextEditSource::LogicToPixel( const Point
& rPoint
, const MapMode
& rMapMode
) const
1120 return mpImpl
->LogicToPixel( rPoint
, rMapMode
);
1123 Point
SvxTextEditSource::PixelToLogic( const Point
& rPoint
, const MapMode
& rMapMode
) const
1125 return mpImpl
->PixelToLogic( rPoint
, rMapMode
);
1128 void SvxTextEditSource::addRange( SvxUnoTextRangeBase
* pNewRange
)
1130 mpImpl
->addRange( pNewRange
);
1133 void SvxTextEditSource::removeRange( SvxUnoTextRangeBase
* pOldRange
)
1135 mpImpl
->removeRange( pOldRange
);
1138 const SvxUnoTextRangeBaseList
& SvxTextEditSource::getRanges() const
1140 return mpImpl
->getRanges();
1143 void SvxTextEditSource::ChangeModel( SdrModel
* pNewModel
)
1145 mpImpl
->ChangeModel( pNewModel
);
1148 void SvxTextEditSource::UpdateOutliner()
1150 mpImpl
->UpdateOutliner();
1153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */