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 
21 #include <sdr/contact/viewobjectcontactofunocontrol.hxx>
22 #include <sdr/contact/viewcontactofunocontrol.hxx>
23 #include <svx/sdr/contact/displayinfo.hxx>
24 #include <svx/sdr/contact/objectcontactofpageview.hxx>
25 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
26 #include <svx/svdouno.hxx>
27 #include <svx/svdpagv.hxx>
28 #include <svx/svdview.hxx>
29 #include <svx/sdrpagewindow.hxx>
30 
31 #include <com/sun/star/awt/XControl.hpp>
32 #include <com/sun/star/awt/XControlModel.hpp>
33 #include <com/sun/star/awt/XControlContainer.hpp>
34 #include <com/sun/star/awt/XWindow2.hpp>
35 #include <com/sun/star/awt/PosSize.hpp>
36 #include <com/sun/star/awt/XView.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/lang/XComponent.hpp>
39 #include <com/sun/star/awt/InvalidateStyle.hpp>
40 #include <com/sun/star/util/XModeChangeListener.hpp>
41 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
42 #include <com/sun/star/uno/XComponentContext.hpp>
43 #include <com/sun/star/container/XContainerListener.hpp>
44 #include <com/sun/star/container/XContainer.hpp>
45 
46 #include <vcl/canvastools.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/window.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <comphelper/scopeguard.hxx>
51 #include <cppuhelper/implbase.hxx>
52 #include <toolkit/helper/vclunohelper.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <tools/debug.hxx>
55 #include <basegfx/matrix/b2dhommatrix.hxx>
56 #include <basegfx/matrix/b2dhommatrixtools.hxx>
57 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
58 
59 /*
60 
61 Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
62 specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
63 window as child of the document window, and coupling this Window to a drawing layer object, makes things
64 difficult sometimes.
65 
66 Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
67 verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
68 an automatic test for one or more of those issues for which this is possible :)
69 
70 https://bz.apache.org/ooo/show_bug.cgi?id=105992
71 zooming documents containing (alive) form controls improperly positions the controls
72 
73 https://bz.apache.org/ooo/show_bug.cgi?id=104362
74 crash when copy a control
75 
76 https://bz.apache.org/ooo/show_bug.cgi?id=104544
77 Gridcontrol duplicated after design view on/off
78 
79 https://bz.apache.org/ooo/show_bug.cgi?id=102089
80 print preview shows control elements with property printable=false
81 
82 https://bz.apache.org/ooo/show_bug.cgi?id=102090
83 problem with setVisible on TextControl
84 
85 https://bz.apache.org/ooo/show_bug.cgi?id=103138
86 loop when insert a control in draw
87 
88 https://bz.apache.org/ooo/show_bug.cgi?id=101398
89 initially-displaying a document with many controls is very slow
90 
91 https://bz.apache.org/ooo/show_bug.cgi?id=72429
92 repaint error in form wizard in bugdoc database
93 
94 https://bz.apache.org/ooo/show_bug.cgi?id=72694
95 form control artifacts when scrolling a text fast
96 
97 */
98 
99 
100 namespace sdr::contact {
101 
102 
103     using namespace ::com::sun::star::awt::InvalidateStyle;
104     using ::com::sun::star::uno::Reference;
105     using ::com::sun::star::uno::XInterface;
106     using ::com::sun::star::uno::UNO_QUERY;
107     using ::com::sun::star::uno::UNO_QUERY_THROW;
108     using ::com::sun::star::uno::Exception;
109     using ::com::sun::star::uno::RuntimeException;
110     using ::com::sun::star::awt::XControl;
111     using ::com::sun::star::awt::XControlModel;
112     using ::com::sun::star::awt::XControlContainer;
113     using ::com::sun::star::awt::XWindow2;
114     using ::com::sun::star::awt::XWindowListener;
115     using ::com::sun::star::awt::PosSize::POSSIZE;
116     using ::com::sun::star::awt::XView;
117     using ::com::sun::star::awt::WindowEvent;
118     using ::com::sun::star::beans::XPropertySet;
119     using ::com::sun::star::lang::XComponent;
120     using ::com::sun::star::awt::XWindowPeer;
121     using ::com::sun::star::beans::XPropertyChangeListener;
122     using ::com::sun::star::util::XModeChangeListener;
123     using ::com::sun::star::util::XModeChangeBroadcaster;
124     using ::com::sun::star::util::ModeChangeEvent;
125     using ::com::sun::star::lang::EventObject;
126     using ::com::sun::star::beans::PropertyChangeEvent;
127     using ::com::sun::star::container::XContainerListener;
128     using ::com::sun::star::container::XContainer;
129     using ::com::sun::star::container::ContainerEvent;
130     using ::com::sun::star::uno::Any;
131 
132     namespace {
133 
134     class ControlHolder
135     {
136     private:
137         Reference< XControl >   m_xControl;
138         Reference< XWindow2 >   m_xControlWindow;
139         Reference< XView    >   m_xControlView;
140 
141     public:
ControlHolder()142         ControlHolder()
143             :m_xControl()
144             ,m_xControlWindow()
145             ,m_xControlView()
146         {
147         }
148 
ControlHolder(const Reference<XControl> & _rxControl)149         explicit ControlHolder( const Reference< XControl >& _rxControl )
150             :m_xControl()
151             ,m_xControlWindow()
152             ,m_xControlView()
153         {
154             *this = _rxControl;
155         }
156 
operator =(const Reference<XControl> & _rxControl)157         ControlHolder& operator=( const Reference< XControl >& _rxControl )
158         {
159             clear();
160 
161             m_xControl = _rxControl;
162             if ( m_xControl.is() )
163             {
164                 m_xControlWindow.set( m_xControl, UNO_QUERY );
165                 m_xControlView.set( m_xControl, UNO_QUERY );
166                 if ( !m_xControlWindow.is() || !m_xControlView.is() )
167                 {
168                     OSL_FAIL( "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
169                     clear();
170                 }
171             }
172 
173             return *this;
174         }
175 
176     public:
is() const177         bool    is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
clear()178         void    clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
179 
180         // delegators for the methods of the UNO interfaces
181         // Note all those will crash if called for a NULL object.
isDesignMode() const182         bool     isDesignMode() const                        { return m_xControl->isDesignMode();         }
setDesignMode(const bool _bDesign) const183         void     setDesignMode( const bool _bDesign ) const  { m_xControl->setDesignMode( _bDesign );     }
isVisible() const184         bool     isVisible() const                           { return m_xControlWindow->isVisible();      }
setVisible(const bool _bVisible) const185         void     setVisible( const bool _bVisible ) const    { m_xControlWindow->setVisible( _bVisible ); }
186         Reference< XControlModel >
getModel() const187                         getModel() const { return m_xControl->getModel(); }
setModel(const Reference<XControlModel> & _m) const188         void     setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
189 
addWindowListener(const Reference<XWindowListener> & _l) const190         void     addWindowListener( const Reference< XWindowListener >& _l ) const    { m_xControlWindow->addWindowListener( _l );    }
removeWindowListener(const Reference<XWindowListener> & _l) const191         void     removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
192                void     setPosSize( const tools::Rectangle& _rPosSize ) const;
193                tools::Rectangle
194                         getPosSize() const;
195                void     setZoom( const ::basegfx::B2DVector& _rScale ) const;
196                ::basegfx::B2DVector
197                         getZoom() const;
198 
199                void     invalidate() const;
200 
201     public:
getControl() const202         const Reference< XControl >&    getControl() const  { return m_xControl; }
203     };
204 
operator ==(const ControlHolder & _rControl,const Reference<XInterface> & _rxCompare)205     bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
206     {
207         return _rControl.getControl() == _rxCompare;
208     }
209 
operator ==(const ControlHolder & _rControl,const Any & _rxCompare)210     bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
211     {
212         return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
213     }
214 
215     }
216 
setPosSize(const tools::Rectangle & _rPosSize) const217     void ControlHolder::setPosSize( const tools::Rectangle& _rPosSize ) const
218     {
219         // no check whether we're valid, this is the responsibility of the caller
220 
221         // don't call setPosSize when pos/size did not change #i104181#
222         ::tools::Rectangle aCurrentRect( getPosSize() );
223         if ( aCurrentRect != _rPosSize )
224         {
225             m_xControlWindow->setPosSize(
226                 _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
227                 POSSIZE
228             );
229         }
230     }
231 
232 
getPosSize() const233     ::tools::Rectangle ControlHolder::getPosSize() const
234     {
235         // no check whether we're valid, this is the responsibility of the caller
236         return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
237     }
238 
239 
setZoom(const::basegfx::B2DVector & _rScale) const240     void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
241     {
242         // no check whether we're valid, this is the responsibility of the caller
243         m_xControlView->setZoom( static_cast<float>(_rScale.getX()), static_cast<float>(_rScale.getY()) );
244     }
245 
246 
invalidate() const247     void ControlHolder::invalidate() const
248     {
249         Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
250         if ( xPeer.is() )
251         {
252             VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xPeer );
253             OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
254             if ( pWindow )
255                 pWindow->Invalidate();
256         }
257     }
258 
259 
getZoom() const260     ::basegfx::B2DVector ControlHolder::getZoom() const
261     {
262         // no check whether we're valid, this is the responsibility of the caller
263 
264         // Argh. Why does XView have a setZoom only, but not a getZoom?
265         VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
266         OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
267 
268         ::basegfx::B2DVector aZoom( 1, 1 );
269         if ( pWindow )
270         {
271             const Fraction& rZoom( pWindow->GetZoom() );
272             aZoom.setX( static_cast<double>(rZoom) );
273             aZoom.setY( static_cast<double>(rZoom) );
274         }
275         return aZoom;
276     }
277 
278     namespace UnoControlContactHelper {
279 
280     /** positions a control, and sets its zoom mode, using a given transformation and output device
281      */
adjustControlGeometry_throw(const ControlHolder & _rControl,const tools::Rectangle & _rLogicBoundingRect,const basegfx::B2DHomMatrix & _rViewTransformation,const::basegfx::B2DHomMatrix & _rZoomLevelNormalization)282     static void adjustControlGeometry_throw( const ControlHolder& _rControl, const tools::Rectangle& _rLogicBoundingRect,
283         const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
284     {
285         OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
286         if ( !_rControl.is() )
287             return;
288 
289     #if OSL_DEBUG_LEVEL > 0
290         ::basegfx::B2DTuple aViewScale, aViewTranslate;
291         double nViewRotate(0), nViewShearX(0);
292         _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
293 
294         ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
295         double nZoomRotate(0), nZoomShearX(0);
296         _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
297     #endif
298 
299         // transform the logic bound rect, using the view transformation, to pixel coordinates
300         ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
301         aTopLeft *= _rViewTransformation;
302         ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
303         aBottomRight *= _rViewTransformation;
304 
305         const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
306                                                static_cast<tools::Long>(std::round(aTopLeft.getY())),
307                                                static_cast<tools::Long>(std::round(aBottomRight.getX())),
308                                                static_cast<tools::Long>(std::round(aBottomRight.getY())));
309         _rControl.setPosSize( aPaintRectPixel );
310 
311         // determine the scale from the current view transformation, and the normalization matrix
312         ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
313         ::basegfx::B2DVector aScale, aTranslate;
314         double fRotate, fShearX;
315         aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
316         _rControl.setZoom( aScale );
317     }
318 
319     /** disposes the given control
320      */
disposeAndClearControl_nothrow(ControlHolder & _rControl)321     static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
322     {
323         try
324         {
325             Reference< XComponent > xControlComp = _rControl.getControl();
326             if ( xControlComp.is() )
327                 xControlComp->dispose();
328         }
329         catch( const Exception& )
330         {
331             DBG_UNHANDLED_EXCEPTION("svx");
332         }
333         _rControl.clear();
334     }
335 
336     }
337 
338     namespace {
339 
340     /** interface encapsulating access to an SdrPageView, stripped down to the methods we really need
341      */
342     class IPageViewAccess
343     {
344     public:
345         /** determines whether the view is currently in design mode
346          */
347         virtual bool    isDesignMode() const = 0;
348 
349         /** retrieves the control container for a given output device
350          */
351         virtual Reference< XControlContainer >
352                         getControlContainer( const OutputDevice& _rDevice ) const = 0;
353 
354         /** determines whether a given layer is visible
355          */
356         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const = 0;
357 
358     protected:
~IPageViewAccess()359         ~IPageViewAccess() {}
360     };
361 
362     /** is a ->IPageViewAccess implementation based on a real ->SdrPageView instance
363      */
364     class SdrPageViewAccess : public IPageViewAccess
365     {
366         const SdrPageView&  m_rPageView;
367     public:
SdrPageViewAccess(const SdrPageView & _rPageView)368         explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
369 
~SdrPageViewAccess()370         virtual ~SdrPageViewAccess() {}
371 
372         virtual bool    isDesignMode() const override;
373         virtual Reference< XControlContainer >
374                         getControlContainer( const OutputDevice& _rDevice ) const override;
375         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const override;
376     };
377 
378     }
379 
isDesignMode() const380     bool SdrPageViewAccess::isDesignMode() const
381     {
382         return m_rPageView.GetView().IsDesignMode();
383     }
384 
385 
getControlContainer(const OutputDevice & _rDevice) const386     Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
387     {
388         Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
389         DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
390             "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
391         return xControlContainer;
392     }
393 
394 
isLayerVisible(SdrLayerID _nLayerID) const395     bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
396     {
397         return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
398     }
399 
400     namespace {
401 
402     /** is a ->IPageViewAccess implementation which can be used to create an invisible control for
403         an arbitrary window
404      */
405     class InvisibleControlViewAccess : public IPageViewAccess
406     {
407     private:
408         Reference< XControlContainer >& m_rControlContainer;
409     public:
InvisibleControlViewAccess(Reference<XControlContainer> & _inout_ControlContainer)410         explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
411             :m_rControlContainer( _inout_ControlContainer )
412         {
413         }
414 
~InvisibleControlViewAccess()415         virtual ~InvisibleControlViewAccess() {}
416 
417         virtual bool    isDesignMode() const override;
418         virtual Reference< XControlContainer >
419                         getControlContainer( const OutputDevice& _rDevice ) const override;
420         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const override;
421     };
422 
423     }
424 
isDesignMode() const425     bool InvisibleControlViewAccess::isDesignMode() const
426     {
427         return true;
428     }
429 
430 
getControlContainer(const OutputDevice & _rDevice) const431     Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
432     {
433         if ( !m_rControlContainer.is() )
434         {
435             const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
436             OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
437             if ( pWindow )
438                 m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< vcl::Window* >( pWindow ) );
439         }
440         return m_rControlContainer;
441     }
442 
443 
isLayerVisible(SdrLayerID) const444     bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
445     {
446         return false;
447     }
448 
449     namespace {
450 
451     //= DummyPageViewAccess
452 
453     /** is a ->IPageViewAccess implementation which can be used to create a control for an arbitrary
454         non-Window device
455 
456         The implementation will report the "PageView" as being in design mode, all layers to be visible,
457         and will not return any ControlContainer, so all control container related features (notifications etc)
458         are not available.
459      */
460     class DummyPageViewAccess : public IPageViewAccess
461     {
462     public:
DummyPageViewAccess()463         DummyPageViewAccess()
464         {
465         }
466 
~DummyPageViewAccess()467         virtual ~DummyPageViewAccess() {}
468 
469         virtual bool    isDesignMode() const override;
470         virtual Reference< XControlContainer >
471                         getControlContainer( const OutputDevice& _rDevice ) const override;
472         virtual bool    isLayerVisible( SdrLayerID _nLayerID ) const override;
473     };
474 
475     }
476 
isDesignMode() const477     bool DummyPageViewAccess::isDesignMode() const
478     {
479         return true;
480     }
481 
482 
getControlContainer(const OutputDevice &) const483     Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
484     {
485         return nullptr;
486     }
487 
488 
isLayerVisible(SdrLayerID) const489     bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
490     {
491         return true;
492     }
493 
494 
495     //= ViewObjectContactOfUnoControl_Impl
496 
497     typedef     ::cppu::WeakImplHelper <   XWindowListener
498                                         ,   XPropertyChangeListener
499                                         ,   XContainerListener
500                                         ,   XModeChangeListener
501                                         >   ViewObjectContactOfUnoControl_Impl_Base;
502 
503     class ViewObjectContactOfUnoControl_Impl:
504         public ViewObjectContactOfUnoControl_Impl_Base
505     {
506     private:
507         // tdf#41935 note that access to members is protected with SolarMutex;
508         // the class previously had its own mutex but that is prone to deadlock
509 
510         /// the instance whose IMPL we are
511         ViewObjectContactOfUnoControl*  m_pAntiImpl;
512 
513         /// are we currently inside impl_ensureControl_nothrow?
514         bool                            m_bCreatingControl;
515 
516         /// the control we're responsible for
517         ControlHolder                   m_aControl;
518 
519         /// the ControlContainer where we inserted our control
520         Reference< XContainer >         m_xContainer;
521 
522         /// the output device for which the control was created
523         VclPtr<OutputDevice>            m_pOutputDeviceForWindow;
524 
525         /// flag indicating whether the control is currently visible
526         bool                            m_bControlIsVisible;
527 
528         /// are we currently listening at a design mode control?
529         bool                            m_bIsDesignModeListening;
530 
531         enum ViewControlMode
532         {
533             eDesign,
534             eAlive,
535             eUnknown
536         };
537         /// is the control currently in design mode?
538         mutable ViewControlMode         m_eControlDesignMode;
539 
540         ::basegfx::B2DHomMatrix         m_aZoomLevelNormalization;
541 
542     public:
543         explicit ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl );
544         ViewObjectContactOfUnoControl_Impl(const ViewObjectContactOfUnoControl_Impl&) = delete;
545         ViewObjectContactOfUnoControl_Impl& operator=(const ViewObjectContactOfUnoControl_Impl&) = delete;
546 
547         /** disposes the instance, which is nonfunctional afterwards
548         */
549         void dispose();
550 
551         /** determines whether the instance is disposed
552         */
isDisposed() const553         bool isDisposed() const { return impl_isDisposed_nofail(); }
554 
555         /** returns the SdrUnoObject associated with the ViewContact
556 
557             @precond
558                 We're not disposed.
559         */
560         bool    getUnoObject( SdrUnoObj*& _out_rpObject ) const;
561 
562         /** ensures that we have an ->XControl
563 
564             Must only be called if a control is needed when no DisplayInfo is present, yet.
565 
566             For creating a control, an ->OutputDevice is needed, and an ->SdrPageView. Both will be obtained
567             from a ->ObjectContactOfPageView. So, if our (anti-impl's) object contact is not a ->ObjectContactOfPageView,
568             this method fill fail.
569 
570             Failure of this method will be reported via an assertion in a non-product version.
571         */
572         void    ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
573 
574         /** returns our XControl, if it already has been created
575 
576             If you want to ensure that the control exists before accessing it, use ->ensureControl
577         */
578         const ControlHolder&
getExistentControl() const579                 getExistentControl() const { return m_aControl; }
580 
581         bool
hasControl() const582                 hasControl() const { return m_aControl.is(); }
583 
584         /** positions our XControl according to the geometry settings in the SdrUnoObj, modified by the given
585             transformation, and sets proper zoom settings according to our device
586 
587             @precond
588                 ->m_pOutputDeviceForWindow and ->m_aControl are not <NULL/>
589         */
590         void    positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
591 
592         /** determines whether or not our control is printable
593 
594             Effectively, this method returns the value of the "Printable" property
595             of the control's model. If we have no control, <FALSE/> is returned.
596         */
597         bool    isPrintableControl() const;
598 
599         /** sets the design mode on the control, or at least remembers the flag for the
600             time the control is created
601         */
602         void    setControlDesignMode( bool _bDesignMode ) const;
603 
604         /** determines whether our control is currently visible
605             @nofail
606         */
isControlVisible() const607         bool    isControlVisible() const { return m_bControlIsVisible; }
608 
609         /// creates an XControl for the given device and SdrUnoObj
610         static bool
611                 createControlForDevice(
612                     IPageViewAccess const & _rPageView,
613                     const OutputDevice& _rDevice,
614                     const SdrUnoObj& _rUnoObject,
615                     const basegfx::B2DHomMatrix& _rInitialViewTransformation,
616                     const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
617                     ControlHolder& _out_rControl
618                 );
619 
620         const ViewContactOfUnoControl&
getViewContact() const621                 getViewContact() const
622         {
623             ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
624             return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
625         }
626 
627     protected:
628         virtual ~ViewObjectContactOfUnoControl_Impl() override;
629 
630         // XEventListener
631         virtual void SAL_CALL disposing( const EventObject& Source ) override;
632 
633         // XWindowListener
634         virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
635         virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
636         virtual void SAL_CALL windowShown( const EventObject& e ) override;
637         virtual void SAL_CALL windowHidden( const EventObject& e ) override;
638 
639         // XPropertyChangeListener
640         virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
641 
642         // XModeChangeListener
643         virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
644 
645         // XContainerListener
646         virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
647         virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
648         virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
649 
650     private:
651         /** retrieves the SdrPageView which our associated SdrPageViewWindow belongs to
652 
653             @param out_rpPageView
654                 a reference to a pointer holding, upon return, the desired SdrPageView
655 
656             @return
657                 <TRUE/> if and only if a ->SdrPageView could be obtained
658 
659             @precond
660                 We really belong to an SdrPageViewWindow. Perhaps (I'm not sure ATM :)
661                 there are instance for which this might not be true, but those instances
662                 should never have a need to call this method.
663 
664             @precond
665                 We're not disposed.
666 
667             @postcond
668                 The method expects success, if it returns with <FALSE/>, this will have been
669                 asserted.
670 
671             @nothrow
672         */
673         bool    impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
674 
675         /** adjusts the control visibility so it respects its layer's visibility
676 
677             @precond
678                 ->m_aControl is not <NULL/>
679 
680             @precond
681                 We're not disposed.
682 
683             @precond
684                 We really belong to an SdrPageViewWindow. There are instance for which this
685                 might not be true, but those instances should never have a need to call
686                 this method.
687         */
688         void impl_adjustControlVisibilityToLayerVisibility_throw();
689 
690         /** adjusts the control visibility so it respects its layer's visibility
691 
692             The control must never be visible if it's in design mode.
693             In alive mode, it must be visibility if and only it's on a visible layer.
694 
695             @param _rxControl
696                 the control whose visibility is to be adjusted
697 
698             @param _rPageView
699                 provides access to the attributes of the SdrPageView which the control finally belongs to
700 
701             @param _rUnoObject
702                 our SdrUnoObj
703 
704             @param _bIsCurrentlyVisible
705                 determines whether the control is currently visible. Note that this is only a shortcut for
706                 querying _rxControl for the XWindow2 interface, and calling isVisible at this interface.
707                 This shortcut has been chosen since the caller usually already has this information.
708                 If _bForce is <TRUE/>, _bIsCurrentlyVisible is ignored.
709 
710             @param _bForce
711                 set to <TRUE/> if you want to force a ->XWindow::setVisible call,
712                 no matter if the control visibility is already correct
713 
714             @precond
715                 We're not disposed.
716         */
717         static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
718             IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
719 
720         /** starts or stops listening at various aspects of our control
721 
722             @precond
723                 ->m_aControl is not <NULL/>
724         */
725         void impl_switchControlListening_nothrow( bool _bStart );
726 
727         /** starts or stops listening at our control container
728 
729             @precond
730                 ->m_xContainer is not <NULL/>
731         */
732         void impl_switchContainerListening_nothrow( bool _bStart );
733 
734         /** starts or stops listening at the control for design-mode relevant facets
735         */
736         void impl_switchDesignModeListening_nothrow( bool _bStart );
737 
738         /** starts or stops listening for all properties at our control
739 
740             @param _bStart
741                 determines whether to start or to stop listening
742 
743             @precond
744                 ->m_aControl is not <NULL/>
745         */
746         void impl_switchPropertyListening_nothrow( bool _bStart );
747 
748         /** disposes the instance
749             @param _bAlsoDisposeControl
750                 determines whether the XControl should be disposed, too
751         */
752         void impl_dispose_nothrow( bool _bAlsoDisposeControl );
753 
754         /** determines whether the instance is disposed
755             @nofail
756         */
impl_isDisposed_nofail() const757         bool    impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
758 
759         /** determines whether the control currently is in design mode
760 
761             @precond
762                 The design mode must already be known. It is known when we first had access to
763                 an SdrPageView (which carries this flag), or somebody explicitly set it from
764                 outside.
765         */
impl_isControlDesignMode_nothrow() const766         bool impl_isControlDesignMode_nothrow() const
767         {
768             DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
769             return m_eControlDesignMode == eDesign;
770         }
771 
772         /** ensures that we have a control for the given PageView/OutputDevice
773         */
774         bool impl_ensureControl_nothrow(
775                 IPageViewAccess const & _rPageView,
776                 const OutputDevice& _rDevice,
777                 const basegfx::B2DHomMatrix& _rInitialViewTransformation
778              );
779 
780         const OutputDevice& impl_getOutputDevice_throw() const;
781     };
782 
783     namespace {
784 
785     class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
786     {
787     private:
788         typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D  BufferedDecompositionPrimitive2D;
789 
790     protected:
791         virtual void
792             get2DDecomposition(
793                 ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor,
794                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
795             ) const override;
796 
797         virtual void create2DDecomposition(
798                 ::drawinglayer::primitive2d::Primitive2DContainer& rContainer,
799                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
800             ) const override;
801 
802         virtual ::basegfx::B2DRange
803             getB2DRange(
804                 const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
805             ) const override;
806 
807     public:
LazyControlCreationPrimitive2D(const::rtl::Reference<ViewObjectContactOfUnoControl_Impl> & _pVOCImpl)808         explicit LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
809             :m_pVOCImpl( _pVOCImpl )
810         {
811             ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
812             getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
813         }
814 
815         virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
816 
817         // declare unique ID for this primitive class
818         virtual sal_uInt32 getPrimitive2DID() const override;
819 
820         static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
821 
822     private:
impl_positionAndZoomControl(const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const823         void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
824         {
825             if ( !_rViewInformation.getViewport().isEmpty() )
826                 m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
827         }
828 
829     private:
830         ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >  m_pVOCImpl;
831         /** The geometry is part of the identity of a primitive, so we cannot calculate it on demand
832             (since the data the calculation is based on might have changed then), but need to calc
833             it at construction time, and remember it.
834         */
835         ::basegfx::B2DHomMatrix                                 m_aTransformation;
836     };
837 
838     }
839 
ViewObjectContactOfUnoControl_Impl(ViewObjectContactOfUnoControl * _pAntiImpl)840     ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl )
841         :m_pAntiImpl( _pAntiImpl )
842         ,m_bCreatingControl( false )
843         ,m_pOutputDeviceForWindow( nullptr )
844         ,m_bControlIsVisible( false )
845         ,m_bIsDesignModeListening( false )
846         ,m_eControlDesignMode( eUnknown )
847         ,m_aZoomLevelNormalization()
848     {
849         DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
850 
851         const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
852         m_aZoomLevelNormalization = rPageViewDevice.GetInverseViewTransformation();
853 
854     #if OSL_DEBUG_LEVEL > 0
855         ::basegfx::B2DVector aScale, aTranslate;
856         double fRotate, fShearX;
857         m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
858     #endif
859 
860         ::basegfx::B2DHomMatrix aScaleNormalization;
861         const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
862         aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
863         aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
864         m_aZoomLevelNormalization *= aScaleNormalization;
865 
866     #if OSL_DEBUG_LEVEL > 0
867         m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
868     #endif
869    }
870 
871 
~ViewObjectContactOfUnoControl_Impl()872     ViewObjectContactOfUnoControl_Impl::~ViewObjectContactOfUnoControl_Impl()
873     {
874         if ( !impl_isDisposed_nofail() )
875         {
876             acquire();
877             dispose();
878         }
879 
880     }
881 
882 
impl_dispose_nothrow(bool _bAlsoDisposeControl)883     void ViewObjectContactOfUnoControl_Impl::impl_dispose_nothrow( bool _bAlsoDisposeControl )
884     {
885         if ( impl_isDisposed_nofail() )
886             return;
887 
888         if ( m_aControl.is() )
889             impl_switchControlListening_nothrow( false );
890 
891         if ( m_xContainer.is() )
892             impl_switchContainerListening_nothrow( false );
893 
894         // dispose the control
895         if ( _bAlsoDisposeControl )
896             UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
897 
898         m_aControl.clear();
899         m_xContainer.clear();
900         m_pOutputDeviceForWindow = nullptr;
901         m_bControlIsVisible = false;
902 
903         m_pAntiImpl = nullptr;
904     }
905 
906 
dispose()907     void ViewObjectContactOfUnoControl_Impl::dispose()
908     {
909         SolarMutexGuard aSolarGuard;
910         impl_dispose_nothrow( true );
911     }
912 
913 
getUnoObject(SdrUnoObj * & _out_rpObject) const914     bool ViewObjectContactOfUnoControl_Impl::getUnoObject( SdrUnoObj*& _out_rpObject ) const
915     {
916         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
917         if ( impl_isDisposed_nofail() )
918             _out_rpObject = nullptr;
919         else
920         {
921             _out_rpObject = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
922             DBG_ASSERT( _out_rpObject || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
923                 "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
924         }
925         return ( _out_rpObject != nullptr );
926     }
927 
928 
positionAndZoomControl(const basegfx::B2DHomMatrix & _rViewTransformation) const929     void ViewObjectContactOfUnoControl_Impl::positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const
930     {
931         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
932         if ( !m_aControl.is() )
933             return;
934 
935         try
936         {
937             SdrUnoObj* pUnoObject( nullptr );
938             if ( getUnoObject( pUnoObject ) )
939             {
940                 const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
941                 UnoControlContactHelper::adjustControlGeometry_throw( m_aControl, aRect, _rViewTransformation, m_aZoomLevelNormalization );
942             }
943             else
944                 OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
945         }
946         catch( const Exception& )
947         {
948             DBG_UNHANDLED_EXCEPTION("svx");
949         }
950     }
951 
952 
ensureControl(const basegfx::B2DHomMatrix * _pInitialViewTransformationOrNULL)953     void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
954     {
955         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
956         if ( impl_isDisposed_nofail() )
957             return;
958 
959         ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
960         if ( pPageViewContact )
961         {
962             SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
963             const OutputDevice& rDevice( *m_pAntiImpl->getPageViewOutputDevice() );
964             impl_ensureControl_nothrow(
965                 aPVAccess,
966                 rDevice,
967                 _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
968             );
969             return;
970         }
971 
972         DummyPageViewAccess aNoPageView;
973         const OutputDevice& rDevice( impl_getOutputDevice_throw() );
974         impl_ensureControl_nothrow(
975             aNoPageView,
976             rDevice,
977             _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
978         );
979     }
980 
981 
impl_getOutputDevice_throw() const982     const OutputDevice& ViewObjectContactOfUnoControl_Impl::impl_getOutputDevice_throw() const
983     {
984         // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
985         // OriginalPaintWindow
986         const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
987         if( oPageOutputDev )
988             return *oPageOutputDev;
989 
990         const OutputDevice* pDevice = m_pAntiImpl->GetObjectContact().TryToGetOutputDevice();
991         ENSURE_OR_THROW( pDevice, "no output device -> no control" );
992         return *pDevice;
993     }
994 
995 
996     namespace
997     {
lcl_resetFlag(bool & rbFlag)998         void lcl_resetFlag( bool& rbFlag )
999         {
1000             rbFlag = false;
1001         }
1002     }
1003 
1004 
impl_ensureControl_nothrow(IPageViewAccess const & _rPageView,const OutputDevice & _rDevice,const basegfx::B2DHomMatrix & _rInitialViewTransformation)1005     bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
1006         const basegfx::B2DHomMatrix& _rInitialViewTransformation )
1007     {
1008         if ( m_bCreatingControl )
1009         {
1010             OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
1011             // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
1012             // those affected the grid control, which is the only control so far which is visible in design mode (and
1013             // not only in alive mode).
1014             // Creating the control triggered a Window::Update on some of its child windows, which triggered a
1015             // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
1016             // which it is not really prepared for.
1017 
1018             // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
1019             // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
1020             return false;
1021         }
1022 
1023         m_bCreatingControl = true;
1024         ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
1025 
1026         if ( m_aControl.is() )
1027         {
1028             if ( m_pOutputDeviceForWindow.get() == &_rDevice )
1029                 return true;
1030 
1031             // Somebody requested a control for a new device, which means either of
1032             // - our PageView's paint window changed since we were last here
1033             // - we don't belong to a page view, and are simply painted onto different devices
1034             // The first sounds strange (doesn't it?), the second means we could perhaps
1035             // optimize this in the future - there is no need to re-create the control every time,
1036             // is it? #i74523#
1037             if ( m_xContainer.is() )
1038                 impl_switchContainerListening_nothrow( false );
1039             impl_switchControlListening_nothrow( false );
1040             UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
1041         }
1042 
1043         SdrUnoObj* pUnoObject( nullptr );
1044         if ( !getUnoObject( pUnoObject ) )
1045             return false;
1046 
1047         ControlHolder aControl;
1048         if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
1049             return false;
1050 
1051         m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
1052         m_aControl = aControl;
1053         m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
1054         DBG_ASSERT( (   m_xContainer.is()                                           // either have a XControlContainer
1055                     ||  (   ( !_rPageView.getControlContainer( _rDevice ).is() )    // or don't have any container,
1056                         &&  ( _rDevice.GetOwnerWindow() == nullptr )  // which is allowed for non-Window instances only
1057                         )
1058                     ),
1059             "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
1060 
1061         try
1062         {
1063             m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
1064             m_bControlIsVisible = m_aControl.isVisible();
1065         }
1066         catch( const Exception& )
1067         {
1068             DBG_UNHANDLED_EXCEPTION("svx");
1069         }
1070 
1071         // start listening at all aspects of the control which are interesting to us ...
1072         impl_switchControlListening_nothrow( true );
1073 
1074         // start listening at the control container, in case somebody tampers with our control
1075         if ( m_xContainer.is() )
1076             impl_switchContainerListening_nothrow( true );
1077 
1078         return m_aControl.is();
1079     }
1080 
1081 
createControlForDevice(IPageViewAccess const & _rPageView,const OutputDevice & _rDevice,const SdrUnoObj & _rUnoObject,const basegfx::B2DHomMatrix & _rInitialViewTransformation,const basegfx::B2DHomMatrix & _rInitialZoomNormalization,ControlHolder & _out_rControl)1082     bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
1083         const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
1084         const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
1085     {
1086         _out_rControl.clear();
1087 
1088         const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
1089         DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
1090         if ( !xControlModel.is() )
1091             return false;
1092 
1093         bool bSuccess = false;
1094         try
1095         {
1096             const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
1097 
1098             Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1099             _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
1100 
1101             // knit the model and the control
1102             _out_rControl.setModel( xControlModel );
1103             const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
1104 
1105             // proper geometry
1106             UnoControlContactHelper::adjustControlGeometry_throw(
1107                 _out_rControl,
1108                 aRect,
1109                 _rInitialViewTransformation,
1110                 _rInitialZoomNormalization
1111             );
1112 
1113             // set design mode before peer is created,
1114             // this is also needed for accessibility
1115             _out_rControl.setDesignMode( _rPageView.isDesignMode() );
1116 
1117             // adjust the initial visibility according to the visibility of the layer
1118             impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
1119 
1120             // add the control to the respective control container
1121             // do this last
1122             Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
1123             if ( xControlContainer.is() )
1124                 xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
1125 
1126             bSuccess = true;
1127         }
1128         catch( const Exception& )
1129         {
1130             DBG_UNHANDLED_EXCEPTION("svx");
1131         }
1132 
1133         if ( !bSuccess )
1134         {
1135             // delete the control which might have been created already
1136             UnoControlContactHelper::disposeAndClearControl_nothrow( _out_rControl );
1137         }
1138 
1139         return _out_rControl.is();
1140     }
1141 
1142 
impl_getPageView_nothrow(SdrPageView * & _out_rpPageView)1143     bool ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow( SdrPageView*& _out_rpPageView )
1144     {
1145         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
1146 
1147         _out_rpPageView = nullptr;
1148         if ( impl_isDisposed_nofail() )
1149             return false;
1150 
1151         ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
1152         if ( pPageViewContact )
1153             _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
1154 
1155         DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
1156         return ( _out_rpPageView != nullptr );
1157     }
1158 
1159 
impl_adjustControlVisibilityToLayerVisibility_throw()1160     void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw()
1161     {
1162         OSL_PRECOND( m_aControl.is(),
1163             "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
1164 
1165         SdrPageView* pPageView( nullptr );
1166         if ( !impl_getPageView_nothrow( pPageView ) )
1167             return;
1168 
1169         SdrUnoObj* pUnoObject( nullptr );
1170         if ( !getUnoObject( pUnoObject ) )
1171             return;
1172 
1173         SdrPageViewAccess aPVAccess( *pPageView );
1174         impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
1175     }
1176 
1177 
impl_adjustControlVisibilityToLayerVisibility_throw(const ControlHolder & _rControl,const SdrUnoObj & _rUnoObject,IPageViewAccess const & _rPageView,bool _bIsCurrentlyVisible,bool _bForce)1178     void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rControl,
1179         const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
1180     {
1181         // in design mode, there is no problem with the visibility: The XControl is hidden by
1182         // default, and the Drawing Layer will simply not call our paint routine, if we're in
1183         // a hidden layer. So, only alive mode matters.
1184         if ( !_rControl.isDesignMode() )
1185         {
1186             // the layer of our object
1187             SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
1188             // is the object we're residing in visible in this view?
1189             bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
1190 
1191             if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
1192             {
1193                 _rControl.setVisible( bIsObjectVisible );
1194             }
1195         }
1196     }
1197 
1198 
impl_switchContainerListening_nothrow(bool _bStart)1199     void ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow( bool _bStart )
1200     {
1201         OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
1202         if ( !m_xContainer.is() )
1203             return;
1204 
1205         try
1206         {
1207             if ( _bStart )
1208                 m_xContainer->addContainerListener( this );
1209             else
1210                 m_xContainer->removeContainerListener( this );
1211         }
1212         catch( const Exception& )
1213         {
1214             DBG_UNHANDLED_EXCEPTION("svx");
1215         }
1216     }
1217 
1218 
impl_switchControlListening_nothrow(bool _bStart)1219     void ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow( bool _bStart )
1220     {
1221         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
1222         if ( !m_aControl.is() )
1223             return;
1224 
1225         try
1226         {
1227             // listen for visibility changes
1228             if ( _bStart )
1229                 m_aControl.addWindowListener( this );
1230             else
1231                 m_aControl.removeWindowListener( this );
1232 
1233             // in design mode, listen for some more aspects
1234             impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() && _bStart );
1235 
1236             // listen for design mode changes
1237             Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
1238             if ( _bStart )
1239                 xDesignModeChanges->addModeChangeListener( this );
1240             else
1241                 xDesignModeChanges->removeModeChangeListener( this );
1242         }
1243         catch( const Exception& )
1244         {
1245             DBG_UNHANDLED_EXCEPTION("svx");
1246         }
1247     }
1248 
1249 
impl_switchDesignModeListening_nothrow(bool _bStart)1250     void ViewObjectContactOfUnoControl_Impl::impl_switchDesignModeListening_nothrow( bool _bStart )
1251     {
1252         if ( m_bIsDesignModeListening != _bStart )
1253         {
1254             m_bIsDesignModeListening = _bStart;
1255             impl_switchPropertyListening_nothrow( _bStart );
1256         }
1257     }
1258 
1259 
impl_switchPropertyListening_nothrow(bool _bStart)1260     void ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow( bool _bStart )
1261     {
1262         OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
1263         if ( !m_aControl.is() )
1264             return;
1265 
1266         try
1267         {
1268             Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
1269             if ( _bStart )
1270                 xModelProperties->addPropertyChangeListener( OUString(), this );
1271             else
1272                 xModelProperties->removePropertyChangeListener( OUString(), this );
1273         }
1274         catch( const Exception& )
1275         {
1276             DBG_UNHANDLED_EXCEPTION("svx");
1277         }
1278     }
1279 
1280 
isPrintableControl() const1281     bool ViewObjectContactOfUnoControl_Impl::isPrintableControl() const
1282     {
1283         SdrUnoObj* pUnoObject( nullptr );
1284         if ( !getUnoObject( pUnoObject ) )
1285             return false;
1286 
1287         bool bIsPrintable = false;
1288         try
1289         {
1290             Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
1291             OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
1292         }
1293         catch( const Exception& )
1294         {
1295             DBG_UNHANDLED_EXCEPTION("svx");
1296         }
1297         return bIsPrintable;
1298     }
1299 
1300 
disposing(const EventObject & Source)1301     void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
1302     {
1303         SolarMutexGuard aSolarGuard;
1304             // some code below - in particular our disposal - might trigger actions which require the
1305             // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1306             // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1307             // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1308 
1309         if ( !m_aControl.is() )
1310             return;
1311 
1312         if  (   ( m_aControl            == Source.Source )
1313             ||  ( m_aControl.getModel() == Source.Source )
1314             )
1315         {
1316             // the model or the control is dying ... hmm, not much sense in that we ourself continue
1317             // living
1318             impl_dispose_nothrow( false );
1319             return;
1320         }
1321 
1322         DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
1323     }
1324 
1325 
windowResized(const WindowEvent &)1326     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
1327     {
1328         // not interested in
1329     }
1330 
1331 
windowMoved(const WindowEvent &)1332     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
1333     {
1334         // not interested in
1335     }
1336 
1337 
windowShown(const EventObject &)1338     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
1339     {
1340         SolarMutexGuard aSolarGuard;
1341         m_bControlIsVisible = true;
1342     }
1343 
1344 
windowHidden(const EventObject &)1345     void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
1346     {
1347         SolarMutexGuard aSolarGuard;
1348         m_bControlIsVisible = false;
1349     }
1350 
1351 
propertyChange(const PropertyChangeEvent &)1352     void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
1353     {
1354         SolarMutexGuard aSolarGuard;
1355             // (re)painting might require VCL operations, which need the SolarMutex
1356 
1357         OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
1358         if ( impl_isDisposed_nofail() )
1359             return;
1360 
1361         DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
1362         if ( !m_aControl.is() )
1363             return;
1364 
1365         // a generic property changed. If we're in design mode, we need to repaint the control
1366         if ( impl_isControlDesignMode_nothrow() )
1367         {
1368             m_pAntiImpl->propertyChange();
1369         }
1370     }
1371 
1372 
modeChanged(const ModeChangeEvent & _rSource)1373     void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
1374     {
1375         SolarMutexGuard aSolarGuard;
1376 
1377         DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
1378 
1379         m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
1380 
1381         impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() );
1382 
1383         try
1384         {
1385             // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
1386             impl_adjustControlVisibilityToLayerVisibility_throw();
1387         }
1388         catch( const Exception& )
1389         {
1390             DBG_UNHANDLED_EXCEPTION("svx");
1391         }
1392     }
1393 
1394 
elementInserted(const ContainerEvent &)1395     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
1396     {
1397         // not interested in
1398     }
1399 
1400 
elementRemoved(const ContainerEvent & Event)1401     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
1402     {
1403         SolarMutexGuard aSolarGuard;
1404             // some code below - in particular our disposal - might trigger actions which require the
1405             // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
1406             // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
1407             // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
1408         DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
1409 
1410         if ( m_aControl == Event.Element )
1411             impl_dispose_nothrow( false );
1412     }
1413 
1414 
elementReplaced(const ContainerEvent & Event)1415     void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
1416     {
1417         SolarMutexGuard aSolarGuard;
1418         DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
1419 
1420         if ( ! ( m_aControl == Event.ReplacedElement ) )
1421             return;
1422 
1423         Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
1424         DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
1425         if ( !xNewControl.is() )
1426             return;
1427 
1428         ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
1429 
1430         DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
1431         // another model should - in the drawing layer - also imply another SdrUnoObj, which
1432         // should also result in new ViewContact, and thus in new ViewObjectContacts
1433 
1434         impl_switchControlListening_nothrow( false );
1435 
1436         ControlHolder aNewControl( xNewControl );
1437         aNewControl.setZoom( m_aControl.getZoom() );
1438         aNewControl.setPosSize( m_aControl.getPosSize() );
1439         aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
1440 
1441         m_aControl = xNewControl;
1442         m_bControlIsVisible = m_aControl.isVisible();
1443 
1444         impl_switchControlListening_nothrow( true );
1445 
1446         m_pAntiImpl->onControlChangedOrModified( ViewObjectContactOfUnoControl::ImplAccess() );
1447     }
1448 
1449 
setControlDesignMode(bool _bDesignMode) const1450     void ViewObjectContactOfUnoControl_Impl::setControlDesignMode( bool _bDesignMode ) const
1451     {
1452         if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
1453             // nothing to do
1454             return;
1455         m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
1456 
1457         if ( !m_aControl.is() )
1458             // nothing to do, the setting will be respected as soon as the control
1459             // is created
1460             return;
1461 
1462         try
1463         {
1464             m_aControl.setDesignMode( _bDesignMode );
1465         }
1466         catch( const Exception& )
1467         {
1468             DBG_UNHANDLED_EXCEPTION("svx");
1469         }
1470     }
1471 
1472 
1473     //= LazyControlCreationPrimitive2D
1474 
1475 
operator ==(const BasePrimitive2D & rPrimitive) const1476     bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1477     {
1478         if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
1479             return false;
1480 
1481         const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
1482         if ( !pRHS )
1483             return false;
1484 
1485         if ( m_pVOCImpl != pRHS->m_pVOCImpl )
1486             return false;
1487 
1488         if ( m_aTransformation != pRHS->m_aTransformation )
1489             return false;
1490 
1491         return true;
1492     }
1493 
1494 
getTransformation(const ViewContactOfUnoControl & _rVOC,::basegfx::B2DHomMatrix & _out_Transformation)1495     void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
1496     {
1497         // Do use model data directly to create the correct geometry. Do NOT
1498         // use getBoundRect()/getSnapRect() here; these will use the sequence of
1499         // primitives themselves in the long run.
1500         const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
1501         const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aSdrGeoData);
1502 
1503         _out_Transformation.identity();
1504         _out_Transformation.set( 0, 0, aRange.getWidth() );
1505         _out_Transformation.set( 1, 1, aRange.getHeight() );
1506         _out_Transformation.set( 0, 2, aRange.getMinX() );
1507         _out_Transformation.set( 1, 2, aRange.getMinY() );
1508     }
1509 
1510 
getB2DRange(const::drawinglayer::geometry::ViewInformation2D &) const1511     ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
1512     {
1513         ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
1514         aRange.transform( m_aTransformation );
1515         return aRange;
1516     }
1517 
1518 
get2DDecomposition(::drawinglayer::primitive2d::Primitive2DDecompositionVisitor & rVisitor,const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const1519     void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1520     {
1521     #if OSL_DEBUG_LEVEL > 0
1522         ::basegfx::B2DVector aScale, aTranslate;
1523         double fRotate, fShearX;
1524         _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1525     #endif
1526         if ( m_pVOCImpl->hasControl() )
1527             impl_positionAndZoomControl( _rViewInformation );
1528         BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
1529     }
1530 
1531 
create2DDecomposition(::drawinglayer::primitive2d::Primitive2DContainer & rContainer,const::drawinglayer::geometry::ViewInformation2D & _rViewInformation) const1532     void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
1533     {
1534     #if OSL_DEBUG_LEVEL > 0
1535         ::basegfx::B2DVector aScale, aTranslate;
1536         double fRotate, fShearX;
1537         _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1538     #endif
1539         const bool bHadControl = m_pVOCImpl->getExistentControl().is();
1540 
1541         // force control here to make it a VCL ChildWindow. Will be fetched
1542         // and used below by getExistentControl()
1543         m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
1544         impl_positionAndZoomControl( _rViewInformation );
1545 
1546         // get needed data
1547         const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
1548         Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
1549         const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
1550 
1551         if ( !bHadControl && rControl.is() && rControl.isVisible() )
1552             rControl.invalidate();
1553 
1554         // check if we already have an XControl.
1555         if ( !xControlModel.is() || !rControl.is() )
1556         {
1557             // use the default mechanism. This will create a ControlPrimitive2D without
1558             // handing over a XControl. If not even a XControlModel exists, it will
1559             // create the SdrObject fallback visualisation
1560             const drawinglayer::primitive2d::Primitive2DContainer& aTmp = rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer();
1561             rContainer.insert(rContainer.end(), aTmp.begin(), aTmp.end());
1562             return;
1563         }
1564 
1565         // create a primitive and hand over the existing xControl. This will
1566         // allow the primitive to not need to create another one on demand.
1567         rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
1568             m_aTransformation, xControlModel, rControl.getControl() ) );
1569     }
1570 
1571 
ImplPrimitive2DIDBlock(LazyControlCreationPrimitive2D,PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D)1572     ImplPrimitive2DIDBlock( LazyControlCreationPrimitive2D, PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D )
1573 
1574     ViewObjectContactOfUnoControl::ViewObjectContactOfUnoControl( ObjectContact& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
1575         :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
1576         ,m_pImpl( new ViewObjectContactOfUnoControl_Impl( this ) )
1577     {
1578     }
1579 
1580 
~ViewObjectContactOfUnoControl()1581     ViewObjectContactOfUnoControl::~ViewObjectContactOfUnoControl()
1582     {
1583         m_pImpl->dispose();
1584         m_pImpl = nullptr;
1585 
1586     }
1587 
1588 
getControl()1589     Reference< XControl > ViewObjectContactOfUnoControl::getControl()
1590     {
1591         SolarMutexGuard aSolarGuard;
1592         m_pImpl->ensureControl( nullptr );
1593         return m_pImpl->getExistentControl().getControl();
1594     }
1595 
1596 
getTemporaryControlForWindow(const vcl::Window & _rWindow,Reference<XControlContainer> & _inout_ControlContainer,const SdrUnoObj & _rUnoObject)1597     Reference< XControl > ViewObjectContactOfUnoControl::getTemporaryControlForWindow(
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 
ensureControlVisibility(bool _bVisible) const1609     void ViewObjectContactOfUnoControl::ensureControlVisibility( bool _bVisible ) const
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         {
1635             DBG_UNHANDLED_EXCEPTION("svx");
1636         }
1637     }
1638 
1639 
setControlDesignMode(bool _bDesignMode) const1640     void ViewObjectContactOfUnoControl::setControlDesignMode( bool _bDesignMode ) const
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 
createPrimitive2DSequence(const DisplayInfo &) const1655     drawinglayer::primitive2d::Primitive2DContainer ViewObjectContactOfUnoControl::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/) const
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 drawinglayer::primitive2d::Primitive2DContainer();
1662 
1663         if ( GetObjectContact().getViewInformation2D().getViewTransformation().isIdentity() )
1664             // remove this when #i115754# is fixed
1665             return drawinglayer::primitive2d::Primitive2DContainer();
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 drawinglayer::primitive2d::Primitive2DContainer();
1671 
1672         ::drawinglayer::primitive2d::Primitive2DReference xPrimitive( new LazyControlCreationPrimitive2D( m_pImpl ) );
1673         return ::drawinglayer::primitive2d::Primitive2DContainer { xPrimitive };
1674     }
1675 
1676 
isPrimitiveVisible(const DisplayInfo & _rDisplayInfo) const1677     bool ViewObjectContactOfUnoControl::isPrimitiveVisible( const DisplayInfo& _rDisplayInfo ) const
1678     {
1679         SolarMutexGuard aSolarGuard;
1680 
1681         if ( m_pImpl->hasControl() )
1682         {
1683             const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
1684         #if OSL_DEBUG_LEVEL > 0
1685             ::basegfx::B2DVector aScale, aTranslate;
1686             double fRotate, fShearX;
1687             rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
1688         #endif
1689 
1690             if ( !rViewInformation.getViewport().isEmpty() )
1691             {
1692                 // tdf#121963 check and eventually pre-multiply ViewTransformation
1693                 // with GridOffset transformation to avoid alternating positions of
1694                 // FormControls which are victims of the non-linear calc ViewTransformation
1695                 // aka GridOffset. For other paths (e.g. repaint) this is included already
1696                 // as part of the object's sequence of B2DPrimitive - representation
1697                 // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
1698                 basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
1699 
1700                 if(GetObjectContact().supportsGridOffsets())
1701                 {
1702                     const basegfx::B2DVector& rGridOffset(getGridOffset());
1703 
1704                     if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
1705                     {
1706                         // pre-multiply: GridOffset needs to be applied directly to logic model data
1707                         // of object coordinates, so multiply GridOffset from right to make it
1708                         // work as 1st change - these objects may still be part of groups/hierarchies
1709                         aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
1710                     }
1711                 }
1712 
1713                 m_pImpl->positionAndZoomControl(aViewTransformation);
1714             }
1715         }
1716 
1717         return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
1718     }
1719 
1720 
propertyChange()1721     void ViewObjectContactOfUnoControl::propertyChange()
1722     {
1723         impl_onControlChangedOrModified();
1724     }
1725 
1726 
ActionChanged()1727     void ViewObjectContactOfUnoControl::ActionChanged()
1728     {
1729         // call parent
1730         ViewObjectContactOfSdrObj::ActionChanged();
1731         const ControlHolder& rControl(m_pImpl->getExistentControl());
1732 
1733         if(!rControl.is() || rControl.isDesignMode())
1734             return;
1735 
1736         // #i93180# if layer visibility has changed and control is in live mode, it is necessary
1737         // to correct visibility to make those control vanish on SdrObject LayerID changes
1738         const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
1739 
1740         if(pSdrPageView)
1741         {
1742             const SdrObject& rObject = getSdrObject();
1743             const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
1744 
1745             if(rControl.isVisible() != bIsLayerVisible)
1746             {
1747                 rControl.setVisible(bIsLayerVisible);
1748             }
1749         }
1750     }
1751 
1752 
impl_onControlChangedOrModified()1753     void ViewObjectContactOfUnoControl::impl_onControlChangedOrModified()
1754     {
1755         // graphical invalidate at all views
1756         ActionChanged();
1757 
1758         // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
1759         // since e.g. background color has changed and existing decompositions are possibly no
1760         // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
1761         // since it only has a uno reference to the XControlModel
1762         flushPrimitive2DSequence();
1763     }
1764 
UnoControlPrintOrPreviewContact(ObjectContactOfPageView & _rObjectContact,ViewContactOfUnoControl & _rViewContact)1765     UnoControlPrintOrPreviewContact::UnoControlPrintOrPreviewContact( ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
1766         :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
1767     {
1768     }
1769 
1770 
~UnoControlPrintOrPreviewContact()1771     UnoControlPrintOrPreviewContact::~UnoControlPrintOrPreviewContact()
1772     {
1773     }
1774 
1775 
createPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const1776     drawinglayer::primitive2d::Primitive2DContainer UnoControlPrintOrPreviewContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo ) const
1777     {
1778         if ( !m_pImpl->isPrintableControl() )
1779             return drawinglayer::primitive2d::Primitive2DContainer();
1780         return ViewObjectContactOfUnoControl::createPrimitive2DSequence( rDisplayInfo );
1781     }
1782 
1783 
1784 } // namespace sdr::contact
1785 
1786 
1787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1788