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