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