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