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