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 <utility>
48#include <vcl/canvastools.hxx>
49#include <vcl/svapp.hxx>
50#include <vcl/window.hxx>
56#include <tools/debug.hxx>
60
61/*
62
63Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
64specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
65window as child of the document window, and coupling this Window to a drawing layer object, makes things
66difficult sometimes.
67
68Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
69verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
70an automatic test for one or more of those issues for which this is possible :)
71
72https://bz.apache.org/ooo/show_bug.cgi?id=105992
73zooming documents containing (alive) form controls improperly positions the controls
74
75https://bz.apache.org/ooo/show_bug.cgi?id=104362
76crash when copy a control
77
78https://bz.apache.org/ooo/show_bug.cgi?id=104544
79Gridcontrol duplicated after design view on/off
80
81https://bz.apache.org/ooo/show_bug.cgi?id=102089
82print preview shows control elements with property printable=false
83
84https://bz.apache.org/ooo/show_bug.cgi?id=102090
85problem with setVisible on TextControl
86
87https://bz.apache.org/ooo/show_bug.cgi?id=103138
88loop when insert a control in draw
89
90https://bz.apache.org/ooo/show_bug.cgi?id=101398
91initially-displaying a document with many controls is very slow
92
93https://bz.apache.org/ooo/show_bug.cgi?id=72429
94repaint error in form wizard in bugdoc database
95
96https://bz.apache.org/ooo/show_bug.cgi?id=72694
97form control artifacts when scrolling a text fast
98
99*/
100
101
102namespace sdr::contact {
103
104
105 using namespace ::com::sun::star::awt::InvalidateStyle;
106 using ::com::sun::star::uno::Reference;
107 using ::com::sun::star::uno::XInterface;
108 using ::com::sun::star::uno::UNO_QUERY;
109 using ::com::sun::star::uno::UNO_QUERY_THROW;
110 using ::com::sun::star::uno::Exception;
111 using ::com::sun::star::uno::RuntimeException;
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 OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
283 if ( !_rControl.is() )
284 return;
285
286 #if OSL_DEBUG_LEVEL > 0
287 ::basegfx::B2DTuple aViewScale, aViewTranslate;
288 double nViewRotate(0), nViewShearX(0);
289 _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
290
291 ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
292 double nZoomRotate(0), nZoomShearX(0);
293 _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
294 #endif
295
296 // transform the logic bound rect, using the view transformation, to pixel coordinates
297 ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
298 aTopLeft *= _rViewTransformation;
299 ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
300 aBottomRight *= _rViewTransformation;
301
302 const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
303 static_cast<tools::Long>(std::round(aTopLeft.getY())),
304 static_cast<tools::Long>(std::round(aBottomRight.getX())),
305 static_cast<tools::Long>(std::round(aBottomRight.getY())));
306 _rControl.setPosSize( aPaintRectPixel );
307
308 // determine the scale from the current view transformation, and the normalization matrix
309 ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
310 ::basegfx::B2DVector aScale, aTranslate;
311 double fRotate, fShearX;
312 aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
313 _rControl.setZoom( aScale );
314 }
315
318 static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
319 {
320 try
321 {
322 Reference< XComponent > xControlComp = _rControl.getControl();
323 if ( xControlComp.is() )
324 xControlComp->dispose();
325 }
326 catch( const Exception& )
327 {
329 }
330 _rControl.clear();
331 }
332
333 }
334
335 namespace {
336
339 class IPageViewAccess
340 {
341 public:
344 virtual bool isDesignMode() const = 0;
345
348 virtual Reference< XControlContainer >
349 getControlContainer( const OutputDevice& _rDevice ) const = 0;
350
353 virtual bool isLayerVisible( SdrLayerID _nLayerID ) const = 0;
354
355 protected:
356 ~IPageViewAccess() {}
357 };
358
361 class SdrPageViewAccess : public IPageViewAccess
362 {
364 public:
365 explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
366
367 virtual ~SdrPageViewAccess() {}
368
369 virtual bool isDesignMode() const override;
370 virtual Reference< XControlContainer >
371 getControlContainer( const OutputDevice& _rDevice ) const override;
372 virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
373 };
374
375 }
376
377 bool SdrPageViewAccess::isDesignMode() const
378 {
380 }
381
382
383 Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
384 {
385 Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
386 DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
387 "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
388 return xControlContainer;
389 }
390
391
392 bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
393 {
394 return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
395 }
396
397 namespace {
398
402 class InvisibleControlViewAccess : public IPageViewAccess
403 {
404 private:
405 Reference< XControlContainer >& m_rControlContainer;
406 public:
407 explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
408 :m_rControlContainer( _inout_ControlContainer )
409 {
410 }
411
412 virtual ~InvisibleControlViewAccess() {}
413
414 virtual bool isDesignMode() const override;
415 virtual Reference< XControlContainer >
416 getControlContainer( const OutputDevice& _rDevice ) const override;
417 virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
418 };
419
420 }
421
422 bool InvisibleControlViewAccess::isDesignMode() const
423 {
424 return true;
425 }
426
427
428 Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
429 {
430 if ( !m_rControlContainer.is() )
431 {
432 const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
433 OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
434 if ( pWindow )
436 }
437 return m_rControlContainer;
438 }
439
440
441 bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
442 {
443 return false;
444 }
445
446 namespace {
447
448 //= DummyPageViewAccess
449
457 class DummyPageViewAccess : public IPageViewAccess
458 {
459 public:
460 DummyPageViewAccess()
461 {
462 }
463
464 virtual ~DummyPageViewAccess() {}
465
466 virtual bool isDesignMode() const override;
467 virtual Reference< XControlContainer >
468 getControlContainer( const OutputDevice& _rDevice ) const override;
469 virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
470 };
471
472 }
473
474 bool DummyPageViewAccess::isDesignMode() const
475 {
476 return true;
477 }
478
479
480 Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
481 {
482 return nullptr;
483 }
484
485
486 bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
487 {
488 return true;
489 }
490
491
492 //= ViewObjectContactOfUnoControl_Impl
493
494 typedef ::cppu::WeakImplHelper < XWindowListener
495 , XPropertyChangeListener
496 , XContainerListener
497 , XModeChangeListener
499
502 {
503 private:
504 // tdf#41935 note that access to members is protected with SolarMutex;
505 // the class previously had its own mutex but that is prone to deadlock
506
509
512
514 ControlHolder m_aControl;
515
517 Reference< XContainer > m_xContainer;
518
521
524
527
529 {
533 };
536
538
539 public:
543
546 void dispose();
547
550 bool isDisposed() const { return impl_isDisposed_nofail(); }
551
557 SdrUnoObj* getUnoObject() const;
558
569 void ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
570
575 const ControlHolder&
576 getExistentControl() const { return m_aControl; }
577
578 bool
579 hasControl() const { return m_aControl.is(); }
580
587 void positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
588
594 bool isPrintableControl() const;
595
599 void setControlDesignMode( bool _bDesignMode ) const;
600
604 bool isControlVisible() const { return m_bControlIsVisible; }
605
607 static bool
609 IPageViewAccess const & _rPageView,
610 const OutputDevice& _rDevice,
611 const SdrUnoObj& _rUnoObject,
612 const basegfx::B2DHomMatrix& _rInitialViewTransformation,
613 const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
614 ControlHolder& _out_rControl
615 );
616
619 {
620 ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
621 return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
622 }
623
624 protected:
625 virtual ~ViewObjectContactOfUnoControl_Impl() override;
626
627 // XEventListener
628 virtual void SAL_CALL disposing( const EventObject& Source ) override;
629
630 // XWindowListener
631 virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
632 virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
633 virtual void SAL_CALL windowShown( const EventObject& e ) override;
634 virtual void SAL_CALL windowHidden( const EventObject& e ) override;
635
636 // XPropertyChangeListener
637 virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
638
639 // XModeChangeListener
640 virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
641
642 // XContainerListener
643 virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
644 virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
645 virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
646
647 private:
670 bool impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
671
686
714 static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
715 IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
716
722 void impl_switchControlListening_nothrow( bool _bStart );
723
729 void impl_switchContainerListening_nothrow( bool _bStart );
730
733 void impl_switchDesignModeListening_nothrow( bool _bStart );
734
743 void impl_switchPropertyListening_nothrow( bool _bStart );
744
749 void impl_dispose_nothrow( bool _bAlsoDisposeControl );
750
754 bool impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
755
764 {
765 DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
767 }
768
772 IPageViewAccess const & _rPageView,
773 const OutputDevice& _rDevice,
774 const basegfx::B2DHomMatrix& _rInitialViewTransformation
775 );
776
778 };
779
780 namespace {
781
782 class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
783 {
784 private:
785 typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D BufferedDecompositionPrimitive2D;
786
787 protected:
788 virtual void
789 get2DDecomposition(
791 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
792 ) const override;
793
794 virtual void create2DDecomposition(
796 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
797 ) const override;
798
799 virtual ::basegfx::B2DRange
800 getB2DRange(
801 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
802 ) const override;
803
804 public:
805 explicit LazyControlCreationPrimitive2D( ::rtl::Reference< ViewObjectContactOfUnoControl_Impl > _pVOCImpl )
806 :m_pVOCImpl(std::move( _pVOCImpl ))
807 {
808 ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
809 getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
810 }
811
812 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
813
814 // declare unique ID for this primitive class
815 virtual sal_uInt32 getPrimitive2DID() const override;
816
817 static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
818
819 private:
820 void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
821 {
822 if ( !_rViewInformation.getViewport().isEmpty() )
823 m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
824 }
825
826 private:
833 };
834
835 }
836
838 :m_pAntiImpl( _pAntiImpl )
839 ,m_bCreatingControl( false )
840 ,m_pOutputDeviceForWindow( nullptr )
841 ,m_bControlIsVisible( false )
842 ,m_bIsDesignModeListening( false )
843 ,m_eControlDesignMode( eUnknown )
844 {
845 DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
846
847 const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
849
850 #if OSL_DEBUG_LEVEL > 0
851 ::basegfx::B2DVector aScale, aTranslate;
852 double fRotate, fShearX;
853 m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
854 #endif
855
856 ::basegfx::B2DHomMatrix aScaleNormalization;
857 const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
858 aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
859 aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
860 m_aZoomLevelNormalization *= aScaleNormalization;
861
862 #if OSL_DEBUG_LEVEL > 0
863 m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
864 #endif
865 }
866
867
869 {
870 if ( !impl_isDisposed_nofail() )
871 {
872 acquire();
873 dispose();
874 }
875
876 }
877
878
880 {
882 return;
883
884 if ( m_aControl.is() )
886
887 if ( m_xContainer.is() )
889
890 // dispose the control
891 if ( _bAlsoDisposeControl )
893
894 m_aControl.clear();
895 m_xContainer.clear();
896 m_pOutputDeviceForWindow = nullptr;
897 m_bControlIsVisible = false;
898
899 m_pAntiImpl = nullptr;
900 }
901
902
904 {
905 SolarMutexGuard aSolarGuard;
906 impl_dispose_nothrow( true );
907 }
908
909
911 {
912 OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
914 return nullptr;
915 auto pRet = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
917 "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
918 return pRet;
919 }
920
921
923 {
924 OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
925 if ( !m_aControl.is() )
926 return;
927
928 try
929 {
930 SdrUnoObj* pUnoObject = getUnoObject();
931 if ( pUnoObject )
932 {
933 const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
935 }
936 else
937 OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
938 }
939 catch( const Exception& )
940 {
942 }
943 }
944
945
946 void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
947 {
948 OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
950 return;
951
952 ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
953 if ( pPageViewContact )
954 {
955 SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
958 aPVAccess,
959 rDevice,
960 _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
961 );
962 return;
963 }
964
965 DummyPageViewAccess aNoPageView;
966 const OutputDevice& rDevice( impl_getOutputDevice_throw() );
968 aNoPageView,
969 rDevice,
970 _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
971 );
972 }
973
974
976 {
977 // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
978 // OriginalPaintWindow
979 const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
980 if( oPageOutputDev )
981 return *oPageOutputDev;
982
984 ENSURE_OR_THROW( pDevice, "no output device -> no control" );
985 return *pDevice;
986 }
987
988
989 namespace
990 {
991 void lcl_resetFlag( bool& rbFlag )
992 {
993 rbFlag = false;
994 }
995 }
996
997
998 bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
999 const basegfx::B2DHomMatrix& _rInitialViewTransformation )
1000 {
1001 if ( m_bCreatingControl )
1002 {
1003 OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
1004 // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
1005 // those affected the grid control, which is the only control so far which is visible in design mode (and
1006 // not only in alive mode).
1007 // Creating the control triggered a Window::Update on some of its child windows, which triggered a
1008 // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
1009 // which it is not really prepared for.
1010
1011 // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
1012 // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
1013 return false;
1014 }
1015
1016 m_bCreatingControl = true;
1017 ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
1018
1019 if ( m_aControl.is() )
1020 {
1021 if ( m_pOutputDeviceForWindow.get() == &_rDevice )
1022 return true;
1023
1024 // Somebody requested a control for a new device, which means either of
1025 // - our PageView's paint window changed since we were last here
1026 // - we don't belong to a page view, and are simply painted onto different devices
1027 // The first sounds strange (doesn't it?), the second means we could perhaps
1028 // optimize this in the future - there is no need to re-create the control every time,
1029 // is it? #i74523#
1030 if ( m_xContainer.is() )
1034 }
1035
1036 SdrUnoObj* pUnoObject = getUnoObject();
1037 if ( !pUnoObject )
1038 return false;
1039
1040 ControlHolder aControl;
1041 if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
1042 return false;
1043
1044 m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
1045 m_aControl = aControl;
1046 m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
1047 DBG_ASSERT( ( m_xContainer.is() // either have a XControlContainer
1048 || ( ( !_rPageView.getControlContainer( _rDevice ).is() ) // or don't have any container,
1049 && ( _rDevice.GetOwnerWindow() == nullptr ) // which is allowed for non-Window instances only
1050 )
1051 ),
1052 "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
1053
1054 try
1055 {
1056 m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
1057 m_bControlIsVisible = m_aControl.isVisible();
1058 }
1059 catch( const Exception& )
1060 {
1062 }
1063
1064 // start listening at all aspects of the control which are interesting to us ...
1066
1067 // start listening at the control container, in case somebody tampers with our control
1068 if ( m_xContainer.is() )
1070
1071 return m_aControl.is();
1072 }
1073
1074
1075 bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
1076 const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
1077 const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
1078 {
1079 _out_rControl.clear();
1080
1081 const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
1082 DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
1083 if ( !xControlModel.is() )
1084 return false;
1085
1086 bool bSuccess = false;
1087 try
1088 {
1089 const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
1090
1091 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1092 _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
1093
1094 // tdf#150886 for calc/writer/impress make forms ignore the platform theme
1095 Reference<XPropertySet> xModelProperties(xControlModel, UNO_QUERY);
1096 Reference<XPropertySetInfo> xInfo = xModelProperties ? xModelProperties->getPropertySetInfo() : nullptr;
1097 if (xInfo && xInfo->hasPropertyByName("StandardTheme"))
1098 xModelProperties->setPropertyValue("StandardTheme", Any(!_rUnoObject.getSdrModelFromSdrObject().AreControlsThemed()));
1099
1100 // knit the model and the control
1101 _out_rControl.setModel( xControlModel );
1102 const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
1103
1104 // proper geometry
1106 _out_rControl,
1107 aRect,
1108 _rInitialViewTransformation,
1109 _rInitialZoomNormalization
1110 );
1111
1112 // set design mode before peer is created,
1113 // this is also needed for accessibility
1114 _out_rControl.setDesignMode( _rPageView.isDesignMode() );
1115
1116 // adjust the initial visibility according to the visibility of the layer
1117 impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
1118
1119 // add the control to the respective control container
1120 // do this last
1121 Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
1122 if ( xControlContainer.is() )
1123 xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
1124
1125 bSuccess = true;
1126 }
1127 catch( const Exception& )
1128 {
1130 }
1131
1132 if ( !bSuccess )
1133 {
1134 // delete the control which might have been created already
1136 }
1137
1138 return _out_rControl.is();
1139 }
1140
1141
1143 {
1144 OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
1145
1146 _out_rpPageView = nullptr;
1147 if ( impl_isDisposed_nofail() )
1148 return false;
1149
1150 ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1151 if ( pPageViewContact )
1152 _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
1153
1154 DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
1155 return ( _out_rpPageView != nullptr );
1156 }
1157
1158
1160 {
1161 OSL_PRECOND( m_aControl.is(),
1162 "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
1163
1164 SdrPageView* pPageView( nullptr );
1165 if ( !impl_getPageView_nothrow( pPageView ) )
1166 return;
1167
1168 SdrUnoObj* pUnoObject = getUnoObject();
1169 if ( !pUnoObject )
1170 return;
1171
1172 SdrPageViewAccess aPVAccess( *pPageView );
1173 impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
1174 }
1175
1176
1178 const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
1179 {
1180 // in design mode, there is no problem with the visibility: The XControl is hidden by
1181 // default, and the Drawing Layer will simply not call our paint routine, if we're in
1182 // a hidden layer. So, only alive mode matters.
1183 if ( !_rControl.isDesignMode() )
1184 {
1185 // the layer of our object
1186 SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
1187 // is the object we're residing in visible in this view?
1188 bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
1189
1190 if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
1191 {
1192 _rControl.setVisible( bIsObjectVisible );
1193 }
1194 }
1195 }
1196
1197
1199 {
1200 OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
1201 if ( !m_xContainer.is() )
1202 return;
1203
1204 try
1205 {
1206 if ( _bStart )
1207 m_xContainer->addContainerListener( this );
1208 else
1209 m_xContainer->removeContainerListener( this );
1210 }
1211 catch( const Exception& )
1212 {
1214 }
1215 }
1216
1217
1219 {
1220 OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
1221 if ( !m_aControl.is() )
1222 return;
1223
1224 try
1225 {
1226 // listen for visibility changes
1227 if ( _bStart )
1228 m_aControl.addWindowListener( this );
1229 else
1230 m_aControl.removeWindowListener( this );
1231
1232 // in design mode, listen for some more aspects
1234
1235 // listen for design mode changes
1236 Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
1237 if ( _bStart )
1238 xDesignModeChanges->addModeChangeListener( this );
1239 else
1240 xDesignModeChanges->removeModeChangeListener( this );
1241 }
1242 catch( const Exception& )
1243 {
1245 }
1246 }
1247
1248
1250 {
1251 if ( m_bIsDesignModeListening != _bStart )
1252 {
1253 m_bIsDesignModeListening = _bStart;
1255 }
1256 }
1257
1258
1260 {
1261 OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
1262 if ( !m_aControl.is() )
1263 return;
1264
1265 try
1266 {
1267 Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
1268 if ( _bStart )
1269 xModelProperties->addPropertyChangeListener( OUString(), this );
1270 else
1271 xModelProperties->removePropertyChangeListener( OUString(), this );
1272 }
1273 catch( const Exception& )
1274 {
1276 }
1277 }
1278
1279
1281 {
1282 SdrUnoObj* pUnoObject = getUnoObject();
1283 if ( !pUnoObject )
1284 return false;
1285
1286 bool bIsPrintable = false;
1287 try
1288 {
1289 Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
1290 OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
1291 }
1292 catch( const Exception& )
1293 {
1295 }
1296 return bIsPrintable;
1297 }
1298
1299
1300 void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
1301 {
1302 SolarMutexGuard aSolarGuard;
1303 // some code below - in particular our disposal - might trigger actions which require the
1304 // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1305 // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1306 // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1307
1308 if ( !m_aControl.is() )
1309 return;
1310
1311 if ( ( m_aControl == Source.Source )
1312 || ( m_aControl.getModel() == Source.Source )
1313 )
1314 {
1315 // the model or the control is dying ... hmm, not much sense in that we ourself continue
1316 // living
1317 impl_dispose_nothrow( false );
1318 return;
1319 }
1320
1321 DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
1322 }
1323
1324
1325 void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
1326 {
1327 // not interested in
1328 }
1329
1330
1331 void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
1332 {
1333 // not interested in
1334 }
1335
1336
1337 void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
1338 {
1339 SolarMutexGuard aSolarGuard;
1340 m_bControlIsVisible = true;
1341 }
1342
1343
1344 void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
1345 {
1346 SolarMutexGuard aSolarGuard;
1347 m_bControlIsVisible = false;
1348 }
1349
1350
1351 void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
1352 {
1353 SolarMutexGuard aSolarGuard;
1354 // (re)painting might require VCL operations, which need the SolarMutex
1355
1356 OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
1357 if ( impl_isDisposed_nofail() )
1358 return;
1359
1360 DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
1361 if ( !m_aControl.is() )
1362 return;
1363
1364 // a generic property changed. If we're in design mode, we need to repaint the control
1366 {
1368 }
1369 }
1370
1371
1372 void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
1373 {
1374 SolarMutexGuard aSolarGuard;
1375
1376 DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
1377
1378 m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
1379
1381
1382 try
1383 {
1384 // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
1386 }
1387 catch( const Exception& )
1388 {
1390 }
1391 }
1392
1393
1394 void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
1395 {
1396 // not interested in
1397 }
1398
1399
1400 void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
1401 {
1402 SolarMutexGuard aSolarGuard;
1403 // some code below - in particular our disposal - might trigger actions which require the
1404 // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1405 // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1406 // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1407 DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
1408
1409 if ( m_aControl == Event.Element )
1410 impl_dispose_nothrow( false );
1411 }
1412
1413
1414 void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
1415 {
1416 SolarMutexGuard aSolarGuard;
1417 DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
1418
1419 if ( ! ( m_aControl == Event.ReplacedElement ) )
1420 return;
1421
1422 Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
1423 DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
1424 if ( !xNewControl.is() )
1425 return;
1426
1427 ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
1428
1429 DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
1430 // another model should - in the drawing layer - also imply another SdrUnoObj, which
1431 // should also result in new ViewContact, and thus in new ViewObjectContacts
1432
1434
1435 ControlHolder aNewControl( xNewControl );
1436 aNewControl.setZoom( m_aControl.getZoom() );
1437 aNewControl.setPosSize( m_aControl.getPosSize() );
1438 aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
1439
1440 m_aControl = xNewControl;
1441 m_bControlIsVisible = m_aControl.isVisible();
1442
1444
1446 }
1447
1448
1450 {
1451 if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
1452 // nothing to do
1453 return;
1454 m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
1455
1456 if ( !m_aControl.is() )
1457 // nothing to do, the setting will be respected as soon as the control
1458 // is created
1459 return;
1460
1461 try
1462 {
1463 m_aControl.setDesignMode( _bDesignMode );
1464 }
1465 catch( const Exception& )
1466 {
1468 }
1469 }
1470
1471
1472 //= LazyControlCreationPrimitive2D
1473
1474
1475 bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1476 {
1477 if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
1478 return false;
1479
1480 const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
1481 if ( !pRHS )
1482 return false;
1483
1484 if ( m_pVOCImpl != pRHS->m_pVOCImpl )
1485 return false;
1486
1487 if ( m_aTransformation != pRHS->m_aTransformation )
1488 return false;
1489
1490 return true;
1491 }
1492
1493
1494 void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
1495 {
1496 // Do use model data directly to create the correct geometry. Do NOT
1497 // use getBoundRect()/getSnapRect() here; these will use the sequence of
1498 // primitives themselves in the long run.
1499 const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
1501
1502 _out_Transformation.identity();
1503 _out_Transformation.set( 0, 0, aRange.getWidth() );
1504 _out_Transformation.set( 1, 1, aRange.getHeight() );
1505 _out_Transformation.set( 0, 2, aRange.getMinX() );
1506 _out_Transformation.set( 1, 2, aRange.getMinY() );
1507 }
1508
1509
1510 ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
1511 {
1512 ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
1513 aRange.transform( m_aTransformation );
1514 return aRange;
1515 }
1516
1517
1518 void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1519 {
1520 #if OSL_DEBUG_LEVEL > 0
1521 ::basegfx::B2DVector aScale, aTranslate;
1522 double fRotate, fShearX;
1523 _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1524 #endif
1525 if ( m_pVOCImpl->hasControl() )
1526 impl_positionAndZoomControl( _rViewInformation );
1527 BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
1528 }
1529
1530
1531 void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1532 {
1533 #if OSL_DEBUG_LEVEL > 0
1534 ::basegfx::B2DVector aScale, aTranslate;
1535 double fRotate, fShearX;
1536 _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1537 #endif
1538 const bool bHadControl = m_pVOCImpl->getExistentControl().is();
1539
1540 // force control here to make it a VCL ChildWindow. Will be fetched
1541 // and used below by getExistentControl()
1542 m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
1543 impl_positionAndZoomControl( _rViewInformation );
1544
1545 // get needed data
1546 const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
1547 Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
1548 const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
1549
1550 if ( !bHadControl && rControl.is() && rControl.isVisible() )
1551 rControl.invalidate();
1552
1553 // check if we already have an XControl.
1554 if ( !xControlModel.is() || !rControl.is() )
1555 {
1556 // use the default mechanism. This will create a ControlPrimitive2D without
1557 // handing over a XControl. If not even a XControlModel exists, it will
1558 // create the SdrObject fallback visualisation
1559 rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer(rContainer);
1560 return;
1561 }
1562
1563 // create a primitive and hand over the existing xControl. This will
1564 // allow the primitive to not need to create another one on demand.
1565 rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
1566 m_aTransformation, xControlModel, rControl.getControl() ) );
1567 }
1568
1569 sal_uInt32 LazyControlCreationPrimitive2D::getPrimitive2DID() const
1570 {
1572 }
1573
1575 :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
1577 {
1578 }
1579
1580
1582 {
1583 m_pImpl->dispose();
1584 m_pImpl = nullptr;
1585
1586 }
1587
1588
1590 {
1591 SolarMutexGuard aSolarGuard;
1592 m_pImpl->ensureControl( nullptr );
1593 return m_pImpl->getExistentControl().getControl();
1594 }
1595
1596
1598 const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
1599 {
1600 ControlHolder aControl;
1601
1602 InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
1603 OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, *_rWindow.GetOutDev(), _rUnoObject,
1604 _rWindow.GetOutDev()->GetViewTransformation(), _rWindow.GetOutDev()->GetInverseViewTransformation(), aControl ) );
1605 return aControl.getControl();
1606 }
1607
1608
1610 {
1611 SolarMutexGuard aSolarGuard;
1612
1613 try
1614 {
1615 const ControlHolder& rControl( m_pImpl->getExistentControl() );
1616 if ( !rControl.is() )
1617 return;
1618
1619 // only need to care for alive mode
1620 if ( rControl.isDesignMode() )
1621 return;
1622
1623 // is the visibility correct?
1624 if ( m_pImpl->isControlVisible() == _bVisible )
1625 return;
1626
1627 // no -> adjust it
1628 rControl.setVisible( _bVisible );
1629 DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
1630 // now this would mean that either isControlVisible is not reliable,
1631 // or that showing/hiding the window did not work as intended.
1632 }
1633 catch( const Exception& )
1634 {
1636 }
1637 }
1638
1639
1641 {
1642 SolarMutexGuard aSolarGuard;
1643 m_pImpl->setControlDesignMode( _bDesignMode );
1644
1645 if(!_bDesignMode)
1646 {
1647 // when live mode is switched on, a refresh is needed. The edit mode visualisation
1648 // needs to be repainted and the now used VCL-Window needs to be positioned and
1649 // sized. Both is done from the repaint refresh.
1650 const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
1651 }
1652 }
1653
1654
1656 {
1657 if ( m_pImpl->isDisposed() )
1658 // our control already died.
1659 // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
1660 // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
1661 return;
1662
1663 if ( GetObjectContact().getViewInformation2D().getViewTransformation().isIdentity() )
1664 // remove this when #i115754# is fixed
1665 return;
1666
1667 // ignore existing controls which are in alive mode and manually switched to "invisible" #i102090#
1668 const ControlHolder& rControl( m_pImpl->getExistentControl() );
1669 if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
1670 return;
1671
1672 rVisitor.visit( new LazyControlCreationPrimitive2D( m_pImpl ) );
1673 }
1674
1675
1677 {
1678 SolarMutexGuard aSolarGuard;
1679
1680 if ( m_pImpl->hasControl() )
1681 {
1682 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
1683 #if OSL_DEBUG_LEVEL > 0
1684 ::basegfx::B2DVector aScale, aTranslate;
1685 double fRotate, fShearX;
1686 rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1687 #endif
1688
1689 if ( !rViewInformation.getViewport().isEmpty() )
1690 {
1691 // tdf#121963 check and eventually pre-multiply ViewTransformation
1692 // with GridOffset transformation to avoid alternating positions of
1693 // FormControls which are victims of the non-linear calc ViewTransformation
1694 // aka GridOffset. For other paths (e.g. repaint) this is included already
1695 // as part of the object's sequence of B2DPrimitive - representation
1696 // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
1697 basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
1698
1699 if(GetObjectContact().supportsGridOffsets())
1700 {
1701 const basegfx::B2DVector& rGridOffset(getGridOffset());
1702
1703 if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
1704 {
1705 // pre-multiply: GridOffset needs to be applied directly to logic model data
1706 // of object coordinates, so multiply GridOffset from right to make it
1707 // work as 1st change - these objects may still be part of groups/hierarchies
1708 aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
1709 }
1710 }
1711
1712 m_pImpl->positionAndZoomControl(aViewTransformation);
1713 }
1714 }
1715
1716 return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
1717 }
1718
1719
1721 {
1723 }
1724
1725
1727 {
1728 // call parent
1730 const ControlHolder& rControl(m_pImpl->getExistentControl());
1731
1732 if(!rControl.is() || rControl.isDesignMode())
1733 return;
1734
1735 // #i93180# if layer visibility has changed and control is in live mode, it is necessary
1736 // to correct visibility to make those control vanish on SdrObject LayerID changes
1737 const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
1738
1739 if(pSdrPageView)
1740 {
1741 const SdrObject& rObject = getSdrObject();
1742 const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
1743
1744 if(rControl.isVisible() != bIsLayerVisible)
1745 {
1746 rControl.setVisible(bIsLayerVisible);
1747 }
1748 }
1749 }
1750
1751
1753 {
1754 // graphical invalidate at all views
1755 ActionChanged();
1756
1757 // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
1758 // since e.g. background color has changed and existing decompositions are possibly no
1759 // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
1760 // since it only has a uno reference to the XControlModel
1762 }
1763
1765 :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
1766 {
1767 }
1768
1769
1771 {
1772 }
1773
1774
1776 {
1777 if ( !m_pImpl->isPrintableControl() )
1778 return;
1780 }
1781
1782
1783} // namespace sdr::contact
1784
1785
1786/* 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:271
Abstract DrawObject.
Definition: svdobj.hxx:261
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:28
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)