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