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