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