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