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