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