xref: /trunk/main/svx/source/unodraw/unoshtxt.cxx (revision 4d7c9de0)
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