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