Coverage Report

Created: 2026-02-14 09:37

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