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