LibreOffice Module svx (master)  1
unoshtxt.cxx
Go to the documentation of this file.
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 <vcl/svapp.hxx>
25 
26 #include <svx/unoshtxt.hxx>
27 #include <editeng/unoedhlp.hxx>
28 #include <svl/lstner.hxx>
29 #include <rtl/ref.hxx>
30 #include <tools/debug.hxx>
31 #include <svl/hint.hxx>
32 #include <svl/style.hxx>
33 #include <svx/svdmodel.hxx>
34 #include <svx/svdoutl.hxx>
35 #include <svx/svdobj.hxx>
36 #include <svx/svdview.hxx>
37 #include <editeng/outliner.hxx>
38 #include <editeng/unoforou.hxx>
39 #include <editeng/unoviwou.hxx>
40 #include <editeng/outlobj.hxx>
41 #include <svx/svdotext.hxx>
42 #include <svx/svdpage.hxx>
43 #include <editeng/editeng.hxx>
44 
45 #include <editeng/unotext.hxx>
46 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
48 #include <svx/svdotable.hxx>
49 #include <cell.hxx>
50 #include <unotools/configmgr.hxx>
51 
52 
53 // SvxTextEditSourceImpl
54 
55 
77 {
78 private:
79  oslInterlockedCount maRefCount;
80 
81  SdrObject* mpObject; // TTTT could be reference (?)
85  SdrModel* mpModel; // TTTT probably not needed -> use SdrModel from SdrObject (?)
86  std::unique_ptr<SdrOutliner> mpOutliner;
87  std::unique_ptr<SvxOutlinerForwarder> mpTextForwarder;
88  std::unique_ptr<SvxDrawOutlinerViewForwarder> mpViewForwarder; // if non-NULL, use GetViewModeTextForwarder text forwarder
89  css::uno::Reference< css::linguistic2::XLinguServiceManager2 > m_xLinguServiceManager;
92  bool mbIsLocked;
95  bool mbForwarderIsEditMode; // have to reflect that, since ENDEDIT can happen more often
96  bool mbShapeIsEditMode; // only true, if SdrHintKind::BeginEdit was received
97  bool mbNotificationsDisabled; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder)
99 
101 
104  std::unique_ptr<SvxDrawOutlinerViewForwarder> CreateViewForwarder();
105 
106  void SetupOutliner();
107 
108  bool HasView() const { return mpView != nullptr; }
109  bool IsEditMode() const
110  {
111  if (!mbShapeIsEditMode)
112  return false;
113  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
114  return pTextObj && pTextObj->IsTextEditActive();
115  }
116 
117  void dispose();
118 
119 public:
120  SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText );
121  SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const OutputDevice& rWindow );
122  virtual ~SvxTextEditSourceImpl() override;
123 
124  void acquire();
125  void release();
126 
127  virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
128 
131  void UpdateData();
132 
133  void addRange( SvxUnoTextRangeBase* pNewRange );
134  void removeRange( SvxUnoTextRangeBase* pOldRange );
136 
137  void lock();
138  void unlock();
139 
140  bool IsValid() const;
141 
142  Point LogicToPixel( const Point&, const MapMode& rMapMode );
143  Point PixelToLogic( const Point&, const MapMode& rMapMode );
144 
145  DECL_LINK( NotifyHdl, EENotify&, void );
146 
147  virtual void ObjectInDestruction(const SdrObject& rObject) override;
148 
149  void UpdateOutliner();
150 };
151 
152 
154  : maRefCount ( 0 ),
155  mpObject ( pObject ),
156  mpText ( pText ),
157  mpView ( nullptr ),
158  mpWindow ( nullptr ),
159  mpModel ( pObject ? &pObject->getSdrModelFromSdrObject() : nullptr ), // TTTT should be reference
160  mbDataValid ( false ),
161  mbIsLocked ( false ),
162  mbNeedsUpdate ( false ),
163  mbOldUndoMode ( false ),
164  mbForwarderIsEditMode ( false ),
165  mbShapeIsEditMode ( false ),
166  mbNotificationsDisabled ( false ),
167  mbNotifyEditOutlinerSet ( false )
168 {
169  DBG_ASSERT( mpObject, "invalid pObject!" );
170 
171  if( !mpText )
172  {
173  SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
174  if( pTextObj )
175  mpText = pTextObj->getText( 0 );
176  }
177 
178  if( mpModel )
180 
181  if( mpObject )
182  mpObject->AddObjectUser( *this );
183 }
184 
185 
187  : maRefCount ( 0 ),
188  mpObject ( &rObject ),
189  mpText ( pText ),
190  mpView ( &rView ),
191  mpWindow ( &rWindow ),
192  mpModel ( &rObject.getSdrModelFromSdrObject() ), // TTTT should be reference
193  mbDataValid ( false ),
194  mbIsLocked ( false ),
195  mbNeedsUpdate ( false ),
196  mbOldUndoMode ( false ),
197  mbForwarderIsEditMode ( false ),
198  mbShapeIsEditMode ( true ),
199  mbNotificationsDisabled ( false ),
200  mbNotifyEditOutlinerSet ( false )
201 {
202  if( !mpText )
203  {
204  SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
205  if( pTextObj )
206  mpText = pTextObj->getText( 0 );
207  }
208 
211  mpObject->AddObjectUser( *this );
212 
213  // Init edit mode state from shape info (IsTextEditActive())
215 }
216 
217 
219 {
220  DBG_ASSERT( !mbIsLocked, "text edit source was not unlocked before dispose!" );
221  if( mpObject )
222  mpObject->RemoveObjectUser( *this );
223 
224  dispose();
225 }
226 
227 
229 {
230  if( pNewRange )
231  if( std::find( mvTextRanges.begin(), mvTextRanges.end(), pNewRange ) == mvTextRanges.end() )
232  mvTextRanges.push_back( pNewRange );
233 }
234 
235 
237 {
238  if( pOldRange )
239  mvTextRanges.erase( std::remove(mvTextRanges.begin(), mvTextRanges.end(), pOldRange), mvTextRanges.end() );
240 }
241 
242 
244 {
245  osl_atomic_increment( &maRefCount );
246 }
247 
248 
250 {
251  if( ! osl_atomic_decrement( &maRefCount ) )
252  delete this;
253 }
254 
256 {
257  // #i105988 keep reference to this object
259 
260  if (SfxHintId::Dying == rHint.GetId())
261  {
262  if (&rBC == mpView)
263  {
264  mpView = nullptr;
265  mpViewForwarder.reset();
266  }
267  }
268  else if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
269  {
270  const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
271  switch( pSdrHint->GetKind() )
272  {
274  {
275  mbDataValid = false; // Text has to be get again
276 
277  if( HasView() )
278  {
279  // Update maTextOffset, object has changed
280  // Cannot call that here, since TakeTextRect() (called from there)
281  // changes outliner content.
282  // UpdateOutliner();
283 
284  // Broadcast object changes, as they might change visible attributes
285  SvxViewChangedHint aHint;
286  Broadcast( aHint );
287  }
288  break;
289  }
290 
292  if( mpObject == pSdrHint->GetObject() )
293  {
294  // Once SdrHintKind::BeginEdit is broadcast, each EditSource of
295  // AccessibleCell will handle it here and call below:
296  // mpView->GetTextEditOutliner()->SetNotifyHdl(), which
297  // will replace the Notifier for current editable cell. It
298  // is totally wrong. So add check here to avoid the
299  // incorrect replacement of notifier.
300 
301  // Currently it only happens on the editsource of
302  // AccessibleCell
303  if (mpObject && mpText)
304  {
305  sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( mpObject );
306  if(pTableObj)
307  {
308  const sdr::table::CellRef& xCell = pTableObj->getActiveCell();
309  if (xCell.is())
310  {
311  sdr::table::Cell* pCellObj = dynamic_cast< sdr::table::Cell* >( mpText );
312  if (pCellObj && xCell.get() != pCellObj)
313  break;
314  }
315  }
316  }
317  // invalidate old forwarder
318  if( !mbForwarderIsEditMode )
319  {
320  mpTextForwarder.reset();
321  }
322 
323  // register as listener - need to broadcast state change messages
324  if( mpView && mpView->GetTextEditOutliner() )
325  {
328  }
329 
330  // Only now we're really in edit mode
331  mbShapeIsEditMode = true;
332 
333  Broadcast( *pSdrHint );
334  }
335  break;
336 
338  if( mpObject == pSdrHint->GetObject() )
339  {
340  Broadcast( *pSdrHint );
341 
342  // We're no longer in edit mode
343  mbShapeIsEditMode = false;
344 
345  // remove as listener - outliner might outlive ourselves
346  if( mpView && mpView->GetTextEditOutliner() )
347  {
349  mbNotifyEditOutlinerSet = false;
350  }
351 
352  // destroy view forwarder, OutlinerView no longer
353  // valid (no need for UpdateData(), it's been
354  // synched on SdrEndTextEdit)
355  mpViewForwarder.reset();
356 
357  // Invalidate text forwarder, we might
358  // not be called again before entering edit mode a
359  // second time! Then, the old outliner might be
360  // invalid.
362  {
363  mbForwarderIsEditMode = false;
364  mpTextForwarder.reset();
365  }
366  }
367  break;
368 
370  dispose();
371  break;
372  default:
373  break;
374  }
375  }
376  else if (const SvxViewChangedHint* pViewHint = dynamic_cast<const SvxViewChangedHint*>(&rHint))
377  {
378  Broadcast( *pViewHint );
379  }
380 }
381 
382 /* this is a callback from the attached SdrObject when it is actually deleted */
384 {
385  mpObject = nullptr;
386  dispose();
387  Broadcast( SfxHint( SfxHintId::Dying ) );
388 }
389 
390 /* unregister at all objects and set all references to 0 */
392 {
393  mpTextForwarder.reset();
394  mpViewForwarder.reset();
395 
396  if( mpOutliner )
397  {
398  if( mpModel )
399  {
400  mpModel->disposeOutliner( std::move(mpOutliner) );
401  }
402  else
403  {
404  mpOutliner.reset();
405  }
406  }
407 
408  if( mpModel )
409  {
410  EndListening( *mpModel );
411  mpModel = nullptr;
412  }
413 
414  if( mpView )
415  {
416  // remove as listener - outliner might outlive ourselves
418  {
420  mbNotifyEditOutlinerSet = false;
421  }
422  EndListening( *mpView );
423  mpView = nullptr;
424  }
425 
426  if( mpObject )
427  {
428  mpObject->RemoveObjectUser( *this );
429  mpObject = nullptr;
430  }
431  mpWindow = nullptr;
432 }
433 
434 
436 {
437  // only for UAA edit source: setup outliner equivalently as in
438  // SdrTextObj::Paint(), such that formatting equals screen
439  // layout
440  if( !(mpObject && mpOutliner) )
441  return;
442 
443  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
444  if( pTextObj )
445  {
446  tools::Rectangle aPaintRect;
447  tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
448  pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect );
449 
450  // calc text offset from shape anchor
451  maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
452  }
453 }
454 
455 
457 {
458  // only for UAA edit source: update outliner equivalently as in
459  // SdrTextObj::Paint(), such that formatting equals screen
460  // layout
461  if( !(mpObject && mpOutliner) )
462  return;
463 
464  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
465  if( pTextObj )
466  {
467  tools::Rectangle aPaintRect;
468  tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
469  pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect );
470 
471  // calc text offset from shape anchor
472  maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
473  }
474 }
475 
476 
478 {
479  bool bCreated = false;
480 
481  // prevent EE/Outliner notifications during setup
483 
484  if (!mpTextForwarder)
485  {
486  if( mpOutliner == nullptr )
487  {
488  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
489  OutlinerMode nOutlMode = OutlinerMode::TextObject;
490  if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == OBJ_OUTLINETEXT )
491  nOutlMode = OutlinerMode::OutlineObject;
492 
493  mpOutliner = mpModel->createOutliner( nOutlMode );
494 
495  // Do the setup after outliner creation, would be useless otherwise
496  if( HasView() )
497  {
498  // Setup outliner _before_ filling it
499  SetupOutliner();
500  }
501 
502  mpOutliner->SetTextObjNoInit( pTextObj );
503  if( mbIsLocked )
504  {
505  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
506  mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
507  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
508  }
509 
511  {
512  if ( !m_xLinguServiceManager.is() )
513  {
514  css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
515  m_xLinguServiceManager.set(css::linguistic2::LinguServiceManager::create(xContext));
516  }
517 
518  css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator = m_xLinguServiceManager->getHyphenator();
519  if( xHyphenator.is() )
520  mpOutliner->SetHyphenator( xHyphenator );
521  }
522  }
523 
524 
526  // delay listener subscription and UAA initialization until Outliner is fully setup
527  bCreated = true;
528 
529  mbForwarderIsEditMode = false;
530  mbDataValid = false;
531  }
532 
534  {
535  mpTextForwarder->flushCache();
536 
537  std::optional<OutlinerParaObject> pOutlinerParaObject;
538  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
539  if( pTextObj && pTextObj->getActiveText() == mpText )
540  pOutlinerParaObject = pTextObj->CreateEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
541  bool bOwnParaObj(false);
542 
543  if( pOutlinerParaObject )
544  bOwnParaObj = true; // text edit active
545  else if (mpText->GetOutlinerParaObject())
546  pOutlinerParaObject = *mpText->GetOutlinerParaObject();
547 
548  if( pOutlinerParaObject && ( bOwnParaObj || !mpObject->IsEmptyPresObj() || mpObject->getSdrPageFromSdrObject()->IsMasterPage() ) )
549  {
550  // tdf#72776: do not set empty text to SdrOutliner, if it is already set
551  if( !mpOutliner->GetEditEngine().GetTextLen() || pOutlinerParaObject->Count() > 1 || ( pOutlinerParaObject->Count() == 1 &&
552  !pOutlinerParaObject->GetTextObject().GetText(0).isEmpty() ) )
553  mpOutliner->SetText( *pOutlinerParaObject );
554 
555  // put text to object and set EmptyPresObj to FALSE
556  if( mpText && bOwnParaObj && mpObject->IsEmptyPresObj() && pTextObj->IsReallyEdited() )
557  {
558  mpObject->SetEmptyPresObj( false );
559  static_cast< SdrTextObj* >( mpObject)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject, mpText );
560 
561  // #i103982# Here, due to mpObject->NbcSetOutlinerParaObjectForText, we LOSE ownership of the
562  // OPO, so do NOT delete it when leaving this method (!)
563  bOwnParaObj = false;
564  }
565  }
566  else
567  {
568  bool bVertical = pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical();
569 
570  // set objects style sheet on empty outliner
572  if( pPool )
573  mpOutliner->SetStyleSheetPool( pPool );
574 
576  if( pStyleSheet )
577  mpOutliner->SetStyleSheet( 0, pStyleSheet );
578 
579  if( bVertical )
580  {
581  mpOutliner->SetVertical( pOutlinerParaObject->GetVertical());
582  mpOutliner->SetRotation( pOutlinerParaObject->GetRotation());
583  }
584  }
585 
586  // maybe we have to set the border attributes
587  if (mpOutliner->GetParagraphCount()==1)
588  {
589  // if we only have one paragraph we check if it is empty
590  OUString aStr(mpOutliner->GetText(mpOutliner->GetParagraph(0)));
591 
592  if (aStr.isEmpty())
593  {
594  // its empty, so we have to force the outliner to initialise itself
595  mpOutliner->SetText( "", mpOutliner->GetParagraph( 0 ) );
596 
597  if(mpObject->GetStyleSheet())
598  mpOutliner->SetStyleSheet( 0, mpObject->GetStyleSheet());
599  }
600  }
601 
602  mbDataValid = true;
603  }
604 
605  if( bCreated && mpOutliner && HasView() )
606  {
607  // register as listener - need to broadcast state change messages
608  // registration delayed until outliner is completely set up
609  mpOutliner->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
610  }
611 
612  // prevent EE/Outliner notifications during setup
613  mbNotificationsDisabled = false;
614 
615  return mpTextForwarder.get();
616 }
617 
618 
620 {
621  if( !mpTextForwarder && HasView() )
622  {
623  SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner();
624 
625  if( pEditOutliner )
626  {
628  mbForwarderIsEditMode = true;
629  }
630  }
631 
632  return mpTextForwarder.get();
633 }
634 
635 
637 {
638  if( mpObject == nullptr )
639  return nullptr;
640 
641  if( mpModel == nullptr )
643 
644  // distinguish the cases
645  // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner
646  // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code)
647  if( HasView() )
648  {
650  {
651  // forwarder mismatch - create new
652  mpTextForwarder.reset();
653  }
654 
655  if( IsEditMode() )
656  return GetEditModeTextForwarder();
657  else
659  }
660  else
661  {
662  // tdf#123470 if the text edit mode of the shape is active, then we
663  // cannot trust a previously cached TextForwarder state as the text may
664  // be out of date, so force a refetch in that case.
665  if (IsEditMode())
666  {
667  assert(!mbForwarderIsEditMode); // because without a view there is no other option except !mbForwarderIsEditMode
668  bool bTextEditActive = false;
669  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(mpObject);
670  // similar to the GetBackgroundTextForwarder check, see if the text edit is active
671  if (pTextObj && pTextObj->getActiveText() == mpText && pTextObj->CanCreateEditOutlinerParaObject())
672  bTextEditActive = true; // text edit active
673  if (bTextEditActive)
674  mbDataValid = false;
675  }
676 
678  }
679 }
680 
681 std::unique_ptr<SvxDrawOutlinerViewForwarder> SvxTextEditSourceImpl::CreateViewForwarder()
682 {
684  {
685  // register as listener - need to broadcast state change messages
688 
689  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
690  if( pTextObj )
691  {
692  tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
694 
695  return std::unique_ptr<SvxDrawOutlinerViewForwarder>(new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ));
696  }
697  }
698 
699  return nullptr;
700 }
701 
703 {
704  if( mpObject == nullptr )
705  return nullptr;
706 
707  if( mpModel == nullptr )
709 
710  // shall we delete?
711  if( mpViewForwarder )
712  {
713  if( !IsEditMode() )
714  {
715  // destroy all forwarders (no need for UpdateData(),
716  // it's been synched on SdrEndTextEdit)
717  mpViewForwarder.reset();
718  }
719  }
720  // which to create? Directly in edit mode, create new, or none?
721  else if( mpView )
722  {
723  if( IsEditMode() )
724  {
725  // create new view forwarder
727  }
728  else if( bCreate )
729  {
730  // dispose old text forwarder
731  UpdateData();
732 
733  mpTextForwarder.reset();
734 
735  // enter edit mode
737 
739  {
740  SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
741  if (pTextObj && pTextObj->IsTextEditActive())
742  {
743  // create new view forwarder
745  }
746  else
747  {
748  // failure. Somehow, SdrBeginTextEdit did not set
749  // our SdrTextObj into edit mode
751  }
752  }
753  }
754  }
755 
756  return mpViewForwarder.get();
757 }
758 
759 
761 {
762  // if we have a view and in edit mode, we're working with the
763  // DrawOutliner. Thus, all changes made on the text forwarder are
764  // reflected on the view and committed to the model on
765  // SdrEndTextEdit(). Thus, no need for explicit updates here.
766  if( HasView() && IsEditMode() )
767  return;
768 
769  if( mbIsLocked )
770  {
771  mbNeedsUpdate = true;
772  }
773  else
774  {
775  if( mpOutliner && mpObject && mpText )
776  {
777  SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
778  if( pTextObj )
779  {
780  if( mpOutliner->GetParagraphCount() != 1 || mpOutliner->GetEditEngine().GetTextLen( 0 ) )
781  {
782  pTextObj->NbcSetOutlinerParaObjectForText( mpOutliner->CreateParaObject(), mpText );
783  }
784  else
785  {
786  pTextObj->NbcSetOutlinerParaObjectForText( std::nullopt, mpText );
787  }
788  }
789 
790  if( mpObject->IsEmptyPresObj() )
791  mpObject->SetEmptyPresObj(false);
792  }
793  }
794 }
795 
797 {
798  // if this assert ever fires, we will need to make this a counter instead of a boolean
799  assert(!mbIsLocked && "cannot nest these loc() calls");
800  mbIsLocked = true;
801  if( mpOutliner )
802  {
803  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
804  mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
805  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
806  }
807 }
808 
810 {
811  mbIsLocked = false;
812 
813  if( mbNeedsUpdate )
814  {
815  UpdateData();
816  mbNeedsUpdate = false;
817  }
818 
819  if( mpOutliner )
820  {
821  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( true );
822  const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode );
823  }
824 }
825 
827 {
828  return mpView && mpWindow;
829 }
830 
831 Point SvxTextEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode )
832 {
833  // The responsibilities of ViewForwarder happen to be
834  // somewhat mixed in this case. On the one hand, we need the
835  // different interface queries on the SvxEditSource interface,
836  // since we need both VisAreas. On the other hand, if an
837  // EditViewForwarder exists, maTextOffset does not remain static,
838  // but may change with every key press.
839  if( IsEditMode() )
840  {
841  SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
842 
843  if( pForwarder )
844  return pForwarder->LogicToPixel( rPoint, rMapMode );
845  }
846  else if( IsValid() && mpModel )
847  {
848  Point aPoint1( rPoint );
849  aPoint1.AdjustX(maTextOffset.X() );
850  aPoint1.AdjustY(maTextOffset.Y() );
851 
852  Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode,
853  MapMode(mpModel->GetScaleUnit()) ) );
854  MapMode aMapMode(mpWindow->GetMapMode());
855  aMapMode.SetOrigin(Point());
856  return mpWindow->LogicToPixel( aPoint2, aMapMode );
857  }
858 
859  return Point();
860 }
861 
862 Point SvxTextEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode )
863 {
864  // The responsibilities of ViewForwarder happen to be
865  // somewhat mixed in this case. On the one hand, we need the
866  // different interface queries on the SvxEditSource interface,
867  // since we need both VisAreas. On the other hand, if an
868  // EditViewForwarder exists, maTextOffset does not remain static,
869  // but may change with every key press.
870  if( IsEditMode() )
871  {
872  SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
873 
874  if( pForwarder )
875  return pForwarder->PixelToLogic( rPoint, rMapMode );
876  }
877  else if( IsValid() && mpModel )
878  {
879  MapMode aMapMode(mpWindow->GetMapMode());
880  aMapMode.SetOrigin(Point());
881  Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) );
882  Point aPoint2( OutputDevice::LogicToLogic( aPoint1,
884  rMapMode ) );
885  aPoint2.AdjustX( -(maTextOffset.X()) );
886  aPoint2.AdjustY( -(maTextOffset.Y()) );
887 
888  return aPoint2;
889  }
890 
891  return Point();
892 }
893 
894 IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify&, rNotify, void)
895 {
896  if( !mbNotificationsDisabled )
897  {
898  std::unique_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( &rNotify) );
899 
900  if (aHint)
901  Broadcast(*aHint);
902  }
903 }
904 
906 {
907  mpImpl = new SvxTextEditSourceImpl( pObject, pText );
908 }
909 
910 
912 {
913  mpImpl = new SvxTextEditSourceImpl( rObj, pText, rView, rWindow );
914 }
915 
916 
918 {
919  mpImpl = pImpl;
920 }
921 
922 
924 {
925  ::SolarMutexGuard aGuard;
926  mpImpl.clear();
927 }
928 
929 
930 std::unique_ptr<SvxEditSource> SvxTextEditSource::Clone() const
931 {
932  return std::unique_ptr<SvxEditSource>(new SvxTextEditSource( mpImpl.get() ));
933 }
934 
935 
937 {
938  return mpImpl->GetTextForwarder();
939 }
940 
941 
943 {
944  return mpImpl->GetEditViewForwarder( bCreate );
945 }
946 
947 
949 {
950  return this;
951 }
952 
953 
955 {
956  mpImpl->UpdateData();
957 }
958 
960 {
961  return *mpImpl;
962 }
963 
965 {
966  mpImpl->lock();
967 }
968 
970 {
971  mpImpl->unlock();
972 }
973 
975 {
976  return mpImpl->IsValid();
977 }
978 
979 Point SvxTextEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
980 {
981  return mpImpl->LogicToPixel( rPoint, rMapMode );
982 }
983 
984 Point SvxTextEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
985 {
986  return mpImpl->PixelToLogic( rPoint, rMapMode );
987 }
988 
990 {
991  mpImpl->addRange( pNewRange );
992 }
993 
995 {
996  mpImpl->removeRange( pOldRange );
997 }
998 
1000 {
1001  return mpImpl->getRanges();
1002 }
1003 
1005 {
1006  mpImpl->UpdateOutliner();
1007 }
1008 
1009 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
VclPtr< const OutputDevice > mpWindow
Definition: unoshtxt.cxx:84
virtual void removeRange(SvxUnoTextRangeBase *pOldRange) override
Definition: unoshtxt.cxx:994
virtual Point LogicToPixel(const Point &, const MapMode &) const override
Definition: unoshtxt.cxx:979
OutlinerMode
SdrHintKind GetKind() const
Definition: svdmodel.hxx:132
virtual const tools::Rectangle & GetCurrentBoundRect() const
Definition: svdobj.cxx:957
virtual SdrEndTextEditKind SdrEndTextEdit(bool bDontDeleteReally=false)
Definition: svdedxv.cxx:1422
std::unique_ptr< SvxDrawOutlinerViewForwarder > CreateViewForwarder()
Definition: unoshtxt.cxx:681
void SetupOutlinerFormatting(SdrOutliner &rOutl, tools::Rectangle &rPaintRect) const
Setup given Outliner equivalently to SdrTextObj::Paint()
Definition: svdotext.cxx:1299
bool GetVertical() const
std::unique_ptr< SvxDrawOutlinerViewForwarder > mpViewForwarder
Definition: unoshtxt.cxx:88
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
void RemoveObjectUser(sdr::ObjectUser &rOldUser)
Definition: svdobj.cxx:233
virtual SdrText * getText(sal_Int32 nIndex) const override
returns the nth available text.
Definition: svdotext.cxx:2064
Point PixelToLogic(const Point &, const MapMode &rMapMode)
Definition: unoshtxt.cxx:862
static::std::unique_ptr< SfxHint > EENotification2Hint(EENotify const *aNotify)
bool IsTextFrame() const
Definition: svdotext.hxx:334
SdrModel * mpModel
Definition: unoshtxt.cxx:85
virtual std::unique_ptr< SvxEditSource > Clone() const override
Definition: unoshtxt.cxx:930
bool IsInserted() const
Definition: svdobj.hxx:743
const MapMode & GetMapMode() const
void SetEmptyPresObj(bool bEpt)
Definition: svdobj.cxx:2544
oslInterlockedCount maRefCount
Definition: unoshtxt.cxx:79
virtual SdrObjKind GetObjIdentifier() const
Definition: svdobj.cxx:659
bool IsTextEditActive() const
Definition: svdotext.hxx:354
SbxObjectRef mpObject
std::unique_ptr< SvxOutlinerForwarder > mpTextForwarder
Definition: unoshtxt.cxx:87
SfxHintId GetId() const
void AddObjectUser(sdr::ObjectUser &rNewUser)
Definition: svdobj.cxx:228
virtual ~SvxTextEditSourceImpl() override
Definition: unoshtxt.cxx:218
OutlinerParaObject * GetOutlinerParaObject()
Definition: svdtext.cxx:89
SvxUnoTextRangeBaseVec mvTextRanges
Definition: unoshtxt.cxx:100
MapUnit GetScaleUnit() const
Definition: svdmodel.hxx:369
virtual SvxTextForwarder * GetTextForwarder() override
Definition: unoshtxt.cxx:936
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:269
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: unoshtxt.cxx:255
static bool IsFuzzing()
std::vector< SvxUnoTextRangeBase * > SvxUnoTextRangeBaseVec
virtual bool IsReallyEdited() const
returns true only if we are in edit mode and the user actually changed anything
Definition: svdotext.cxx:1677
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2225
std::unique_ptr< SdrOutliner > mpOutliner
Definition: unoshtxt.cxx:86
virtual SvxEditViewForwarder * GetEditViewForwarder(bool bCreate=false) override
Definition: unoshtxt.cxx:942
std::unique_ptr< SdrOutliner > createOutliner(OutlinerMode nOutlinerMode)
Definition: svdmodel.cxx:1737
SvxTextForwarder * GetEditModeTextForwarder()
Definition: unoshtxt.cxx:619
void SetNotifyHdl(const Link< EENotify &, void > &rLink)
virtual ~SvxTextEditSource() override
Definition: unoshtxt.cxx:923
void NbcSetOutlinerParaObjectForText(std::optional< OutlinerParaObject > pTextObject, SdrText *pText)
Definition: svdotext.cxx:1343
const EditTextObject & GetTextObject() const
const SdrOutliner * GetTextEditOutliner() const
Definition: svdedxv.hxx:243
VclPtr< vcl::Window > mpWindow
Point LogicToPixel(const Point &, const MapMode &rMapMode)
Definition: unoshtxt.cxx:831
void UpdateOutlinerFormatting(SdrOutliner &rOutl, tools::Rectangle &rPaintRect) const
Update given Outliner equivalently to SdrTextObj::Paint()
Definition: svdotext.cxx:1305
SvxEditViewForwarder * GetEditViewForwarder(bool)
Definition: unoshtxt.cxx:702
#define DBG_ASSERT(sCon, aError)
void removeRange(SvxUnoTextRangeBase *pOldRange)
Definition: unoshtxt.cxx:236
virtual SfxStyleSheet * GetTextStyleSheetForObject(SdrObject *pObj) const
Definition: svdpage.cxx:1776
css::uno::Reference< css::linguistic2::XLinguServiceManager2 > m_xLinguServiceManager
Definition: unoshtxt.cxx:89
SvxTextEditSourceImpl(SdrObject *pObject, SdrText *pText)
Definition: unoshtxt.cxx:153
virtual OUString GetText(sal_Int32 nPara) const =0
virtual void addRange(SvxUnoTextRangeBase *pNewRange) override
Definition: unoshtxt.cxx:989
SvxTextForwarder * GetTextForwarder()
Definition: unoshtxt.cxx:636
virtual bool SdrBeginTextEdit(SdrObject *pObj, SdrPageView *pPV=nullptr, vcl::Window *pWin=nullptr, bool bIsNewObj=false, SdrOutliner *pGivenOutliner=nullptr, OutlinerView *pGivenOutlinerView=nullptr, bool bDontDeleteOutliner=false, bool bOnlyOneView=false, bool bGrabFocus=true)
Definition: svdedxv.cxx:1070
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:279
const OutlinerView * GetTextEditOutlinerView() const
Definition: svdedxv.hxx:251
bool IsMasterPage() const
Definition: svdpage.hxx:458
virtual const SvxUnoTextRangeBaseVec & getRanges() const override
Definition: unoshtxt.cxx:999
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
bool IsEditMode() const
Definition: unoshtxt.cxx:109
virtual SdrText * getActiveText() const
returns the currently active text.
Definition: svdotext.cxx:2055
Abstract DrawObject.
Definition: svdobj.hxx:260
virtual SdrInventor GetObjInventor() const
Definition: svdobj.cxx:654
virtual Point LogicToPixel(const Point &rPoint, const MapMode &rMapMode) const =0
bool SetUpdateLayout(bool bUpdate, bool bRestoring=false)
constexpr Point TopLeft() const
SvxTextEditSource(SdrObject *pObj, SdrText *pText)
Definition: unoshtxt.cxx:905
virtual Point PixelToLogic(const Point &rPoint, const MapMode &rMapMode) const =0
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
bool CanCreateEditOutlinerParaObject() const
Definition: svdotext.cxx:863
virtual SfxBroadcaster & GetBroadcaster() const override
Definition: unoshtxt.cxx:959
sal_Int32 Count() const
rtl::Reference< SvxTextEditSourceImpl > mpImpl
Definition: unoshtxt.hxx:84
void Broadcast(const SfxHint &rHint)
bool IsEffectivelyVertical() const
virtual void ObjectInDestruction(const SdrObject &rObject) override
Definition: unoshtxt.cxx:383
bool IsValid() const
Definition: unoshtxt.cxx:826
IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify &, rNotify, void)
Definition: unoshtxt.cxx:894
TextRotation GetRotation() const
bool HasView() const
Definition: unoshtxt.cxx:108
SfxStyleSheetBasePool * GetStyleSheetPool() const
Definition: svdmodel.hxx:540
void EnableUndo(bool bEnable)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
Reference< XComponentContext > getProcessComponentContext()
UnoViewSharedPtr mpView
std::optional< OutlinerParaObject > CreateEditOutlinerParaObject() const
Definition: svdotext.cxx:872
virtual SvxViewForwarder * GetViewForwarder() override
Definition: unoshtxt.cxx:948
DECL_LINK(NotifyHdl, EENotify &, void)
void disposeOutliner(std::unique_ptr< SdrOutliner > pOutliner)
Definition: svdmodel.cxx:1754
SdrObjKind GetTextKind() const
Definition: svdotext.hxx:349
TitleText, special text object for StarDraw.
Definition: svdobjkind.hxx:44
virtual Point PixelToLogic(const Point &, const MapMode &) const override
Definition: unoshtxt.cxx:984
virtual bool IsValid() const override
Definition: unoshtxt.cxx:974
SdrObject * mpObject
Definition: unoshtxt.cxx:81
void addRange(SvxUnoTextRangeBase *pNewRange)
Definition: unoshtxt.cxx:228
aStr
const sdr::table::CellRef & getActiveCell() const
The active table has the focus or is currently edited.
Definition: svdotable.cxx:1572
const SvxUnoTextRangeBaseVec & getRanges() const
Definition: unoshtxt.cxx:135
SvxTextForwarder * GetBackgroundTextForwarder()
Definition: unoshtxt.cxx:477
virtual void UpdateData() override
Definition: unoshtxt.cxx:954
const SdrObject * GetObject() const
Definition: svdmodel.hxx:131
bool IsEmptyPresObj() const
Definition: svdobj.hxx:831