Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/svx/source/svdraw/svdouno.cxx
Line
Count
Source (jump to first uncovered line)
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
#include <sdr/contact/viewcontactofunocontrol.hxx>
21
#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
22
#include <com/sun/star/container/XChild.hpp>
23
#include <com/sun/star/beans/XPropertySet.hpp>
24
#include <com/sun/star/util/XCloneable.hpp>
25
#include <com/sun/star/uno/XComponentContext.hpp>
26
#include <com/sun/star/lang/XEventListener.hpp>
27
#include <cppuhelper/implbase.hxx>
28
#include <comphelper/processfactory.hxx>
29
#include <svx/svdouno.hxx>
30
#include <svx/svdpagv.hxx>
31
#include <svx/svdmodel.hxx>
32
#include <svx/dialmgr.hxx>
33
#include <svx/strings.hrc>
34
#include <svx/svdview.hxx>
35
#include <svx/svdorect.hxx>
36
#include <svx/svdviter.hxx>
37
#include <rtl/ref.hxx>
38
#include <svx/sdrpagewindow.hxx>
39
#include <comphelper/diagnose_ex.hxx>
40
#include <tools/debug.hxx>
41
#include <o3tl/sorted_vector.hxx>
42
43
using namespace ::com::sun::star;
44
using namespace sdr::contact;
45
46
47
class SdrControlEventListenerImpl : public ::cppu::WeakImplHelper< css::lang::XEventListener >
48
{
49
protected:
50
    SdrUnoObj*                  pObj;
51
52
public:
53
    explicit SdrControlEventListenerImpl(SdrUnoObj* _pObj)
54
785
    :   pObj(_pObj)
55
785
    {}
56
57
    // XEventListener
58
    virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
59
60
    void StopListening(const uno::Reference< lang::XComponent >& xComp);
61
    void StartListening(const uno::Reference< lang::XComponent >& xComp);
62
};
63
64
// XEventListener
65
void SAL_CALL SdrControlEventListenerImpl::disposing( const css::lang::EventObject& /*Source*/)
66
0
{
67
0
    if (pObj)
68
0
    {
69
0
        pObj->m_xUnoControlModel = nullptr;
70
0
    }
71
0
}
72
73
void SdrControlEventListenerImpl::StopListening(const uno::Reference< lang::XComponent >& xComp)
74
0
{
75
0
    if (xComp.is())
76
0
        xComp->removeEventListener(this);
77
0
}
78
79
void SdrControlEventListenerImpl::StartListening(const uno::Reference< lang::XComponent >& xComp)
80
0
{
81
0
    if (xComp.is())
82
0
        xComp->addEventListener(this);
83
0
}
84
85
86
struct SdrUnoObjDataHolder
87
{
88
    mutable ::rtl::Reference< SdrControlEventListenerImpl >
89
                                    pEventListener;
90
};
91
92
93
namespace
94
{
95
    void lcl_ensureControlVisibility( SdrView const * _pView, const SdrUnoObj* _pObject, bool _bVisible )
96
0
    {
97
0
        assert(_pObject && "lcl_ensureControlVisibility: no object -> no survival!");
98
99
0
        SdrPageView* pPageView = _pView ? _pView->GetSdrPageView() : nullptr;
100
0
        DBG_ASSERT( pPageView, "lcl_ensureControlVisibility: no view found!" );
101
0
        if ( !pPageView )
102
0
            return;
103
104
0
        ViewContact& rUnoControlContact( _pObject->GetViewContact() );
105
106
0
        for ( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); ++i )
107
0
        {
108
0
            SdrPageWindow* pPageWindow = pPageView->GetPageWindow( i );
109
0
            DBG_ASSERT( pPageWindow, "lcl_ensureControlVisibility: invalid PageViewWindow!" );
110
0
            if ( !pPageWindow )
111
0
                continue;
112
113
0
            if ( !pPageWindow->HasObjectContact() )
114
0
                continue;
115
116
0
            ObjectContact& rPageViewContact( pPageWindow->GetObjectContact() );
117
0
            const ViewObjectContact& rViewObjectContact( rUnoControlContact.GetViewObjectContact( rPageViewContact ) );
118
0
            const ViewObjectContactOfUnoControl* pUnoControlContact = dynamic_cast< const ViewObjectContactOfUnoControl* >( &rViewObjectContact );
119
0
            DBG_ASSERT( pUnoControlContact, "lcl_ensureControlVisibility: wrong ViewObjectContact type!" );
120
0
            if ( !pUnoControlContact )
121
0
                continue;
122
123
0
            pUnoControlContact->ensureControlVisibility( _bVisible );
124
0
        }
125
0
    }
126
}
127
128
SdrUnoObj::SdrUnoObj(
129
    SdrModel& rSdrModel,
130
    const OUString& rModelName)
131
785
:   SdrRectObj(rSdrModel),
132
785
    m_pImpl( new SdrUnoObjDataHolder )
133
785
{
134
785
    osl_atomic_increment(&m_refCount); // prevent deletion during creation
135
785
    m_bIsUnoObj = true;
136
137
785
    m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
138
139
    // only an owner may create independently
140
785
    if (!rModelName.isEmpty())
141
0
        CreateUnoControlModel(rModelName);
142
785
    osl_atomic_decrement(&m_refCount);
143
785
}
144
145
SdrUnoObj::SdrUnoObj( SdrModel& rSdrModel, SdrUnoObj const & rSource)
146
0
:   SdrRectObj(rSdrModel, rSource),
147
0
    m_pImpl( new SdrUnoObjDataHolder )
148
0
{
149
0
    m_bIsUnoObj = true;
150
151
0
    m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
152
153
0
    m_aUnoControlModelTypeName = rSource.m_aUnoControlModelTypeName;
154
0
    m_aUnoControlTypeName = rSource.m_aUnoControlTypeName;
155
156
    // copy the uno control model
157
0
    const uno::Reference< awt::XControlModel >& xSourceControlModel = rSource.GetUnoControlModel();
158
0
    if ( xSourceControlModel.is() )
159
0
    {
160
0
        try
161
0
        {
162
0
            uno::Reference< util::XCloneable > xClone( xSourceControlModel, uno::UNO_QUERY_THROW );
163
0
            m_xUnoControlModel.set( xClone->createClone(), uno::UNO_QUERY_THROW );
164
0
        }
165
0
        catch( const uno::Exception& )
166
0
        {
167
0
            DBG_UNHANDLED_EXCEPTION("svx");
168
0
        }
169
0
    }
170
171
    // get service name of the control from the control model
172
0
    uno::Reference< beans::XPropertySet > xSet(m_xUnoControlModel, uno::UNO_QUERY);
173
0
    if (xSet.is())
174
0
    {
175
0
        uno::Any aValue( xSet->getPropertyValue(u"DefaultControl"_ustr) );
176
0
        OUString aStr;
177
178
0
        if( aValue >>= aStr )
179
0
            m_aUnoControlTypeName = aStr;
180
0
    }
181
182
0
    uno::Reference< lang::XComponent > xComp(m_xUnoControlModel, uno::UNO_QUERY);
183
0
    if (xComp.is())
184
0
        m_pImpl->pEventListener->StartListening(xComp);
185
0
}
186
187
SdrUnoObj::SdrUnoObj(
188
    SdrModel& rSdrModel,
189
    const OUString& rModelName,
190
    const uno::Reference< lang::XMultiServiceFactory >& rxSFac)
191
0
:   SdrRectObj(rSdrModel),
192
0
    m_pImpl( new SdrUnoObjDataHolder )
193
0
{
194
0
    m_bIsUnoObj = true;
195
196
0
    m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
197
198
    // only an owner may create independently
199
0
    if (!rModelName.isEmpty())
200
0
        CreateUnoControlModel(rModelName,rxSFac);
201
0
}
202
203
SdrUnoObj::~SdrUnoObj()
204
785
{
205
785
    try
206
785
    {
207
        // clean up the control model
208
785
        uno::Reference< lang::XComponent > xComp(m_xUnoControlModel, uno::UNO_QUERY);
209
785
        if (xComp.is())
210
0
        {
211
            // is the control model owned by its environment?
212
0
            uno::Reference< container::XChild > xContent(m_xUnoControlModel, uno::UNO_QUERY);
213
0
            if (xContent.is() && !xContent->getParent().is())
214
0
                xComp->dispose();
215
0
            else
216
0
                m_pImpl->pEventListener->StopListening(xComp);
217
0
        }
218
785
    }
219
785
    catch( const uno::Exception& )
220
785
    {
221
0
        TOOLS_WARN_EXCEPTION( "svx", "SdrUnoObj::~SdrUnoObj" );
222
0
    }
223
785
}
224
225
void SdrUnoObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
226
0
{
227
0
    rInfo.bRotateFreeAllowed        =   false;
228
0
    rInfo.bRotate90Allowed          =   false;
229
0
    rInfo.bMirrorFreeAllowed        =   false;
230
0
    rInfo.bMirror45Allowed          =   false;
231
0
    rInfo.bMirror90Allowed          =   false;
232
0
    rInfo.bTransparenceAllowed = false;
233
0
    rInfo.bShearAllowed             =   false;
234
0
    rInfo.bEdgeRadiusAllowed        =   false;
235
0
    rInfo.bNoOrthoDesired           =   false;
236
0
    rInfo.bCanConvToPath            =   false;
237
0
    rInfo.bCanConvToPoly            =   false;
238
0
    rInfo.bCanConvToPathLineToArea  =   false;
239
0
    rInfo.bCanConvToPolyLineToArea  =   false;
240
0
    rInfo.bCanConvToContour = false;
241
0
}
242
243
SdrObjKind SdrUnoObj::GetObjIdentifier() const
244
0
{
245
0
    return SdrObjKind::UNO;
246
0
}
247
248
void SdrUnoObj::SetContextWritingMode( const sal_Int16 _nContextWritingMode )
249
0
{
250
0
    try
251
0
    {
252
0
        uno::Reference< beans::XPropertySet > xModelProperties( GetUnoControlModel(), uno::UNO_QUERY_THROW );
253
0
        xModelProperties->setPropertyValue( u"ContextWritingMode"_ustr, uno::Any( _nContextWritingMode ) );
254
0
    }
255
0
    catch( const uno::Exception& )
256
0
    {
257
0
        DBG_UNHANDLED_EXCEPTION("svx");
258
0
    }
259
0
}
260
261
OUString SdrUnoObj::TakeObjNameSingul() const
262
0
{
263
0
    OUString sName(SvxResId(STR_ObjNameSingulUno));
264
265
0
    OUString aName(GetName());
266
0
    if (!aName.isEmpty())
267
0
        sName += " '" + aName + "'";
268
269
0
    return sName;
270
0
}
271
272
OUString SdrUnoObj::TakeObjNamePlural() const
273
0
{
274
0
    return SvxResId(STR_ObjNamePluralUno);
275
0
}
276
277
rtl::Reference<SdrObject> SdrUnoObj::CloneSdrObject(SdrModel& rTargetModel) const
278
0
{
279
0
    return new SdrUnoObj(rTargetModel, *this);
280
0
}
281
282
void SdrUnoObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
283
0
{
284
0
    SdrRectObj::NbcResize(rRef,xFact,yFact);
285
286
0
    if (maGeo.m_nShearAngle==0_deg100 && maGeo.m_nRotationAngle==0_deg100)
287
0
        return;
288
289
    // small correctors
290
0
    if (maGeo.m_nRotationAngle>=9000_deg100 && maGeo.m_nRotationAngle<27000_deg100)
291
0
    {
292
0
        moveRectangle(getRectangle().Left() - getRectangle().Right(), getRectangle().Top() - getRectangle().Bottom());
293
0
    }
294
295
0
    maGeo.m_nRotationAngle  = 0_deg100;
296
0
    maGeo.m_nShearAngle = 0_deg100;
297
0
    maGeo.mfSinRotationAngle       = 0.0;
298
0
    maGeo.mfCosRotationAngle       = 1.0;
299
0
    maGeo.mfTanShearAngle       = 0.0;
300
0
    SetBoundAndSnapRectsDirty();
301
0
}
302
303
304
bool SdrUnoObj::hasSpecialDrag() const
305
0
{
306
    // no special drag; we have no rounding rect and
307
    // do want frame handles
308
0
    return false;
309
0
}
310
311
void SdrUnoObj::NbcSetLayer( SdrLayerID _nLayer )
312
0
{
313
0
    if ( GetLayer() == _nLayer )
314
0
    {   // redundant call -> not interested in doing anything here
315
0
        SdrRectObj::NbcSetLayer( _nLayer );
316
0
        return;
317
0
    }
318
319
    // we need some special handling here in case we're moved from an invisible layer
320
    // to a visible one, or vice versa
321
    // (relative to a layer. Remember that the visibility of a layer is a view attribute
322
    // - the same layer can be visible in one view, and invisible in another view, at the
323
    // same time)
324
325
    // collect all views in which our old layer is visible
326
0
    o3tl::sorted_vector< SdrView* > aPreviouslyVisible;
327
328
0
    {
329
0
        SdrViewIter::ForAllViews(this,
330
0
            [&aPreviouslyVisible] (SdrView* pView)
331
0
            {
332
0
                aPreviouslyVisible.insert( pView );
333
0
                return false;
334
0
            });
335
0
    }
336
337
0
    SdrRectObj::NbcSetLayer( _nLayer );
338
339
    // collect all views in which our new layer is visible
340
0
    o3tl::sorted_vector< SdrView* > aNewlyVisible;
341
342
0
    SdrViewIter::ForAllViews( this,
343
0
        [&aPreviouslyVisible, &aNewlyVisible] (SdrView* pView)
344
0
        {
345
0
            if ( aPreviouslyVisible.erase(pView) == 0 )
346
0
            {
347
                // in pView, we were visible _before_ the layer change, and are
348
                // _not_ visible after the layer change
349
                // => remember this view, as our visibility there changed
350
0
                aNewlyVisible.insert( pView );
351
0
            }
352
0
        });
353
354
    // now aPreviouslyVisible contains all views where we became invisible
355
0
    for (const auto& rpView : aPreviouslyVisible)
356
0
    {
357
0
        lcl_ensureControlVisibility( rpView, this, false );
358
0
    }
359
360
    // and aNewlyVisible all views where we became visible
361
0
    for (const auto& rpView : aNewlyVisible)
362
0
    {
363
0
        lcl_ensureControlVisibility( rpView, this, true );
364
0
    }
365
0
}
366
367
void SdrUnoObj::CreateUnoControlModel(const OUString& rModelName)
368
0
{
369
0
    DBG_ASSERT(!m_xUnoControlModel.is(), "model already exists");
370
371
0
    m_aUnoControlModelTypeName = rModelName;
372
373
0
    uno::Reference< awt::XControlModel >   xModel;
374
0
    const uno::Reference< uno::XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
375
0
    if (!m_aUnoControlModelTypeName.isEmpty() )
376
0
    {
377
0
        xModel.set(xContext->getServiceManager()->createInstanceWithContext(
378
0
            m_aUnoControlModelTypeName, xContext), uno::UNO_QUERY);
379
380
0
        if (xModel.is())
381
0
            SetChanged();
382
0
    }
383
384
0
    SetUnoControlModel(xModel);
385
0
}
386
387
void SdrUnoObj::CreateUnoControlModel(const OUString& rModelName,
388
                                      const uno::Reference< lang::XMultiServiceFactory >& rxSFac)
389
0
{
390
0
    DBG_ASSERT(!m_xUnoControlModel.is(), "model already exists");
391
392
0
    m_aUnoControlModelTypeName = rModelName;
393
394
0
    uno::Reference< awt::XControlModel >   xModel;
395
0
    if (!m_aUnoControlModelTypeName.isEmpty() && rxSFac.is() )
396
0
    {
397
0
        xModel.set(rxSFac->createInstance(m_aUnoControlModelTypeName), uno::UNO_QUERY);
398
399
0
        if (xModel.is())
400
0
            SetChanged();
401
0
    }
402
403
0
    SetUnoControlModel(xModel);
404
0
}
405
406
void SdrUnoObj::SetUnoControlModel( const uno::Reference< awt::XControlModel >& xModel)
407
0
{
408
0
    if (m_xUnoControlModel.is())
409
0
    {
410
0
        uno::Reference< lang::XComponent > xComp(m_xUnoControlModel, uno::UNO_QUERY);
411
0
        if (xComp.is())
412
0
            m_pImpl->pEventListener->StopListening(xComp);
413
0
    }
414
415
0
    m_xUnoControlModel = xModel;
416
417
    // control model has to contain service name of the control
418
0
    if (m_xUnoControlModel.is())
419
0
    {
420
0
        uno::Reference< beans::XPropertySet > xSet(m_xUnoControlModel, uno::UNO_QUERY);
421
0
        if (xSet.is())
422
0
        {
423
0
            uno::Any aValue( xSet->getPropertyValue(u"DefaultControl"_ustr) );
424
0
            OUString aStr;
425
0
            if( aValue >>= aStr )
426
0
                m_aUnoControlTypeName = aStr;
427
0
        }
428
429
0
        uno::Reference< lang::XComponent > xComp(m_xUnoControlModel, uno::UNO_QUERY);
430
0
        if (xComp.is())
431
0
            m_pImpl->pEventListener->StartListening(xComp);
432
0
    }
433
434
    // invalidate all ViewObject contacts
435
0
    ViewContactOfUnoControl* pVC = nullptr;
436
0
    if ( impl_getViewContact( pVC ) )
437
0
    {
438
        // flushViewObjectContacts() removes all existing VOCs for the local DrawHierarchy. This
439
        // is always allowed since they will be re-created on demand (and with the changed model)
440
0
        GetViewContact().flushViewObjectContacts();
441
0
    }
442
0
}
443
444
445
uno::Reference< awt::XControl > SdrUnoObj::GetUnoControl(const SdrView& _rView, const OutputDevice& _rOut) const
446
0
{
447
0
    uno::Reference< awt::XControl > xControl;
448
449
0
    SdrPageView* pPageView = _rView.GetSdrPageView();
450
0
    OSL_ENSURE( pPageView && getSdrPageFromSdrObject() == pPageView->GetPage(), "SdrUnoObj::GetUnoControl: This object is not displayed in that particular view!" );
451
0
    if ( !pPageView || getSdrPageFromSdrObject() != pPageView->GetPage() )
452
0
        return nullptr;
453
454
0
    SdrPageWindow* pPageWindow = pPageView->FindPageWindow( _rOut );
455
0
    OSL_ENSURE( pPageWindow, "SdrUnoObj::GetUnoControl: did not find my SdrPageWindow!" );
456
0
    if ( !pPageWindow )
457
0
        return nullptr;
458
459
0
    ViewObjectContact& rViewObjectContact( GetViewContact().GetViewObjectContact( pPageWindow->GetObjectContact() ) );
460
0
    ViewObjectContactOfUnoControl* pUnoContact = dynamic_cast< ViewObjectContactOfUnoControl* >( &rViewObjectContact );
461
0
    OSL_ENSURE( pUnoContact, "SdrUnoObj::GetUnoControl: wrong contact type!" );
462
0
    if ( pUnoContact )
463
0
        xControl = pUnoContact->getControl();
464
465
0
    return xControl;
466
0
}
467
468
469
uno::Reference< awt::XControl > SdrUnoObj::GetTemporaryControlForWindow(
470
    const vcl::Window& _rWindow, uno::Reference< awt::XControlContainer >& _inout_ControlContainer ) const
471
0
{
472
0
    uno::Reference< awt::XControl > xControl;
473
474
0
    ViewContactOfUnoControl* pVC = nullptr;
475
0
    if ( impl_getViewContact( pVC ) )
476
0
        xControl = pVC->getTemporaryControlForWindow( _rWindow, _inout_ControlContainer );
477
478
0
    return xControl;
479
0
}
480
481
482
bool SdrUnoObj::impl_getViewContact( ViewContactOfUnoControl*& _out_rpContact ) const
483
0
{
484
0
    ViewContact& rViewContact( GetViewContact() );
485
0
    _out_rpContact = dynamic_cast< ViewContactOfUnoControl* >( &rViewContact );
486
0
    DBG_ASSERT( _out_rpContact, "SdrUnoObj::impl_getViewContact: could not find my ViewContact!" );
487
0
    return ( _out_rpContact != nullptr );
488
0
}
489
490
491
std::unique_ptr<sdr::contact::ViewContact> SdrUnoObj::CreateObjectSpecificViewContact()
492
785
{
493
785
  return std::make_unique<sdr::contact::ViewContactOfUnoControl>( *this );
494
785
}
495
496
497
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */