LibreOffice Module svx (master)  1
viewobjectcontactofunocontrol.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 
26 #include <svx/svdouno.hxx>
27 #include <svx/svdpagv.hxx>
28 #include <svx/svdview.hxx>
29 #include <svx/sdrpagewindow.hxx>
30 
31 #include <com/sun/star/awt/XControl.hpp>
32 #include <com/sun/star/awt/XControlModel.hpp>
33 #include <com/sun/star/awt/XControlContainer.hpp>
34 #include <com/sun/star/awt/XWindow2.hpp>
35 #include <com/sun/star/awt/PosSize.hpp>
36 #include <com/sun/star/awt/XView.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/lang/XComponent.hpp>
39 #include <com/sun/star/awt/InvalidateStyle.hpp>
40 #include <com/sun/star/util/XModeChangeListener.hpp>
41 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
42 #include <com/sun/star/uno/XComponentContext.hpp>
43 #include <com/sun/star/container/XContainerListener.hpp>
44 #include <com/sun/star/container/XContainer.hpp>
45 
46 #include <vcl/canvastools.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/window.hxx>
51 #include <cppuhelper/implbase.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <tools/debug.hxx>
58 
59 /*
60 
61 Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
62 specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
63 window as child of the document window, and coupling this Window to a drawing layer object, makes things
64 difficult sometimes.
65 
66 Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
67 verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
68 an automatic test for one or more of those issues for which this is possible :)
69 
70 https://bz.apache.org/ooo/show_bug.cgi?id=105992
71 zooming documents containing (alive) form controls improperly positions the controls
72 
73 https://bz.apache.org/ooo/show_bug.cgi?id=104362
74 crash when copy a control
75 
76 https://bz.apache.org/ooo/show_bug.cgi?id=104544
77 Gridcontrol duplicated after design view on/off
78 
79 https://bz.apache.org/ooo/show_bug.cgi?id=102089
80 print preview shows control elements with property printable=false
81 
82 https://bz.apache.org/ooo/show_bug.cgi?id=102090
83 problem with setVisible on TextControl
84 
85 https://bz.apache.org/ooo/show_bug.cgi?id=103138
86 loop when insert a control in draw
87 
88 https://bz.apache.org/ooo/show_bug.cgi?id=101398
89 initially-displaying a document with many controls is very slow
90 
91 https://bz.apache.org/ooo/show_bug.cgi?id=72429
92 repaint error in form wizard in bugdoc database
93 
94 https://bz.apache.org/ooo/show_bug.cgi?id=72694
95 form control artifacts when scrolling a text fast
96 
97 */
98 
99 
100 namespace sdr::contact {
101 
102 
103  using namespace ::com::sun::star::awt::InvalidateStyle;
104  using ::com::sun::star::uno::Reference;
105  using ::com::sun::star::uno::XInterface;
106  using ::com::sun::star::uno::UNO_QUERY;
107  using ::com::sun::star::uno::UNO_QUERY_THROW;
108  using ::com::sun::star::uno::Exception;
109  using ::com::sun::star::uno::RuntimeException;
110  using ::com::sun::star::awt::XControl;
111  using ::com::sun::star::awt::XControlModel;
112  using ::com::sun::star::awt::XControlContainer;
113  using ::com::sun::star::awt::XWindow2;
114  using ::com::sun::star::awt::XWindowListener;
115  using ::com::sun::star::awt::PosSize::POSSIZE;
116  using ::com::sun::star::awt::XView;
117  using ::com::sun::star::awt::WindowEvent;
119  using ::com::sun::star::lang::XComponent;
120  using ::com::sun::star::awt::XWindowPeer;
121  using ::com::sun::star::beans::XPropertyChangeListener;
122  using ::com::sun::star::util::XModeChangeListener;
123  using ::com::sun::star::util::XModeChangeBroadcaster;
124  using ::com::sun::star::util::ModeChangeEvent;
125  using ::com::sun::star::lang::EventObject;
126  using ::com::sun::star::beans::PropertyChangeEvent;
127  using ::com::sun::star::container::XContainerListener;
128  using ::com::sun::star::container::XContainer;
129  using ::com::sun::star::container::ContainerEvent;
130  using ::com::sun::star::uno::Any;
131 
132  namespace {
133 
134  class ControlHolder
135  {
136  private:
137  Reference< XControl > m_xControl;
138  Reference< XWindow2 > m_xControlWindow;
139  Reference< XView > m_xControlView;
140 
141  public:
142  ControlHolder()
143  :m_xControl()
144  ,m_xControlWindow()
145  ,m_xControlView()
146  {
147  }
148 
149  explicit ControlHolder( const Reference< XControl >& _rxControl )
150  :m_xControl()
151  ,m_xControlWindow()
152  ,m_xControlView()
153  {
154  *this = _rxControl;
155  }
156 
157  ControlHolder& operator=( const Reference< XControl >& _rxControl )
158  {
159  clear();
160 
161  m_xControl = _rxControl;
162  if ( m_xControl.is() )
163  {
164  m_xControlWindow.set( m_xControl, UNO_QUERY );
165  m_xControlView.set( m_xControl, UNO_QUERY );
166  if ( !m_xControlWindow.is() || !m_xControlView.is() )
167  {
168  OSL_FAIL( "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
169  clear();
170  }
171  }
172 
173  return *this;
174  }
175 
176  public:
177  bool is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
178  void clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
179 
180  // delegators for the methods of the UNO interfaces
181  // Note all those will crash if called for a NULL object.
182  bool isDesignMode() const { return m_xControl->isDesignMode(); }
183  void setDesignMode( const bool _bDesign ) const { m_xControl->setDesignMode( _bDesign ); }
184  bool isVisible() const { return m_xControlWindow->isVisible(); }
185  void setVisible( const bool _bVisible ) const { m_xControlWindow->setVisible( _bVisible ); }
186  Reference< XControlModel >
187  getModel() const { return m_xControl->getModel(); }
188  void setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
189 
190  void addWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->addWindowListener( _l ); }
191  void removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
192  void setPosSize( const tools::Rectangle& _rPosSize ) const;
194  getPosSize() const;
195  void setZoom( const ::basegfx::B2DVector& _rScale ) const;
197  getZoom() const;
198 
199  void invalidate() const;
200 
201  public:
202  const Reference< XControl >& getControl() const { return m_xControl; }
203  };
204 
205  bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
206  {
207  return _rControl.getControl() == _rxCompare;
208  }
209 
210  bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
211  {
212  return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
213  }
214 
215  }
216 
217  void ControlHolder::setPosSize( const tools::Rectangle& _rPosSize ) const
218  {
219  // no check whether we're valid, this is the responsibility of the caller
220 
221  // don't call setPosSize when pos/size did not change #i104181#
222  ::tools::Rectangle aCurrentRect( getPosSize() );
223  if ( aCurrentRect != _rPosSize )
224  {
225  m_xControlWindow->setPosSize(
226  _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
227  POSSIZE
228  );
229  }
230  }
231 
232 
233  ::tools::Rectangle ControlHolder::getPosSize() const
234  {
235  // no check whether we're valid, this is the responsibility of the caller
236  return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
237  }
238 
239 
240  void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
241  {
242  // no check whether we're valid, this is the responsibility of the caller
243  m_xControlView->setZoom( static_cast<float>(_rScale.getX()), static_cast<float>(_rScale.getY()) );
244  }
245 
246 
247  void ControlHolder::invalidate() const
248  {
249  Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
250  if ( xPeer.is() )
251  {
252  VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xPeer );
253  OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
254  if ( pWindow )
255  pWindow->Invalidate();
256  }
257  }
258 
259 
260  ::basegfx::B2DVector ControlHolder::getZoom() const
261  {
262  // no check whether we're valid, this is the responsibility of the caller
263 
264  // Argh. Why does XView have a setZoom only, but not a getZoom?
265  VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
266  OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
267 
268  ::basegfx::B2DVector aZoom( 1, 1 );
269  if ( pWindow )
270  {
271  const Fraction& rZoom( pWindow->GetZoom() );
272  aZoom.setX( static_cast<double>(rZoom) );
273  aZoom.setY( static_cast<double>(rZoom) );
274  }
275  return aZoom;
276  }
277 
278  namespace UnoControlContactHelper {
279 
282  static void adjustControlGeometry_throw( const ControlHolder& _rControl, const tools::Rectangle& _rLogicBoundingRect,
283  const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
284  {
285  OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
286  if ( !_rControl.is() )
287  return;
288 
289  #if OSL_DEBUG_LEVEL > 0
290  ::basegfx::B2DTuple aViewScale, aViewTranslate;
291  double nViewRotate(0), nViewShearX(0);
292  _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
293 
294  ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
295  double nZoomRotate(0), nZoomShearX(0);
296  _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
297  #endif
298 
299  // transform the logic bound rect, using the view transformation, to pixel coordinates
300  ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
301  aTopLeft *= _rViewTransformation;
302  ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
303  aBottomRight *= _rViewTransformation;
304 
305  const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
306  static_cast<tools::Long>(std::round(aTopLeft.getY())),
307  static_cast<tools::Long>(std::round(aBottomRight.getX())),
308  static_cast<tools::Long>(std::round(aBottomRight.getY())));
309  _rControl.setPosSize( aPaintRectPixel );
310 
311  // determine the scale from the current view transformation, and the normalization matrix
312  ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
313  ::basegfx::B2DVector aScale, aTranslate;
314  double fRotate, fShearX;
315  aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
316  _rControl.setZoom( aScale );
317  }
318 
321  static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
322  {
323  try
324  {
325  Reference< XComponent > xControlComp = _rControl.getControl();
326  if ( xControlComp.is() )
327  xControlComp->dispose();
328  }
329  catch( const Exception& )
330  {
332  }
333  _rControl.clear();
334  }
335 
336  }
337 
338  namespace {
339 
342  class IPageViewAccess
343  {
344  public:
347  virtual bool isDesignMode() const = 0;
348 
351  virtual Reference< XControlContainer >
352  getControlContainer( const OutputDevice& _rDevice ) const = 0;
353 
356  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const = 0;
357 
358  protected:
359  ~IPageViewAccess() {}
360  };
361 
364  class SdrPageViewAccess : public IPageViewAccess
365  {
367  public:
368  explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
369 
370  virtual ~SdrPageViewAccess() {}
371 
372  virtual bool isDesignMode() const override;
373  virtual Reference< XControlContainer >
374  getControlContainer( const OutputDevice& _rDevice ) const override;
375  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
376  };
377 
378  }
379 
380  bool SdrPageViewAccess::isDesignMode() const
381  {
382  return m_rPageView.GetView().IsDesignMode();
383  }
384 
385 
386  Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
387  {
388  Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
389  DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
390  "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
391  return xControlContainer;
392  }
393 
394 
395  bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
396  {
397  return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
398  }
399 
400  namespace {
401 
405  class InvisibleControlViewAccess : public IPageViewAccess
406  {
407  private:
408  Reference< XControlContainer >& m_rControlContainer;
409  public:
410  explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
411  :m_rControlContainer( _inout_ControlContainer )
412  {
413  }
414 
415  virtual ~InvisibleControlViewAccess() {}
416 
417  virtual bool isDesignMode() const override;
418  virtual Reference< XControlContainer >
419  getControlContainer( const OutputDevice& _rDevice ) const override;
420  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
421  };
422 
423  }
424 
425  bool InvisibleControlViewAccess::isDesignMode() const
426  {
427  return true;
428  }
429 
430 
431  Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
432  {
433  if ( !m_rControlContainer.is() )
434  {
435  const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
436  OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
437  if ( pWindow )
438  m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< vcl::Window* >( pWindow ) );
439  }
440  return m_rControlContainer;
441  }
442 
443 
444  bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
445  {
446  return false;
447  }
448 
449  namespace {
450 
451  //= DummyPageViewAccess
452 
460  class DummyPageViewAccess : public IPageViewAccess
461  {
462  public:
463  DummyPageViewAccess()
464  {
465  }
466 
467  virtual ~DummyPageViewAccess() {}
468 
469  virtual bool isDesignMode() const override;
470  virtual Reference< XControlContainer >
471  getControlContainer( const OutputDevice& _rDevice ) const override;
472  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
473  };
474 
475  }
476 
477  bool DummyPageViewAccess::isDesignMode() const
478  {
479  return true;
480  }
481 
482 
483  Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
484  {
485  return nullptr;
486  }
487 
488 
489  bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
490  {
491  return true;
492  }
493 
494 
495  //= ViewObjectContactOfUnoControl_Impl
496 
497  typedef ::cppu::WeakImplHelper < XWindowListener
498  , XPropertyChangeListener
499  , XContainerListener
500  , XModeChangeListener
502 
505  {
506  private:
507  // tdf#41935 note that access to members is protected with SolarMutex;
508  // the class previously had its own mutex but that is prone to deadlock
509 
512 
515 
517  ControlHolder m_aControl;
518 
520  Reference< XContainer > m_xContainer;
521 
524 
527 
530 
532  {
536  };
539 
541 
542  public:
546 
549  void dispose();
550 
553  bool isDisposed() const { return impl_isDisposed_nofail(); }
554 
560  bool getUnoObject( SdrUnoObj*& _out_rpObject ) const;
561 
572  void ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
573 
578  const ControlHolder&
579  getExistentControl() const { return m_aControl; }
580 
581  bool
582  hasControl() const { return m_aControl.is(); }
583 
590  void positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
591 
597  bool isPrintableControl() const;
598 
602  void setControlDesignMode( bool _bDesignMode ) const;
603 
607  bool isControlVisible() const { return m_bControlIsVisible; }
608 
610  static bool
612  IPageViewAccess const & _rPageView,
613  const OutputDevice& _rDevice,
614  const SdrUnoObj& _rUnoObject,
615  const basegfx::B2DHomMatrix& _rInitialViewTransformation,
616  const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
617  ControlHolder& _out_rControl
618  );
619 
622  {
623  ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
624  return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
625  }
626 
627  protected:
628  virtual ~ViewObjectContactOfUnoControl_Impl() override;
629 
630  // XEventListener
631  virtual void SAL_CALL disposing( const EventObject& Source ) override;
632 
633  // XWindowListener
634  virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
635  virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
636  virtual void SAL_CALL windowShown( const EventObject& e ) override;
637  virtual void SAL_CALL windowHidden( const EventObject& e ) override;
638 
639  // XPropertyChangeListener
640  virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
641 
642  // XModeChangeListener
643  virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
644 
645  // XContainerListener
646  virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
647  virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
648  virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
649 
650  private:
673  bool impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
674 
689 
717  static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
718  IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
719 
725  void impl_switchControlListening_nothrow( bool _bStart );
726 
732  void impl_switchContainerListening_nothrow( bool _bStart );
733 
736  void impl_switchDesignModeListening_nothrow( bool _bStart );
737 
746  void impl_switchPropertyListening_nothrow( bool _bStart );
747 
752  void impl_dispose_nothrow( bool _bAlsoDisposeControl );
753 
757  bool impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
758 
767  {
768  DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
769  return m_eControlDesignMode == eDesign;
770  }
771 
775  IPageViewAccess const & _rPageView,
776  const OutputDevice& _rDevice,
777  const basegfx::B2DHomMatrix& _rInitialViewTransformation
778  );
779 
781  };
782 
783  namespace {
784 
785  class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
786  {
787  private:
788  typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D BufferedDecompositionPrimitive2D;
789 
790  protected:
791  virtual void
792  get2DDecomposition(
794  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
795  ) const override;
796 
797  virtual void create2DDecomposition(
799  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
800  ) const override;
801 
802  virtual ::basegfx::B2DRange
803  getB2DRange(
804  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
805  ) const override;
806 
807  public:
808  explicit LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
809  :m_pVOCImpl( _pVOCImpl )
810  {
811  ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
812  getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
813  }
814 
815  virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
816 
817  // declare unique ID for this primitive class
818  virtual sal_uInt32 getPrimitive2DID() const override;
819 
820  static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
821 
822  private:
823  void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
824  {
825  if ( !_rViewInformation.getViewport().isEmpty() )
826  m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
827  }
828 
829  private:
836  };
837 
838  }
839 
841  :m_pAntiImpl( _pAntiImpl )
842  ,m_bCreatingControl( false )
843  ,m_pOutputDeviceForWindow( nullptr )
844  ,m_bControlIsVisible( false )
845  ,m_bIsDesignModeListening( false )
846  ,m_eControlDesignMode( eUnknown )
847  ,m_aZoomLevelNormalization()
848  {
849  DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
850 
851  const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
853 
854  #if OSL_DEBUG_LEVEL > 0
855  ::basegfx::B2DVector aScale, aTranslate;
856  double fRotate, fShearX;
857  m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
858  #endif
859 
860  ::basegfx::B2DHomMatrix aScaleNormalization;
861  const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
862  aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
863  aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
864  m_aZoomLevelNormalization *= aScaleNormalization;
865 
866  #if OSL_DEBUG_LEVEL > 0
867  m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
868  #endif
869  }
870 
871 
873  {
874  if ( !impl_isDisposed_nofail() )
875  {
876  acquire();
877  dispose();
878  }
879 
880  }
881 
882 
884  {
885  if ( impl_isDisposed_nofail() )
886  return;
887 
888  if ( m_aControl.is() )
890 
891  if ( m_xContainer.is() )
893 
894  // dispose the control
895  if ( _bAlsoDisposeControl )
897 
898  m_aControl.clear();
899  m_xContainer.clear();
900  m_pOutputDeviceForWindow = nullptr;
901  m_bControlIsVisible = false;
902 
903  m_pAntiImpl = nullptr;
904  }
905 
906 
908  {
909  SolarMutexGuard aSolarGuard;
910  impl_dispose_nothrow( true );
911  }
912 
913 
915  {
916  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
917  if ( impl_isDisposed_nofail() )
918  _out_rpObject = nullptr;
919  else
920  {
921  _out_rpObject = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
922  DBG_ASSERT( _out_rpObject || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
923  "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
924  }
925  return ( _out_rpObject != nullptr );
926  }
927 
928 
930  {
931  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
932  if ( !m_aControl.is() )
933  return;
934 
935  try
936  {
937  SdrUnoObj* pUnoObject( nullptr );
938  if ( getUnoObject( pUnoObject ) )
939  {
940  const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
942  }
943  else
944  OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
945  }
946  catch( const Exception& )
947  {
949  }
950  }
951 
952 
953  void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
954  {
955  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
956  if ( impl_isDisposed_nofail() )
957  return;
958 
959  ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
960  if ( pPageViewContact )
961  {
962  SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
963  const OutputDevice& rDevice( *m_pAntiImpl->getPageViewOutputDevice() );
965  aPVAccess,
966  rDevice,
967  _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
968  );
969  return;
970  }
971 
972  DummyPageViewAccess aNoPageView;
973  const OutputDevice& rDevice( impl_getOutputDevice_throw() );
975  aNoPageView,
976  rDevice,
977  _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
978  );
979  }
980 
981 
983  {
984  // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
985  // OriginalPaintWindow
986  const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
987  if( oPageOutputDev )
988  return *oPageOutputDev;
989 
991  ENSURE_OR_THROW( pDevice, "no output device -> no control" );
992  return *pDevice;
993  }
994 
995 
996  namespace
997  {
998  void lcl_resetFlag( bool& rbFlag )
999  {
1000  rbFlag = false;
1001  }
1002  }
1003 
1004 
1005  bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
1006  const basegfx::B2DHomMatrix& _rInitialViewTransformation )
1007  {
1008  if ( m_bCreatingControl )
1009  {
1010  OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
1011  // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
1012  // those affected the grid control, which is the only control so far which is visible in design mode (and
1013  // not only in alive mode).
1014  // Creating the control triggered a Window::Update on some of its child windows, which triggered a
1015  // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
1016  // which it is not really prepared for.
1017 
1018  // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
1019  // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
1020  return false;
1021  }
1022 
1023  m_bCreatingControl = true;
1024  ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
1025 
1026  if ( m_aControl.is() )
1027  {
1028  if ( m_pOutputDeviceForWindow.get() == &_rDevice )
1029  return true;
1030 
1031  // Somebody requested a control for a new device, which means either of
1032  // - our PageView's paint window changed since we were last here
1033  // - we don't belong to a page view, and are simply painted onto different devices
1034  // The first sounds strange (doesn't it?), the second means we could perhaps
1035  // optimize this in the future - there is no need to re-create the control every time,
1036  // is it? #i74523#
1037  if ( m_xContainer.is() )
1041  }
1042 
1043  SdrUnoObj* pUnoObject( nullptr );
1044  if ( !getUnoObject( pUnoObject ) )
1045  return false;
1046 
1047  ControlHolder aControl;
1048  if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
1049  return false;
1050 
1051  m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
1052  m_aControl = aControl;
1053  m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
1054  DBG_ASSERT( ( m_xContainer.is() // either have a XControlContainer
1055  || ( ( !_rPageView.getControlContainer( _rDevice ).is() ) // or don't have any container,
1056  && ( _rDevice.GetOwnerWindow() == nullptr ) // which is allowed for non-Window instances only
1057  )
1058  ),
1059  "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
1060 
1061  try
1062  {
1063  m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
1064  m_bControlIsVisible = m_aControl.isVisible();
1065  }
1066  catch( const Exception& )
1067  {
1068  DBG_UNHANDLED_EXCEPTION("svx");
1069  }
1070 
1071  // start listening at all aspects of the control which are interesting to us ...
1073 
1074  // start listening at the control container, in case somebody tampers with our control
1075  if ( m_xContainer.is() )
1077 
1078  return m_aControl.is();
1079  }
1080 
1081 
1082  bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
1083  const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
1084  const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
1085  {
1086  _out_rControl.clear();
1087 
1088  const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
1089  DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
1090  if ( !xControlModel.is() )
1091  return false;
1092 
1093  bool bSuccess = false;
1094  try
1095  {
1096  const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
1097 
1098  Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1099  _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
1100 
1101  // knit the model and the control
1102  _out_rControl.setModel( xControlModel );
1103  const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
1104 
1105  // proper geometry
1107  _out_rControl,
1108  aRect,
1109  _rInitialViewTransformation,
1110  _rInitialZoomNormalization
1111  );
1112 
1113  // set design mode before peer is created,
1114  // this is also needed for accessibility
1115  _out_rControl.setDesignMode( _rPageView.isDesignMode() );
1116 
1117  // adjust the initial visibility according to the visibility of the layer
1118  impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
1119 
1120  // add the control to the respective control container
1121  // do this last
1122  Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
1123  if ( xControlContainer.is() )
1124  xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
1125 
1126  bSuccess = true;
1127  }
1128  catch( const Exception& )
1129  {
1130  DBG_UNHANDLED_EXCEPTION("svx");
1131  }
1132 
1133  if ( !bSuccess )
1134  {
1135  // delete the control which might have been created already
1137  }
1138 
1139  return _out_rControl.is();
1140  }
1141 
1142 
1144  {
1145  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
1146 
1147  _out_rpPageView = nullptr;
1148  if ( impl_isDisposed_nofail() )
1149  return false;
1150 
1151  ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1152  if ( pPageViewContact )
1153  _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
1154 
1155  DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
1156  return ( _out_rpPageView != nullptr );
1157  }
1158 
1159 
1161  {
1162  OSL_PRECOND( m_aControl.is(),
1163  "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
1164 
1165  SdrPageView* pPageView( nullptr );
1166  if ( !impl_getPageView_nothrow( pPageView ) )
1167  return;
1168 
1169  SdrUnoObj* pUnoObject( nullptr );
1170  if ( !getUnoObject( pUnoObject ) )
1171  return;
1172 
1173  SdrPageViewAccess aPVAccess( *pPageView );
1174  impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
1175  }
1176 
1177 
1179  const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
1180  {
1181  // in design mode, there is no problem with the visibility: The XControl is hidden by
1182  // default, and the Drawing Layer will simply not call our paint routine, if we're in
1183  // a hidden layer. So, only alive mode matters.
1184  if ( !_rControl.isDesignMode() )
1185  {
1186  // the layer of our object
1187  SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
1188  // is the object we're residing in visible in this view?
1189  bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
1190 
1191  if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
1192  {
1193  _rControl.setVisible( bIsObjectVisible );
1194  }
1195  }
1196  }
1197 
1198 
1200  {
1201  OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
1202  if ( !m_xContainer.is() )
1203  return;
1204 
1205  try
1206  {
1207  if ( _bStart )
1208  m_xContainer->addContainerListener( this );
1209  else
1210  m_xContainer->removeContainerListener( this );
1211  }
1212  catch( const Exception& )
1213  {
1214  DBG_UNHANDLED_EXCEPTION("svx");
1215  }
1216  }
1217 
1218 
1220  {
1221  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
1222  if ( !m_aControl.is() )
1223  return;
1224 
1225  try
1226  {
1227  // listen for visibility changes
1228  if ( _bStart )
1229  m_aControl.addWindowListener( this );
1230  else
1231  m_aControl.removeWindowListener( this );
1232 
1233  // in design mode, listen for some more aspects
1235 
1236  // listen for design mode changes
1237  Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
1238  if ( _bStart )
1239  xDesignModeChanges->addModeChangeListener( this );
1240  else
1241  xDesignModeChanges->removeModeChangeListener( this );
1242  }
1243  catch( const Exception& )
1244  {
1245  DBG_UNHANDLED_EXCEPTION("svx");
1246  }
1247  }
1248 
1249 
1251  {
1252  if ( m_bIsDesignModeListening != _bStart )
1253  {
1254  m_bIsDesignModeListening = _bStart;
1256  }
1257  }
1258 
1259 
1261  {
1262  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
1263  if ( !m_aControl.is() )
1264  return;
1265 
1266  try
1267  {
1268  Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
1269  if ( _bStart )
1270  xModelProperties->addPropertyChangeListener( OUString(), this );
1271  else
1272  xModelProperties->removePropertyChangeListener( OUString(), this );
1273  }
1274  catch( const Exception& )
1275  {
1276  DBG_UNHANDLED_EXCEPTION("svx");
1277  }
1278  }
1279 
1280 
1282  {
1283  SdrUnoObj* pUnoObject( nullptr );
1284  if ( !getUnoObject( pUnoObject ) )
1285  return false;
1286 
1287  bool bIsPrintable = false;
1288  try
1289  {
1290  Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
1291  OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
1292  }
1293  catch( const Exception& )
1294  {
1295  DBG_UNHANDLED_EXCEPTION("svx");
1296  }
1297  return bIsPrintable;
1298  }
1299 
1300 
1301  void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
1302  {
1303  SolarMutexGuard aSolarGuard;
1304  // some code below - in particular our disposal - might trigger actions which require the
1305  // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1306  // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1307  // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1308 
1309  if ( !m_aControl.is() )
1310  return;
1311 
1312  if ( ( m_aControl == Source.Source )
1313  || ( m_aControl.getModel() == Source.Source )
1314  )
1315  {
1316  // the model or the control is dying ... hmm, not much sense in that we ourself continue
1317  // living
1318  impl_dispose_nothrow( false );
1319  return;
1320  }
1321 
1322  DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
1323  }
1324 
1325 
1326  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
1327  {
1328  // not interested in
1329  }
1330 
1331 
1332  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
1333  {
1334  // not interested in
1335  }
1336 
1337 
1338  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
1339  {
1340  SolarMutexGuard aSolarGuard;
1341  m_bControlIsVisible = true;
1342  }
1343 
1344 
1345  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
1346  {
1347  SolarMutexGuard aSolarGuard;
1348  m_bControlIsVisible = false;
1349  }
1350 
1351 
1352  void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
1353  {
1354  SolarMutexGuard aSolarGuard;
1355  // (re)painting might require VCL operations, which need the SolarMutex
1356 
1357  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
1358  if ( impl_isDisposed_nofail() )
1359  return;
1360 
1361  DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
1362  if ( !m_aControl.is() )
1363  return;
1364 
1365  // a generic property changed. If we're in design mode, we need to repaint the control
1367  {
1369  }
1370  }
1371 
1372 
1373  void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
1374  {
1375  SolarMutexGuard aSolarGuard;
1376 
1377  DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
1378 
1379  m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
1380 
1382 
1383  try
1384  {
1385  // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
1387  }
1388  catch( const Exception& )
1389  {
1390  DBG_UNHANDLED_EXCEPTION("svx");
1391  }
1392  }
1393 
1394 
1395  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
1396  {
1397  // not interested in
1398  }
1399 
1400 
1401  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
1402  {
1403  SolarMutexGuard aSolarGuard;
1404  // some code below - in particular our disposal - might trigger actions which require the
1405  // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1406  // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1407  // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1408  DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
1409 
1410  if ( m_aControl == Event.Element )
1411  impl_dispose_nothrow( false );
1412  }
1413 
1414 
1415  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
1416  {
1417  SolarMutexGuard aSolarGuard;
1418  DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
1419 
1420  if ( ! ( m_aControl == Event.ReplacedElement ) )
1421  return;
1422 
1423  Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
1424  DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
1425  if ( !xNewControl.is() )
1426  return;
1427 
1428  ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
1429 
1430  DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
1431  // another model should - in the drawing layer - also imply another SdrUnoObj, which
1432  // should also result in new ViewContact, and thus in new ViewObjectContacts
1433 
1435 
1436  ControlHolder aNewControl( xNewControl );
1437  aNewControl.setZoom( m_aControl.getZoom() );
1438  aNewControl.setPosSize( m_aControl.getPosSize() );
1439  aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
1440 
1441  m_aControl = xNewControl;
1442  m_bControlIsVisible = m_aControl.isVisible();
1443 
1445 
1447  }
1448 
1449 
1451  {
1452  if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
1453  // nothing to do
1454  return;
1455  m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
1456 
1457  if ( !m_aControl.is() )
1458  // nothing to do, the setting will be respected as soon as the control
1459  // is created
1460  return;
1461 
1462  try
1463  {
1464  m_aControl.setDesignMode( _bDesignMode );
1465  }
1466  catch( const Exception& )
1467  {
1468  DBG_UNHANDLED_EXCEPTION("svx");
1469  }
1470  }
1471 
1472 
1473  //= LazyControlCreationPrimitive2D
1474 
1475 
1476  bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1477  {
1478  if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
1479  return false;
1480 
1481  const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
1482  if ( !pRHS )
1483  return false;
1484 
1485  if ( m_pVOCImpl != pRHS->m_pVOCImpl )
1486  return false;
1487 
1488  if ( m_aTransformation != pRHS->m_aTransformation )
1489  return false;
1490 
1491  return true;
1492  }
1493 
1494 
1495  void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
1496  {
1497  // Do use model data directly to create the correct geometry. Do NOT
1498  // use getBoundRect()/getSnapRect() here; these will use the sequence of
1499  // primitives themselves in the long run.
1500  const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
1501  const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aSdrGeoData);
1502 
1503  _out_Transformation.identity();
1504  _out_Transformation.set( 0, 0, aRange.getWidth() );
1505  _out_Transformation.set( 1, 1, aRange.getHeight() );
1506  _out_Transformation.set( 0, 2, aRange.getMinX() );
1507  _out_Transformation.set( 1, 2, aRange.getMinY() );
1508  }
1509 
1510 
1511  ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
1512  {
1513  ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
1514  aRange.transform( m_aTransformation );
1515  return aRange;
1516  }
1517 
1518 
1519  void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1520  {
1521  #if OSL_DEBUG_LEVEL > 0
1522  ::basegfx::B2DVector aScale, aTranslate;
1523  double fRotate, fShearX;
1524  _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1525  #endif
1526  if ( m_pVOCImpl->hasControl() )
1527  impl_positionAndZoomControl( _rViewInformation );
1528  BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
1529  }
1530 
1531 
1532  void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1533  {
1534  #if OSL_DEBUG_LEVEL > 0
1535  ::basegfx::B2DVector aScale, aTranslate;
1536  double fRotate, fShearX;
1537  _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1538  #endif
1539  const bool bHadControl = m_pVOCImpl->getExistentControl().is();
1540 
1541  // force control here to make it a VCL ChildWindow. Will be fetched
1542  // and used below by getExistentControl()
1543  m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
1544  impl_positionAndZoomControl( _rViewInformation );
1545 
1546  // get needed data
1547  const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
1548  Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
1549  const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
1550 
1551  if ( !bHadControl && rControl.is() && rControl.isVisible() )
1552  rControl.invalidate();
1553 
1554  // check if we already have an XControl.
1555  if ( !xControlModel.is() || !rControl.is() )
1556  {
1557  // use the default mechanism. This will create a ControlPrimitive2D without
1558  // handing over a XControl. If not even a XControlModel exists, it will
1559  // create the SdrObject fallback visualisation
1560  const drawinglayer::primitive2d::Primitive2DContainer& aTmp = rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer();
1561  rContainer.insert(rContainer.end(), aTmp.begin(), aTmp.end());
1562  return;
1563  }
1564 
1565  // create a primitive and hand over the existing xControl. This will
1566  // allow the primitive to not need to create another one on demand.
1567  rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
1568  m_aTransformation, xControlModel, rControl.getControl() ) );
1569  }
1570 
1571 
1573 
1575  :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
1576  ,m_pImpl( new ViewObjectContactOfUnoControl_Impl( this ) )
1577  {
1578  }
1579 
1580 
1582  {
1583  m_pImpl->dispose();
1584  m_pImpl = nullptr;
1585 
1586  }
1587 
1588 
1590  {
1591  SolarMutexGuard aSolarGuard;
1592  m_pImpl->ensureControl( nullptr );
1593  return m_pImpl->getExistentControl().getControl();
1594  }
1595 
1596 
1598  const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
1599  {
1600  ControlHolder aControl;
1601 
1602  InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
1603  OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, *_rWindow.GetOutDev(), _rUnoObject,
1604  _rWindow.GetOutDev()->GetViewTransformation(), _rWindow.GetOutDev()->GetInverseViewTransformation(), aControl ) );
1605  return aControl.getControl();
1606  }
1607 
1608 
1610  {
1611  SolarMutexGuard aSolarGuard;
1612 
1613  try
1614  {
1615  const ControlHolder& rControl( m_pImpl->getExistentControl() );
1616  if ( !rControl.is() )
1617  return;
1618 
1619  // only need to care for alive mode
1620  if ( rControl.isDesignMode() )
1621  return;
1622 
1623  // is the visibility correct?
1624  if ( m_pImpl->isControlVisible() == _bVisible )
1625  return;
1626 
1627  // no -> adjust it
1628  rControl.setVisible( _bVisible );
1629  DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
1630  // now this would mean that either isControlVisible is not reliable,
1631  // or that showing/hiding the window did not work as intended.
1632  }
1633  catch( const Exception& )
1634  {
1635  DBG_UNHANDLED_EXCEPTION("svx");
1636  }
1637  }
1638 
1639 
1641  {
1642  SolarMutexGuard aSolarGuard;
1643  m_pImpl->setControlDesignMode( _bDesignMode );
1644 
1645  if(!_bDesignMode)
1646  {
1647  // when live mode is switched on, a refresh is needed. The edit mode visualisation
1648  // needs to be repainted and the now used VCL-Window needs to be positioned and
1649  // sized. Both is done from the repaint refresh.
1650  const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
1651  }
1652  }
1653 
1654 
1656  {
1657  if ( m_pImpl->isDisposed() )
1658  // our control already died.
1659  // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
1660  // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
1662 
1664  // remove this when #i115754# is fixed
1666 
1667  // ignore existing controls which are in alive mode and manually switched to "invisible" #i102090#
1668  const ControlHolder& rControl( m_pImpl->getExistentControl() );
1669  if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
1671 
1672  ::drawinglayer::primitive2d::Primitive2DReference xPrimitive( new LazyControlCreationPrimitive2D( m_pImpl ) );
1673  return ::drawinglayer::primitive2d::Primitive2DContainer { xPrimitive };
1674  }
1675 
1676 
1678  {
1679  SolarMutexGuard aSolarGuard;
1680 
1681  if ( m_pImpl->hasControl() )
1682  {
1683  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
1684  #if OSL_DEBUG_LEVEL > 0
1685  ::basegfx::B2DVector aScale, aTranslate;
1686  double fRotate, fShearX;
1687  rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1688  #endif
1689 
1690  if ( !rViewInformation.getViewport().isEmpty() )
1691  {
1692  // tdf#121963 check and eventually pre-multiply ViewTransformation
1693  // with GridOffset transformation to avoid alternating positions of
1694  // FormControls which are victims of the non-linear calc ViewTransformation
1695  // aka GridOffset. For other paths (e.g. repaint) this is included already
1696  // as part of the object's sequence of B2DPrimitive - representation
1697  // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
1698  basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
1699 
1701  {
1702  const basegfx::B2DVector& rGridOffset(getGridOffset());
1703 
1704  if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
1705  {
1706  // pre-multiply: GridOffset needs to be applied directly to logic model data
1707  // of object coordinates, so multiply GridOffset from right to make it
1708  // work as 1st change - these objects may still be part of groups/hierarchies
1709  aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
1710  }
1711  }
1712 
1713  m_pImpl->positionAndZoomControl(aViewTransformation);
1714  }
1715  }
1716 
1717  return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
1718  }
1719 
1720 
1722  {
1724  }
1725 
1726 
1728  {
1729  // call parent
1731  const ControlHolder& rControl(m_pImpl->getExistentControl());
1732 
1733  if(!rControl.is() || rControl.isDesignMode())
1734  return;
1735 
1736  // #i93180# if layer visibility has changed and control is in live mode, it is necessary
1737  // to correct visibility to make those control vanish on SdrObject LayerID changes
1738  const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
1739 
1740  if(pSdrPageView)
1741  {
1742  const SdrObject& rObject = getSdrObject();
1743  const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
1744 
1745  if(rControl.isVisible() != bIsLayerVisible)
1746  {
1747  rControl.setVisible(bIsLayerVisible);
1748  }
1749  }
1750  }
1751 
1752 
1754  {
1755  // graphical invalidate at all views
1756  ActionChanged();
1757 
1758  // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
1759  // since e.g. background color has changed and existing decompositions are possibly no
1760  // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
1761  // since it only has a uno reference to the XControlModel
1763  }
1764 
1766  :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
1767  {
1768  }
1769 
1770 
1772  {
1773  }
1774 
1775 
1777  {
1778  if ( !m_pImpl->isPrintableControl() )
1781  }
1782 
1783 
1784 } // namespace sdr::contact
1785 
1786 
1787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::B2DHomMatrix GetInverseViewTransformation() const
void impl_dispose_nothrow(bool _bAlsoDisposeControl)
disposes the instance
bool m_bIsDesignModeListening
are we currently listening at a design mode control?
void setControlDesignMode(bool _bDesignMode) const
sets the design mode on the control, or at least remembers the flag for the time the control is creat...
ViewObjectContactOfUnoControl_Impl(ViewObjectContactOfUnoControl *_pAntiImpl)
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
#define PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D
virtual void SAL_CALL modeChanged(const ModeChangeEvent &_rSource) override
VclPtr< OutputDevice > m_pOutputDeviceForWindow
the output device for which the control was created
css::uno::Reference< css::awt::XControl > getControl()
returns the ->XControl instance belonging to the instance, creates it if necessary ...
Reference< XControl > m_xControl
bool impl_isControlDesignMode_nothrow() const
determines whether the control currently is in design mode
virtual SdrObject * TryToGetSdrObject() const
void positionAndZoomControl(const basegfx::B2DHomMatrix &_rViewTransformation) const
positions our XControl according to the geometry settings in the SdrUnoObj, modified by the given tra...
void setControlDesignMode(bool _bDesignMode) const
sets the design/alive mode of the control
SdrView & GetView()
Definition: svdpagv.hxx:135
::rtl::Reference< ViewObjectContactOfUnoControl_Impl > m_pImpl
void impl_switchContainerListening_nothrow(bool _bStart)
starts or stops listening at our control container
virtual drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequence(const DisplayInfo &rDisplayInfo) const override
long Long
const SdrPageView & m_rPageView
bool IsDesignMode() const
Definition: svdmrkv.hxx:236
double getX() const
void impl_onControlChangedOrModified()
to be called when any aspect of the control which requires view updates changed
virtual void SAL_CALL windowHidden(const EventObject &e) override
const MapMode & GetMapMode() const
double getY() const
static css::uno::Reference< css::awt::XControlContainer > CreateControlContainer(vcl::Window *pWindow)
virtual void SAL_CALL windowMoved(const WindowEvent &e) override
ViewObjectContactOfUnoControl * m_pAntiImpl
the instance whose IMPL we are
bool isControlVisible() const
determines whether our control is currently visible
static css::uno::Reference< css::awt::XControl > getTemporaryControlForWindow(const vcl::Window &_rWindow, css::uno::Reference< css::awt::XControlContainer > &_inout_ControlContainer, const SdrUnoObj &_rUnoObject)
retrieves a temporary XControl instance, whose parent is the given device SdrUnoObj::GetTemporaryCon...
virtual void SAL_CALL windowResized(const WindowEvent &e) override
void ensureControl(const basegfx::B2DHomMatrix *_pInitialViewTransformationOrNULL)
ensures that we have an ->XControl
ImplPrimitive2DIDBlock(LazyControlCreationPrimitive2D, PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D) ViewObjectContactOfUnoControl
bool IsVisible() const
Definition: svdobj.hxx:753
const Fraction & GetZoom() const
SdrPageWindow * FindPageWindow(SdrPaintWindow &rPaintWindow) const
Definition: svdpagv.cxx:43
const OutputDevice * getPageViewOutputDevice() const
retrieves the device which a PageView belongs to, starting from its ObjectContactOfPageView ...
bool impl_ensureControl_nothrow(IPageViewAccess const &_rPageView, const OutputDevice &_rDevice, const basegfx::B2DHomMatrix &_rInitialViewTransformation)
ensures that we have a control for the given PageView/OutputDevice
tools::Long Left() const
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
tools::Long Bottom() const
virtual void SAL_CALL propertyChange(const PropertyChangeEvent &evt) override
constexpr tools::Long GetWidth() const
ViewObjectContactOfUnoControl_Impl & operator=(const ViewObjectContactOfUnoControl_Impl &)=delete
bool isPrintableControl() const
determines whether or not our control is printable
ObjectContact & GetObjectContact() const
ViewControlMode m_eControlDesignMode
is the control currently in design mode?
void dispose()
disposes the instance, which is nonfunctional afterwards
virtual void SAL_CALL windowShown(const EventObject &e) override
Reference< XContainer > m_xContainer
the ControlContainer where we inserted our control
void impl_switchControlListening_nothrow(bool _bStart)
starts or stops listening at various aspects of our control
const SdrLayerIDSet & GetVisibleLayers() const
Definition: svdpagv.hxx:215
static void disposeAndClearControl_nothrow(ControlHolder &_rControl)
disposes the given control
bool isDisposed() const
determines whether the instance is disposed
#define DBG_UNHANDLED_EXCEPTION(...)
void propertyChange()
callback from impl class to react on changes of properties form the XControlModel ...
UnoControlPrintOrPreviewContact(ObjectContactOfPageView &_rObjectContact, ViewContactOfUnoControl &_rViewContact)
virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent &Event) override
::rtl::Reference< ViewObjectContactOfUnoControl_Impl > m_pVOCImpl
#define DBG_ASSERT(sCon, aError)
class SAL_NO_VTABLE XPropertySet
Definition: xmlexchg.hxx:28
const drawinglayer::geometry::ViewInformation2D & getViewInformation2D() const
static bool createControlForDevice(IPageViewAccess const &_rPageView, const OutputDevice &_rDevice, const SdrUnoObj &_rUnoObject, const basegfx::B2DHomMatrix &_rInitialViewTransformation, const basegfx::B2DHomMatrix &_rInitialZoomNormalization, ControlHolder &_out_rControl)
creates an XControl for the given device and SdrUnoObj
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent &Event) override
virtual void ActionChanged() override
React on changes of the object of this ViewContact.
const basegfx::B2DHomMatrix & getViewTransformation() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
bool m_bControlIsVisible
flag indicating whether the control is currently visible
bool isIdentity() const
virtual drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequence(const DisplayInfo &rDisplayInfo) const override
void impl_switchDesignModeListening_nothrow(bool _bStart)
starts or stops listening at the control for design-mode relevant facets
eUnknown
tools::Long Top() const
Abstract DrawObject.
Definition: svdobj.hxx:258
const OUString & GetUnoControlTypeName() const
Definition: svdouno.hxx:125
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:680
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
#define ENSURE_OR_THROW(c, m)
Reference< XWindow2 > m_xControlWindow
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:66
::tools::Rectangle ConvertToVCLRect(css::awt::Rectangle const &_rRect)
const ControlHolder & getExistentControl() const
returns our XControl, if it already has been created
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
void ensureControlVisibility(bool _bVisible) const
ensures that the control belonging to this instances has a given visibility
::cppu::WeakImplHelper< XWindowListener, XPropertyChangeListener, XContainerListener, XModeChangeListener > ViewObjectContactOfUnoControl_Impl_Base
virtual void SAL_CALL disposing(const EventObject &Source) override
ControlHolder m_aControl
the control we're responsible for
::basegfx::B2DHomMatrix m_aTransformation
The geometry is part of the identity of a primitive, so we cannot calculate it on demand (since the d...
bool getUnoObject(SdrUnoObj *&_out_rpObject) const
returns the SdrUnoObject associated with the ViewContact
const basegfx::B2DVector & getGridOffset() const
::OutputDevice const * GetOutDev() const
virtual bool supportsGridOffsets() const
Reference< XControlContainer > & m_rControlContainer
virtual void SAL_CALL elementInserted(const css::container::ContainerEvent &Event) override
static void adjustControlGeometry_throw(const ControlHolder &_rControl, const tools::Rectangle &_rLogicBoundingRect, const basegfx::B2DHomMatrix &_rViewTransformation, const ::basegfx::B2DHomMatrix &_rZoomLevelNormalization)
positions a control, and sets its zoom mode, using a given transformation and output device ...
virtual OutputDevice * TryToGetOutputDevice() const
access to OutputDevice. May return 0L like the default implementations do. Override as needed...
const css::uno::Reference< css::awt::XControlModel > & GetUnoControlModel() const
Definition: svdouno.hxx:92
css::uno::Reference< css::awt::XControlContainer > GetControlContainer(const OutputDevice &_rDevice) const
Looks up the control container belonging to given output device.
Definition: svdpagv.cxx:142
bool impl_getPageView_nothrow(SdrPageView *&_out_rpPageView)
retrieves the SdrPageView which our associated SdrPageViewWindow belongs to
ViewContact & GetViewContact() const
OutputDevice * get() const
void impl_adjustControlVisibilityToLayerVisibility_throw()
adjusts the control visibility so it respects its layer's visibility
Reference< XView > m_xControlView
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
void impl_switchPropertyListening_nothrow(bool _bStart)
starts or stops listening for all properties at our control
basegfx::B2DHomMatrix GetViewTransformation() const
bool m_bCreatingControl
are we currently inside impl_ensureControl_nothrow?
bool impl_isDisposed_nofail() const
determines whether the instance is disposed
bool operator==(const ScCsvLayoutData &rData1, const ScCsvLayoutData &rData2)
virtual vcl::Window * GetOwnerWindow() const
to be called when any aspect of the control which requires view updates changed
tools::Long Right() const
virtual bool isPrimitiveVisible(const DisplayInfo &_rDisplayInfo) const override
constexpr tools::Long GetHeight() const
virtual const tools::Rectangle & GetLogicRect() const override
Definition: svdotxtr.cxx:69
virtual SdrPageView * TryToGetSdrPageView() const
access to SdrPageView. May return 0L like the default implementations do. Override as needed...
SdrPageView & GetPageView() const
virtual bool isPrimitiveVisible(const DisplayInfo &rDisplayInfo) const override