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  {
144  }
145 
146  explicit ControlHolder( const Reference< XControl >& _rxControl )
147  {
148  *this = _rxControl;
149  }
150 
151  ControlHolder& operator=( const Reference< XControl >& _rxControl )
152  {
153  clear();
154 
155  m_xControl = _rxControl;
156  if ( m_xControl.is() )
157  {
158  m_xControlWindow.set( m_xControl, UNO_QUERY );
159  m_xControlView.set( m_xControl, UNO_QUERY );
160  if ( !m_xControlWindow.is() || !m_xControlView.is() )
161  {
162  OSL_FAIL( "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
163  clear();
164  }
165  }
166 
167  return *this;
168  }
169 
170  public:
171  bool is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
172  void clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
173 
174  // delegators for the methods of the UNO interfaces
175  // Note all those will crash if called for a NULL object.
176  bool isDesignMode() const { return m_xControl->isDesignMode(); }
177  void setDesignMode( const bool _bDesign ) const { m_xControl->setDesignMode( _bDesign ); }
178  bool isVisible() const { return m_xControlWindow->isVisible(); }
179  void setVisible( const bool _bVisible ) const { m_xControlWindow->setVisible( _bVisible ); }
180  Reference< XControlModel >
181  getModel() const { return m_xControl->getModel(); }
182  void setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
183 
184  void addWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->addWindowListener( _l ); }
185  void removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
186  void setPosSize( const tools::Rectangle& _rPosSize ) const;
188  getPosSize() const;
189  void setZoom( const ::basegfx::B2DVector& _rScale ) const;
191  getZoom() const;
192 
193  void invalidate() const;
194 
195  public:
196  const Reference< XControl >& getControl() const { return m_xControl; }
197  };
198 
199  bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
200  {
201  return _rControl.getControl() == _rxCompare;
202  }
203 
204  bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
205  {
206  return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
207  }
208 
209  }
210 
211  void ControlHolder::setPosSize( const tools::Rectangle& _rPosSize ) const
212  {
213  // no check whether we're valid, this is the responsibility of the caller
214 
215  // don't call setPosSize when pos/size did not change #i104181#
216  ::tools::Rectangle aCurrentRect( getPosSize() );
217  if ( aCurrentRect != _rPosSize )
218  {
219  m_xControlWindow->setPosSize(
220  _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
221  POSSIZE
222  );
223  }
224  }
225 
226 
227  ::tools::Rectangle ControlHolder::getPosSize() const
228  {
229  // no check whether we're valid, this is the responsibility of the caller
230  return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
231  }
232 
233 
234  void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
235  {
236  // no check whether we're valid, this is the responsibility of the caller
237  m_xControlView->setZoom( static_cast<float>(_rScale.getX()), static_cast<float>(_rScale.getY()) );
238  }
239 
240 
241  void ControlHolder::invalidate() const
242  {
243  Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
244  if ( xPeer.is() )
245  {
246  VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xPeer );
247  OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
248  if ( pWindow )
249  pWindow->Invalidate();
250  }
251  }
252 
253 
254  ::basegfx::B2DVector ControlHolder::getZoom() const
255  {
256  // no check whether we're valid, this is the responsibility of the caller
257 
258  // Argh. Why does XView have a setZoom only, but not a getZoom?
259  VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
260  OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
261 
262  ::basegfx::B2DVector aZoom( 1, 1 );
263  if ( pWindow )
264  {
265  const Fraction& rZoom( pWindow->GetZoom() );
266  aZoom.setX( static_cast<double>(rZoom) );
267  aZoom.setY( static_cast<double>(rZoom) );
268  }
269  return aZoom;
270  }
271 
272  namespace UnoControlContactHelper {
273 
276  static void adjustControlGeometry_throw( const ControlHolder& _rControl, const tools::Rectangle& _rLogicBoundingRect,
277  const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
278  {
279  OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
280  if ( !_rControl.is() )
281  return;
282 
283  #if OSL_DEBUG_LEVEL > 0
284  ::basegfx::B2DTuple aViewScale, aViewTranslate;
285  double nViewRotate(0), nViewShearX(0);
286  _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
287 
288  ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
289  double nZoomRotate(0), nZoomShearX(0);
290  _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
291  #endif
292 
293  // transform the logic bound rect, using the view transformation, to pixel coordinates
294  ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
295  aTopLeft *= _rViewTransformation;
296  ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
297  aBottomRight *= _rViewTransformation;
298 
299  const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
300  static_cast<tools::Long>(std::round(aTopLeft.getY())),
301  static_cast<tools::Long>(std::round(aBottomRight.getX())),
302  static_cast<tools::Long>(std::round(aBottomRight.getY())));
303  _rControl.setPosSize( aPaintRectPixel );
304 
305  // determine the scale from the current view transformation, and the normalization matrix
306  ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
307  ::basegfx::B2DVector aScale, aTranslate;
308  double fRotate, fShearX;
309  aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
310  _rControl.setZoom( aScale );
311  }
312 
315  static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
316  {
317  try
318  {
319  Reference< XComponent > xControlComp = _rControl.getControl();
320  if ( xControlComp.is() )
321  xControlComp->dispose();
322  }
323  catch( const Exception& )
324  {
326  }
327  _rControl.clear();
328  }
329 
330  }
331 
332  namespace {
333 
336  class IPageViewAccess
337  {
338  public:
341  virtual bool isDesignMode() const = 0;
342 
345  virtual Reference< XControlContainer >
346  getControlContainer( const OutputDevice& _rDevice ) const = 0;
347 
350  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const = 0;
351 
352  protected:
353  ~IPageViewAccess() {}
354  };
355 
358  class SdrPageViewAccess : public IPageViewAccess
359  {
361  public:
362  explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
363 
364  virtual ~SdrPageViewAccess() {}
365 
366  virtual bool isDesignMode() const override;
367  virtual Reference< XControlContainer >
368  getControlContainer( const OutputDevice& _rDevice ) const override;
369  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
370  };
371 
372  }
373 
374  bool SdrPageViewAccess::isDesignMode() const
375  {
376  return m_rPageView.GetView().IsDesignMode();
377  }
378 
379 
380  Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
381  {
382  Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
383  DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
384  "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
385  return xControlContainer;
386  }
387 
388 
389  bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
390  {
391  return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
392  }
393 
394  namespace {
395 
399  class InvisibleControlViewAccess : public IPageViewAccess
400  {
401  private:
402  Reference< XControlContainer >& m_rControlContainer;
403  public:
404  explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
405  :m_rControlContainer( _inout_ControlContainer )
406  {
407  }
408 
409  virtual ~InvisibleControlViewAccess() {}
410 
411  virtual bool isDesignMode() const override;
412  virtual Reference< XControlContainer >
413  getControlContainer( const OutputDevice& _rDevice ) const override;
414  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
415  };
416 
417  }
418 
419  bool InvisibleControlViewAccess::isDesignMode() const
420  {
421  return true;
422  }
423 
424 
425  Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
426  {
427  if ( !m_rControlContainer.is() )
428  {
429  const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
430  OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
431  if ( pWindow )
432  m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< vcl::Window* >( pWindow ) );
433  }
434  return m_rControlContainer;
435  }
436 
437 
438  bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
439  {
440  return false;
441  }
442 
443  namespace {
444 
445  //= DummyPageViewAccess
446 
454  class DummyPageViewAccess : public IPageViewAccess
455  {
456  public:
457  DummyPageViewAccess()
458  {
459  }
460 
461  virtual ~DummyPageViewAccess() {}
462 
463  virtual bool isDesignMode() const override;
464  virtual Reference< XControlContainer >
465  getControlContainer( const OutputDevice& _rDevice ) const override;
466  virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
467  };
468 
469  }
470 
471  bool DummyPageViewAccess::isDesignMode() const
472  {
473  return true;
474  }
475 
476 
477  Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
478  {
479  return nullptr;
480  }
481 
482 
483  bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
484  {
485  return true;
486  }
487 
488 
489  //= ViewObjectContactOfUnoControl_Impl
490 
491  typedef ::cppu::WeakImplHelper < XWindowListener
492  , XPropertyChangeListener
493  , XContainerListener
494  , XModeChangeListener
496 
499  {
500  private:
501  // tdf#41935 note that access to members is protected with SolarMutex;
502  // the class previously had its own mutex but that is prone to deadlock
503 
506 
509 
511  ControlHolder m_aControl;
512 
514  Reference< XContainer > m_xContainer;
515 
518 
521 
524 
526  {
530  };
533 
535 
536  public:
540 
543  void dispose();
544 
547  bool isDisposed() const { return impl_isDisposed_nofail(); }
548 
554  bool getUnoObject( SdrUnoObj*& _out_rpObject ) const;
555 
566  void ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
567 
572  const ControlHolder&
573  getExistentControl() const { return m_aControl; }
574 
575  bool
576  hasControl() const { return m_aControl.is(); }
577 
584  void positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
585 
591  bool isPrintableControl() const;
592 
596  void setControlDesignMode( bool _bDesignMode ) const;
597 
601  bool isControlVisible() const { return m_bControlIsVisible; }
602 
604  static bool
606  IPageViewAccess const & _rPageView,
607  const OutputDevice& _rDevice,
608  const SdrUnoObj& _rUnoObject,
609  const basegfx::B2DHomMatrix& _rInitialViewTransformation,
610  const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
611  ControlHolder& _out_rControl
612  );
613 
616  {
617  ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
618  return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
619  }
620 
621  protected:
622  virtual ~ViewObjectContactOfUnoControl_Impl() override;
623 
624  // XEventListener
625  virtual void SAL_CALL disposing( const EventObject& Source ) override;
626 
627  // XWindowListener
628  virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
629  virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
630  virtual void SAL_CALL windowShown( const EventObject& e ) override;
631  virtual void SAL_CALL windowHidden( const EventObject& e ) override;
632 
633  // XPropertyChangeListener
634  virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
635 
636  // XModeChangeListener
637  virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
638 
639  // XContainerListener
640  virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
641  virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
642  virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
643 
644  private:
667  bool impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
668 
683 
711  static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
712  IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
713 
719  void impl_switchControlListening_nothrow( bool _bStart );
720 
726  void impl_switchContainerListening_nothrow( bool _bStart );
727 
730  void impl_switchDesignModeListening_nothrow( bool _bStart );
731 
740  void impl_switchPropertyListening_nothrow( bool _bStart );
741 
746  void impl_dispose_nothrow( bool _bAlsoDisposeControl );
747 
751  bool impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
752 
761  {
762  DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
763  return m_eControlDesignMode == eDesign;
764  }
765 
769  IPageViewAccess const & _rPageView,
770  const OutputDevice& _rDevice,
771  const basegfx::B2DHomMatrix& _rInitialViewTransformation
772  );
773 
775  };
776 
777  namespace {
778 
779  class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
780  {
781  private:
782  typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D BufferedDecompositionPrimitive2D;
783 
784  protected:
785  virtual void
786  get2DDecomposition(
788  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
789  ) const override;
790 
791  virtual void create2DDecomposition(
793  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
794  ) const override;
795 
796  virtual ::basegfx::B2DRange
797  getB2DRange(
798  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
799  ) const override;
800 
801  public:
802  explicit LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
803  :m_pVOCImpl( _pVOCImpl )
804  {
805  ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
806  getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
807  }
808 
809  virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
810 
811  // declare unique ID for this primitive class
812  virtual sal_uInt32 getPrimitive2DID() const override;
813 
814  static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
815 
816  private:
817  void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
818  {
819  if ( !_rViewInformation.getViewport().isEmpty() )
820  m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
821  }
822 
823  private:
830  };
831 
832  }
833 
835  :m_pAntiImpl( _pAntiImpl )
836  ,m_bCreatingControl( false )
837  ,m_pOutputDeviceForWindow( nullptr )
838  ,m_bControlIsVisible( false )
839  ,m_bIsDesignModeListening( false )
840  ,m_eControlDesignMode( eUnknown )
841  {
842  DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
843 
844  const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
846 
847  #if OSL_DEBUG_LEVEL > 0
848  ::basegfx::B2DVector aScale, aTranslate;
849  double fRotate, fShearX;
850  m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
851  #endif
852 
853  ::basegfx::B2DHomMatrix aScaleNormalization;
854  const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
855  aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
856  aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
857  m_aZoomLevelNormalization *= aScaleNormalization;
858 
859  #if OSL_DEBUG_LEVEL > 0
860  m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
861  #endif
862  }
863 
864 
866  {
867  if ( !impl_isDisposed_nofail() )
868  {
869  acquire();
870  dispose();
871  }
872 
873  }
874 
875 
877  {
878  if ( impl_isDisposed_nofail() )
879  return;
880 
881  if ( m_aControl.is() )
883 
884  if ( m_xContainer.is() )
886 
887  // dispose the control
888  if ( _bAlsoDisposeControl )
890 
891  m_aControl.clear();
892  m_xContainer.clear();
893  m_pOutputDeviceForWindow = nullptr;
894  m_bControlIsVisible = false;
895 
896  m_pAntiImpl = nullptr;
897  }
898 
899 
901  {
902  SolarMutexGuard aSolarGuard;
903  impl_dispose_nothrow( true );
904  }
905 
906 
908  {
909  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
910  if ( impl_isDisposed_nofail() )
911  _out_rpObject = nullptr;
912  else
913  {
914  _out_rpObject = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
915  DBG_ASSERT( _out_rpObject || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
916  "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
917  }
918  return ( _out_rpObject != nullptr );
919  }
920 
921 
923  {
924  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
925  if ( !m_aControl.is() )
926  return;
927 
928  try
929  {
930  SdrUnoObj* pUnoObject( nullptr );
931  if ( getUnoObject( pUnoObject ) )
932  {
933  const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
935  }
936  else
937  OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
938  }
939  catch( const Exception& )
940  {
942  }
943  }
944 
945 
946  void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
947  {
948  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
949  if ( impl_isDisposed_nofail() )
950  return;
951 
952  ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
953  if ( pPageViewContact )
954  {
955  SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
956  const OutputDevice& rDevice( *m_pAntiImpl->getPageViewOutputDevice() );
958  aPVAccess,
959  rDevice,
960  _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
961  );
962  return;
963  }
964 
965  DummyPageViewAccess aNoPageView;
966  const OutputDevice& rDevice( impl_getOutputDevice_throw() );
968  aNoPageView,
969  rDevice,
970  _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
971  );
972  }
973 
974 
976  {
977  // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
978  // OriginalPaintWindow
979  const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
980  if( oPageOutputDev )
981  return *oPageOutputDev;
982 
984  ENSURE_OR_THROW( pDevice, "no output device -> no control" );
985  return *pDevice;
986  }
987 
988 
989  namespace
990  {
991  void lcl_resetFlag( bool& rbFlag )
992  {
993  rbFlag = false;
994  }
995  }
996 
997 
998  bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
999  const basegfx::B2DHomMatrix& _rInitialViewTransformation )
1000  {
1001  if ( m_bCreatingControl )
1002  {
1003  OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
1004  // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
1005  // those affected the grid control, which is the only control so far which is visible in design mode (and
1006  // not only in alive mode).
1007  // Creating the control triggered a Window::Update on some of its child windows, which triggered a
1008  // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
1009  // which it is not really prepared for.
1010 
1011  // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
1012  // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
1013  return false;
1014  }
1015 
1016  m_bCreatingControl = true;
1017  ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
1018 
1019  if ( m_aControl.is() )
1020  {
1021  if ( m_pOutputDeviceForWindow.get() == &_rDevice )
1022  return true;
1023 
1024  // Somebody requested a control for a new device, which means either of
1025  // - our PageView's paint window changed since we were last here
1026  // - we don't belong to a page view, and are simply painted onto different devices
1027  // The first sounds strange (doesn't it?), the second means we could perhaps
1028  // optimize this in the future - there is no need to re-create the control every time,
1029  // is it? #i74523#
1030  if ( m_xContainer.is() )
1034  }
1035 
1036  SdrUnoObj* pUnoObject( nullptr );
1037  if ( !getUnoObject( pUnoObject ) )
1038  return false;
1039 
1040  ControlHolder aControl;
1041  if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
1042  return false;
1043 
1044  m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
1045  m_aControl = aControl;
1046  m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
1047  DBG_ASSERT( ( m_xContainer.is() // either have a XControlContainer
1048  || ( ( !_rPageView.getControlContainer( _rDevice ).is() ) // or don't have any container,
1049  && ( _rDevice.GetOwnerWindow() == nullptr ) // which is allowed for non-Window instances only
1050  )
1051  ),
1052  "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
1053 
1054  try
1055  {
1056  m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
1057  m_bControlIsVisible = m_aControl.isVisible();
1058  }
1059  catch( const Exception& )
1060  {
1061  DBG_UNHANDLED_EXCEPTION("svx");
1062  }
1063 
1064  // start listening at all aspects of the control which are interesting to us ...
1066 
1067  // start listening at the control container, in case somebody tampers with our control
1068  if ( m_xContainer.is() )
1070 
1071  return m_aControl.is();
1072  }
1073 
1074 
1075  bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
1076  const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
1077  const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
1078  {
1079  _out_rControl.clear();
1080 
1081  const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
1082  DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
1083  if ( !xControlModel.is() )
1084  return false;
1085 
1086  bool bSuccess = false;
1087  try
1088  {
1089  const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
1090 
1091  Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1092  _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
1093 
1094  // knit the model and the control
1095  _out_rControl.setModel( xControlModel );
1096  const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
1097 
1098  // proper geometry
1100  _out_rControl,
1101  aRect,
1102  _rInitialViewTransformation,
1103  _rInitialZoomNormalization
1104  );
1105 
1106  // set design mode before peer is created,
1107  // this is also needed for accessibility
1108  _out_rControl.setDesignMode( _rPageView.isDesignMode() );
1109 
1110  // adjust the initial visibility according to the visibility of the layer
1111  impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
1112 
1113  // add the control to the respective control container
1114  // do this last
1115  Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
1116  if ( xControlContainer.is() )
1117  xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
1118 
1119  bSuccess = true;
1120  }
1121  catch( const Exception& )
1122  {
1123  DBG_UNHANDLED_EXCEPTION("svx");
1124  }
1125 
1126  if ( !bSuccess )
1127  {
1128  // delete the control which might have been created already
1130  }
1131 
1132  return _out_rControl.is();
1133  }
1134 
1135 
1137  {
1138  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
1139 
1140  _out_rpPageView = nullptr;
1141  if ( impl_isDisposed_nofail() )
1142  return false;
1143 
1144  ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1145  if ( pPageViewContact )
1146  _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
1147 
1148  DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
1149  return ( _out_rpPageView != nullptr );
1150  }
1151 
1152 
1154  {
1155  OSL_PRECOND( m_aControl.is(),
1156  "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
1157 
1158  SdrPageView* pPageView( nullptr );
1159  if ( !impl_getPageView_nothrow( pPageView ) )
1160  return;
1161 
1162  SdrUnoObj* pUnoObject( nullptr );
1163  if ( !getUnoObject( pUnoObject ) )
1164  return;
1165 
1166  SdrPageViewAccess aPVAccess( *pPageView );
1167  impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
1168  }
1169 
1170 
1172  const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
1173  {
1174  // in design mode, there is no problem with the visibility: The XControl is hidden by
1175  // default, and the Drawing Layer will simply not call our paint routine, if we're in
1176  // a hidden layer. So, only alive mode matters.
1177  if ( !_rControl.isDesignMode() )
1178  {
1179  // the layer of our object
1180  SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
1181  // is the object we're residing in visible in this view?
1182  bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
1183 
1184  if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
1185  {
1186  _rControl.setVisible( bIsObjectVisible );
1187  }
1188  }
1189  }
1190 
1191 
1193  {
1194  OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
1195  if ( !m_xContainer.is() )
1196  return;
1197 
1198  try
1199  {
1200  if ( _bStart )
1201  m_xContainer->addContainerListener( this );
1202  else
1203  m_xContainer->removeContainerListener( this );
1204  }
1205  catch( const Exception& )
1206  {
1207  DBG_UNHANDLED_EXCEPTION("svx");
1208  }
1209  }
1210 
1211 
1213  {
1214  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
1215  if ( !m_aControl.is() )
1216  return;
1217 
1218  try
1219  {
1220  // listen for visibility changes
1221  if ( _bStart )
1222  m_aControl.addWindowListener( this );
1223  else
1224  m_aControl.removeWindowListener( this );
1225 
1226  // in design mode, listen for some more aspects
1228 
1229  // listen for design mode changes
1230  Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
1231  if ( _bStart )
1232  xDesignModeChanges->addModeChangeListener( this );
1233  else
1234  xDesignModeChanges->removeModeChangeListener( this );
1235  }
1236  catch( const Exception& )
1237  {
1238  DBG_UNHANDLED_EXCEPTION("svx");
1239  }
1240  }
1241 
1242 
1244  {
1245  if ( m_bIsDesignModeListening != _bStart )
1246  {
1247  m_bIsDesignModeListening = _bStart;
1249  }
1250  }
1251 
1252 
1254  {
1255  OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
1256  if ( !m_aControl.is() )
1257  return;
1258 
1259  try
1260  {
1261  Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
1262  if ( _bStart )
1263  xModelProperties->addPropertyChangeListener( OUString(), this );
1264  else
1265  xModelProperties->removePropertyChangeListener( OUString(), this );
1266  }
1267  catch( const Exception& )
1268  {
1269  DBG_UNHANDLED_EXCEPTION("svx");
1270  }
1271  }
1272 
1273 
1275  {
1276  SdrUnoObj* pUnoObject( nullptr );
1277  if ( !getUnoObject( pUnoObject ) )
1278  return false;
1279 
1280  bool bIsPrintable = false;
1281  try
1282  {
1283  Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
1284  OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
1285  }
1286  catch( const Exception& )
1287  {
1288  DBG_UNHANDLED_EXCEPTION("svx");
1289  }
1290  return bIsPrintable;
1291  }
1292 
1293 
1294  void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
1295  {
1296  SolarMutexGuard aSolarGuard;
1297  // some code below - in particular our disposal - might trigger actions which require the
1298  // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1299  // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1300  // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1301 
1302  if ( !m_aControl.is() )
1303  return;
1304 
1305  if ( ( m_aControl == Source.Source )
1306  || ( m_aControl.getModel() == Source.Source )
1307  )
1308  {
1309  // the model or the control is dying ... hmm, not much sense in that we ourself continue
1310  // living
1311  impl_dispose_nothrow( false );
1312  return;
1313  }
1314 
1315  DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
1316  }
1317 
1318 
1319  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
1320  {
1321  // not interested in
1322  }
1323 
1324 
1325  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
1326  {
1327  // not interested in
1328  }
1329 
1330 
1331  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
1332  {
1333  SolarMutexGuard aSolarGuard;
1334  m_bControlIsVisible = true;
1335  }
1336 
1337 
1338  void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
1339  {
1340  SolarMutexGuard aSolarGuard;
1341  m_bControlIsVisible = false;
1342  }
1343 
1344 
1345  void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
1346  {
1347  SolarMutexGuard aSolarGuard;
1348  // (re)painting might require VCL operations, which need the SolarMutex
1349 
1350  OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
1351  if ( impl_isDisposed_nofail() )
1352  return;
1353 
1354  DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
1355  if ( !m_aControl.is() )
1356  return;
1357 
1358  // a generic property changed. If we're in design mode, we need to repaint the control
1360  {
1362  }
1363  }
1364 
1365 
1366  void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
1367  {
1368  SolarMutexGuard aSolarGuard;
1369 
1370  DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
1371 
1372  m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
1373 
1375 
1376  try
1377  {
1378  // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
1380  }
1381  catch( const Exception& )
1382  {
1383  DBG_UNHANDLED_EXCEPTION("svx");
1384  }
1385  }
1386 
1387 
1388  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
1389  {
1390  // not interested in
1391  }
1392 
1393 
1394  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
1395  {
1396  SolarMutexGuard aSolarGuard;
1397  // some code below - in particular our disposal - might trigger actions which require the
1398  // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1399  // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1400  // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1401  DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
1402 
1403  if ( m_aControl == Event.Element )
1404  impl_dispose_nothrow( false );
1405  }
1406 
1407 
1408  void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
1409  {
1410  SolarMutexGuard aSolarGuard;
1411  DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
1412 
1413  if ( ! ( m_aControl == Event.ReplacedElement ) )
1414  return;
1415 
1416  Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
1417  DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
1418  if ( !xNewControl.is() )
1419  return;
1420 
1421  ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
1422 
1423  DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
1424  // another model should - in the drawing layer - also imply another SdrUnoObj, which
1425  // should also result in new ViewContact, and thus in new ViewObjectContacts
1426 
1428 
1429  ControlHolder aNewControl( xNewControl );
1430  aNewControl.setZoom( m_aControl.getZoom() );
1431  aNewControl.setPosSize( m_aControl.getPosSize() );
1432  aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
1433 
1434  m_aControl = xNewControl;
1435  m_bControlIsVisible = m_aControl.isVisible();
1436 
1438 
1440  }
1441 
1442 
1444  {
1445  if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
1446  // nothing to do
1447  return;
1448  m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
1449 
1450  if ( !m_aControl.is() )
1451  // nothing to do, the setting will be respected as soon as the control
1452  // is created
1453  return;
1454 
1455  try
1456  {
1457  m_aControl.setDesignMode( _bDesignMode );
1458  }
1459  catch( const Exception& )
1460  {
1461  DBG_UNHANDLED_EXCEPTION("svx");
1462  }
1463  }
1464 
1465 
1466  //= LazyControlCreationPrimitive2D
1467 
1468 
1469  bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1470  {
1471  if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
1472  return false;
1473 
1474  const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
1475  if ( !pRHS )
1476  return false;
1477 
1478  if ( m_pVOCImpl != pRHS->m_pVOCImpl )
1479  return false;
1480 
1481  if ( m_aTransformation != pRHS->m_aTransformation )
1482  return false;
1483 
1484  return true;
1485  }
1486 
1487 
1488  void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
1489  {
1490  // Do use model data directly to create the correct geometry. Do NOT
1491  // use getBoundRect()/getSnapRect() here; these will use the sequence of
1492  // primitives themselves in the long run.
1493  const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
1494  const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aSdrGeoData);
1495 
1496  _out_Transformation.identity();
1497  _out_Transformation.set( 0, 0, aRange.getWidth() );
1498  _out_Transformation.set( 1, 1, aRange.getHeight() );
1499  _out_Transformation.set( 0, 2, aRange.getMinX() );
1500  _out_Transformation.set( 1, 2, aRange.getMinY() );
1501  }
1502 
1503 
1504  ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
1505  {
1506  ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
1507  aRange.transform( m_aTransformation );
1508  return aRange;
1509  }
1510 
1511 
1512  void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1513  {
1514  #if OSL_DEBUG_LEVEL > 0
1515  ::basegfx::B2DVector aScale, aTranslate;
1516  double fRotate, fShearX;
1517  _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1518  #endif
1519  if ( m_pVOCImpl->hasControl() )
1520  impl_positionAndZoomControl( _rViewInformation );
1521  BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
1522  }
1523 
1524 
1525  void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1526  {
1527  #if OSL_DEBUG_LEVEL > 0
1528  ::basegfx::B2DVector aScale, aTranslate;
1529  double fRotate, fShearX;
1530  _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1531  #endif
1532  const bool bHadControl = m_pVOCImpl->getExistentControl().is();
1533 
1534  // force control here to make it a VCL ChildWindow. Will be fetched
1535  // and used below by getExistentControl()
1536  m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
1537  impl_positionAndZoomControl( _rViewInformation );
1538 
1539  // get needed data
1540  const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
1541  Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
1542  const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
1543 
1544  if ( !bHadControl && rControl.is() && rControl.isVisible() )
1545  rControl.invalidate();
1546 
1547  // check if we already have an XControl.
1548  if ( !xControlModel.is() || !rControl.is() )
1549  {
1550  // use the default mechanism. This will create a ControlPrimitive2D without
1551  // handing over a XControl. If not even a XControlModel exists, it will
1552  // create the SdrObject fallback visualisation
1553  const drawinglayer::primitive2d::Primitive2DContainer& aTmp = rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer();
1554  rContainer.insert(rContainer.end(), aTmp.begin(), aTmp.end());
1555  return;
1556  }
1557 
1558  // create a primitive and hand over the existing xControl. This will
1559  // allow the primitive to not need to create another one on demand.
1560  rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
1561  m_aTransformation, xControlModel, rControl.getControl() ) );
1562  }
1563 
1564  sal_uInt32 LazyControlCreationPrimitive2D::getPrimitive2DID() const
1565  {
1567  }
1568 
1570  :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
1572  {
1573  }
1574 
1575 
1577  {
1578  m_pImpl->dispose();
1579  m_pImpl = nullptr;
1580 
1581  }
1582 
1583 
1585  {
1586  SolarMutexGuard aSolarGuard;
1587  m_pImpl->ensureControl( nullptr );
1588  return m_pImpl->getExistentControl().getControl();
1589  }
1590 
1591 
1593  const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
1594  {
1595  ControlHolder aControl;
1596 
1597  InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
1598  OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, *_rWindow.GetOutDev(), _rUnoObject,
1599  _rWindow.GetOutDev()->GetViewTransformation(), _rWindow.GetOutDev()->GetInverseViewTransformation(), aControl ) );
1600  return aControl.getControl();
1601  }
1602 
1603 
1605  {
1606  SolarMutexGuard aSolarGuard;
1607 
1608  try
1609  {
1610  const ControlHolder& rControl( m_pImpl->getExistentControl() );
1611  if ( !rControl.is() )
1612  return;
1613 
1614  // only need to care for alive mode
1615  if ( rControl.isDesignMode() )
1616  return;
1617 
1618  // is the visibility correct?
1619  if ( m_pImpl->isControlVisible() == _bVisible )
1620  return;
1621 
1622  // no -> adjust it
1623  rControl.setVisible( _bVisible );
1624  DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
1625  // now this would mean that either isControlVisible is not reliable,
1626  // or that showing/hiding the window did not work as intended.
1627  }
1628  catch( const Exception& )
1629  {
1630  DBG_UNHANDLED_EXCEPTION("svx");
1631  }
1632  }
1633 
1634 
1636  {
1637  SolarMutexGuard aSolarGuard;
1638  m_pImpl->setControlDesignMode( _bDesignMode );
1639 
1640  if(!_bDesignMode)
1641  {
1642  // when live mode is switched on, a refresh is needed. The edit mode visualisation
1643  // needs to be repainted and the now used VCL-Window needs to be positioned and
1644  // sized. Both is done from the repaint refresh.
1645  const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
1646  }
1647  }
1648 
1649 
1651  {
1652  if ( m_pImpl->isDisposed() )
1653  // our control already died.
1654  // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
1655  // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
1657 
1659  // remove this when #i115754# is fixed
1661 
1662  // ignore existing controls which are in alive mode and manually switched to "invisible" #i102090#
1663  const ControlHolder& rControl( m_pImpl->getExistentControl() );
1664  if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
1666 
1667  ::drawinglayer::primitive2d::Primitive2DReference xPrimitive( new LazyControlCreationPrimitive2D( m_pImpl ) );
1668  return ::drawinglayer::primitive2d::Primitive2DContainer { xPrimitive };
1669  }
1670 
1671 
1673  {
1674  SolarMutexGuard aSolarGuard;
1675 
1676  if ( m_pImpl->hasControl() )
1677  {
1678  const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
1679  #if OSL_DEBUG_LEVEL > 0
1680  ::basegfx::B2DVector aScale, aTranslate;
1681  double fRotate, fShearX;
1682  rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1683  #endif
1684 
1685  if ( !rViewInformation.getViewport().isEmpty() )
1686  {
1687  // tdf#121963 check and eventually pre-multiply ViewTransformation
1688  // with GridOffset transformation to avoid alternating positions of
1689  // FormControls which are victims of the non-linear calc ViewTransformation
1690  // aka GridOffset. For other paths (e.g. repaint) this is included already
1691  // as part of the object's sequence of B2DPrimitive - representation
1692  // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
1693  basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
1694 
1696  {
1697  const basegfx::B2DVector& rGridOffset(getGridOffset());
1698 
1699  if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
1700  {
1701  // pre-multiply: GridOffset needs to be applied directly to logic model data
1702  // of object coordinates, so multiply GridOffset from right to make it
1703  // work as 1st change - these objects may still be part of groups/hierarchies
1704  aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
1705  }
1706  }
1707 
1708  m_pImpl->positionAndZoomControl(aViewTransformation);
1709  }
1710  }
1711 
1712  return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
1713  }
1714 
1715 
1717  {
1719  }
1720 
1721 
1723  {
1724  // call parent
1726  const ControlHolder& rControl(m_pImpl->getExistentControl());
1727 
1728  if(!rControl.is() || rControl.isDesignMode())
1729  return;
1730 
1731  // #i93180# if layer visibility has changed and control is in live mode, it is necessary
1732  // to correct visibility to make those control vanish on SdrObject LayerID changes
1733  const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
1734 
1735  if(pSdrPageView)
1736  {
1737  const SdrObject& rObject = getSdrObject();
1738  const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
1739 
1740  if(rControl.isVisible() != bIsLayerVisible)
1741  {
1742  rControl.setVisible(bIsLayerVisible);
1743  }
1744  }
1745  }
1746 
1747 
1749  {
1750  // graphical invalidate at all views
1751  ActionChanged();
1752 
1753  // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
1754  // since e.g. background color has changed and existing decompositions are possibly no
1755  // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
1756  // since it only has a uno reference to the XControlModel
1758  }
1759 
1761  :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
1762  {
1763  }
1764 
1765 
1767  {
1768  }
1769 
1770 
1772  {
1773  if ( !m_pImpl->isPrintableControl() )
1776  }
1777 
1778 
1779 } // namespace sdr::contact
1780 
1781 
1782 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::B2DHomMatrix GetInverseViewTransformation() const
double getY() 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...
constexpr tools::Long Left() const
void setControlDesignMode(bool _bDesignMode) const
sets the design/alive mode of the control
SdrView & GetView()
Definition: svdpagv.hxx:130
::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:235
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
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
bool IsVisible() const
Definition: svdobj.hxx:754
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
static vcl::Window * GetWindow(const css::uno::Reference< css::awt::XWindow > &rxWindow)
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:210
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
constexpr tools::Long Right() const
constexpr tools::Long Top() const
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
Abstract DrawObject.
Definition: svdobj.hxx:259
const OUString & GetUnoControlTypeName() const
Definition: svdouno.hxx:124
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:678
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
constexpr tools::Long Bottom() const
#define ENSURE_OR_THROW(c, m)
Reference< XWindow2 > m_xControlWindow
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:64
::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:91
ViewObjectContactOfUnoControl(ObjectContact &_rObjectContact, ViewContactOfUnoControl &_rViewContact)
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
double getX() const
Reference< XView > m_xControlView
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
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
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