Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/embeddedobj/source/commonembedding/embedobj.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
#include <com/sun/star/embed/EmbedStates.hpp>
21
#include <com/sun/star/embed/EmbedUpdateModes.hpp>
22
#include <com/sun/star/embed/ObjectSaveVetoException.hpp>
23
#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
24
#include <com/sun/star/embed/UnreachableStateException.hpp>
25
#include <com/sun/star/embed/XEmbeddedClient.hpp>
26
#include <com/sun/star/embed/XInplaceClient.hpp>
27
#include <com/sun/star/embed/XWindowSupplier.hpp>
28
#include <com/sun/star/embed/StateChangeInProgressException.hpp>
29
#include <com/sun/star/embed/Aspects.hpp>
30
31
#include <com/sun/star/awt/XWindowPeer.hpp>
32
#include <com/sun/star/io/IOException.hpp>
33
#include <com/sun/star/util/XCloseable.hpp>
34
#include <com/sun/star/util/XModifiable.hpp>
35
#include <com/sun/star/frame/ModuleManager.hpp>
36
#include <com/sun/star/lang/DisposedException.hpp>
37
38
#include <com/sun/star/embed/EmbedMisc.hpp>
39
#include <cppuhelper/exc_hlp.hxx>
40
#include <comphelper/multicontainer2.hxx>
41
#include <comphelper/lok.hxx>
42
#include <sal/log.hxx>
43
#include <officecfg/Office/Common.hxx>
44
45
#include <vcl/svapp.hxx>
46
47
#include <targetstatecontrol.hxx>
48
49
#include <commonembobj.hxx>
50
#include "embedobj.hxx"
51
#include <specialobject.hxx>
52
#include <array>
53
54
using namespace ::com::sun::star;
55
56
awt::Rectangle GetRectangleInterception( const awt::Rectangle& aRect1, const awt::Rectangle& aRect2 )
57
0
{
58
0
    awt::Rectangle aResult;
59
60
0
    OSL_ENSURE( aRect1.Width >= 0 && aRect2.Width >= 0 && aRect1.Height >= 0 && aRect2.Height >= 0,
61
0
                "Offset must not be less than zero!" );
62
63
0
    aResult.X = std::max(aRect1.X, aRect2.X);
64
0
    aResult.Y = std::max(aRect1.Y, aRect2.Y);
65
66
0
    sal_Int32 nRight1 = aRect1.X + aRect1.Width;
67
0
    sal_Int32 nBottom1 = aRect1.Y + aRect1.Height;
68
0
    sal_Int32 nRight2 = aRect2.X + aRect2.Width;
69
0
    sal_Int32 nBottom2 = aRect2.Y + aRect2.Height;
70
0
    aResult.Width = std::min( nRight1, nRight2 ) - aResult.X;
71
0
    aResult.Height = std::min( nBottom1, nBottom2 ) - aResult.Y;
72
73
0
    return aResult;
74
0
}
75
76
namespace
77
{
78
    using IntermediateStatesMap = std::array<std::array<uno::Sequence< sal_Int32 >, NUM_SUPPORTED_STATES>, NUM_SUPPORTED_STATES>;
79
    const IntermediateStatesMap & getIntermediateStatesMap()
80
0
    {
81
0
        static const IntermediateStatesMap map = [] () {
82
0
            IntermediateStatesMap tmp;
83
84
            // intermediate states
85
            // In the following table the first index points to starting state,
86
            // the second one to the target state, and the sequence referenced by
87
            // first two indexes contains intermediate states, that should be
88
            // passed by object to reach the target state.
89
            // If the sequence is empty that means that indirect switch from start
90
            // state to the target state is forbidden, only if direct switch is possible
91
            // the state can be reached.
92
93
0
            tmp[0][2] = { embed::EmbedStates::RUNNING };
94
95
0
            tmp[0][3] = { embed::EmbedStates::RUNNING,
96
0
                                                embed::EmbedStates::INPLACE_ACTIVE };
97
98
0
            tmp[0][4] = {embed::EmbedStates::RUNNING};
99
100
0
            tmp[1][3] = { embed::EmbedStates::INPLACE_ACTIVE };
101
102
0
            tmp[2][0] = { embed::EmbedStates::RUNNING };
103
104
0
            tmp[3][0] = { embed::EmbedStates::INPLACE_ACTIVE,
105
0
                                                embed::EmbedStates::RUNNING };
106
107
0
            tmp[3][1] = { embed::EmbedStates::INPLACE_ACTIVE };
108
109
0
            tmp[4][0] = { embed::EmbedStates::RUNNING };
110
111
0
            return tmp;
112
0
        }();
113
0
        return map;
114
0
    }
115
116
    // accepted states
117
    const css::uno::Sequence< sal_Int32 > & getAcceptedStates()
118
0
    {
119
0
        static const css::uno::Sequence< sal_Int32 > states {
120
0
            /* [0] */ embed::EmbedStates::LOADED,
121
0
                          /* [1] */ embed::EmbedStates::RUNNING,
122
0
                          /* [2] */ embed::EmbedStates::INPLACE_ACTIVE,
123
0
                          /* [3] */ embed::EmbedStates::UI_ACTIVE,
124
0
                          /* [4] */ embed::EmbedStates::ACTIVE };
125
0
        assert(states.getLength() == NUM_SUPPORTED_STATES);
126
0
        return states;
127
0
    }
128
129
}
130
131
sal_Int32 OCommonEmbeddedObject::ConvertVerbToState_Impl( sal_Int32 nVerb )
132
0
{
133
0
    auto it = m_aVerbTable.find( nVerb );
134
0
    if (it != m_aVerbTable.end())
135
0
        return it->second;
136
137
0
    throw lang::IllegalArgumentException(); // TODO: unexpected verb provided
138
0
}
139
140
141
void OCommonEmbeddedObject::Deactivate()
142
0
{
143
0
    uno::Reference< util::XModifiable > xModif( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
144
145
    // no need to lock for the initialization
146
0
    uno::Reference< embed::XEmbeddedClient > xClientSite = m_xClientSite;
147
0
    if ( !xClientSite.is() )
148
0
        throw embed::WrongStateException(); //TODO: client site is not set!
149
150
    // tdf#131146 close frame before saving of the document
151
    // (during CloseFrame() call some changes could be detected not registered in util::XModifiable)
152
0
    m_xDocHolder->CloseFrame();
153
154
    // store document if it is modified
155
0
    if ( xModif.is() && xModif->isModified() )
156
0
    {
157
0
        try {
158
0
            xClientSite->saveObject();
159
160
            // tdf#141529 take note that an eventually used linked file
161
            // got changed/saved/written and that we need to copy it back if the
162
            // hosting file/document gets saved
163
0
            if(m_aLinkTempFile.is())
164
0
                m_bLinkTempFileChanged = true;
165
0
        }
166
0
        catch( const embed::ObjectSaveVetoException& )
167
0
        {
168
0
        }
169
0
        catch( const uno::Exception& )
170
0
        {
171
0
            css::uno::Any anyEx = cppu::getCaughtException();
172
0
            throw embed::StorageWrappedTargetException(
173
0
                u"The client could not store the object!"_ustr,
174
0
                static_cast< ::cppu::OWeakObject* >( this ),
175
0
                anyEx );
176
0
        }
177
0
    }
178
179
0
    xClientSite->visibilityChanged( false );
180
0
}
181
182
183
void OCommonEmbeddedObject::StateChangeNotification_Impl( bool bBeforeChange, sal_Int32 nOldState, sal_Int32 nNewState ,::osl::ResettableMutexGuard& rGuard )
184
0
{
185
0
    if ( !m_pInterfaceContainer )
186
0
        return;
187
188
0
    comphelper::OInterfaceContainerHelper2* pContainer = m_pInterfaceContainer->getContainer(
189
0
                        cppu::UnoType<embed::XStateChangeListener>::get());
190
0
    if ( pContainer == nullptr )
191
0
        return;
192
193
0
    lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
194
0
    comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
195
196
    // should be locked after the method is finished successfully
197
0
    rGuard.clear();
198
199
0
    while (pIterator.hasMoreElements())
200
0
    {
201
0
        try
202
0
        {
203
0
            if ( bBeforeChange )
204
0
                static_cast<embed::XStateChangeListener*>(pIterator.next())->changingState( aSource, nOldState, nNewState );
205
0
            else
206
0
                static_cast<embed::XStateChangeListener*>(pIterator.next())->stateChanged( aSource, nOldState, nNewState );
207
0
        }
208
0
        catch( const uno::Exception& )
209
0
        {
210
            // even if the listener complains ignore it for now
211
0
           }
212
213
0
        if ( m_bDisposed )
214
0
            return;
215
0
    }
216
217
0
    rGuard.reset();
218
0
}
219
220
void OCommonEmbeddedObject::SetInplaceActiveState()
221
0
{
222
0
    if ( !m_xClientSite.is() )
223
0
        throw embed::WrongStateException( u"client site not set, yet"_ustr, *this );
224
225
0
    uno::Reference< embed::XInplaceClient > xInplaceClient( m_xClientSite, uno::UNO_QUERY );
226
0
    if ( !xInplaceClient.is() || !xInplaceClient->canInplaceActivate() )
227
0
        throw embed::WrongStateException(); //TODO: can't activate inplace
228
0
    xInplaceClient->activatingInplace();
229
230
0
    uno::Reference< embed::XWindowSupplier > xClientWindowSupplier( xInplaceClient, uno::UNO_QUERY_THROW );
231
232
0
    m_xClientWindow = xClientWindowSupplier->getWindow();
233
0
    m_aOwnRectangle = xInplaceClient->getPlacement();
234
0
    m_aClipRectangle = xInplaceClient->getClipRectangle();
235
0
    awt::Rectangle aRectangleToShow = GetRectangleInterception( m_aOwnRectangle, m_aClipRectangle );
236
237
    // create own window based on the client window
238
    // place and resize the window according to the rectangles
239
0
    uno::Reference< awt::XWindowPeer > xClientWindowPeer( m_xClientWindow, uno::UNO_QUERY_THROW );
240
241
    // dispatch provider may not be provided
242
0
    uno::Reference< frame::XDispatchProvider > xContainerDP = xInplaceClient->getInplaceDispatchProvider();
243
0
    bool bOk = m_xDocHolder->ShowInplace( xClientWindowPeer, aRectangleToShow, xContainerDP );
244
0
    m_nObjectState = embed::EmbedStates::INPLACE_ACTIVE;
245
0
    if ( !bOk )
246
0
    {
247
0
        SwitchStateTo_Impl( embed::EmbedStates::RUNNING );
248
0
        throw embed::WrongStateException(); //TODO: can't activate inplace
249
0
    }
250
0
}
251
252
void OCommonEmbeddedObject::SwitchStateTo_Impl( sal_Int32 nNextState )
253
0
{
254
    // TODO: may be needs interaction handler to detect whether the object state
255
    //         can be changed even after errors
256
257
0
    if ( m_nObjectState == embed::EmbedStates::LOADED )
258
0
    {
259
0
        if ( nNextState == embed::EmbedStates::RUNNING )
260
0
        {
261
            // after the object reaches the running state the cloned size is not necessary any more
262
0
            m_bHasClonedSize = false;
263
264
0
            if ( m_bIsLinkURL )
265
0
            {
266
0
                m_xDocHolder->SetComponent( LoadLink_Impl(), m_bReadOnly );
267
0
            }
268
0
            else
269
0
            {
270
0
                if ( !dynamic_cast<OSpecialEmbeddedObject*>(this) )
271
0
                {
272
                    // in case embedded object is in loaded state the contents must
273
                    // be stored in the related storage and the storage
274
                    // must be created already
275
0
                    if ( !m_xObjectStorage.is() )
276
0
                        throw io::IOException(); //TODO: access denied
277
278
0
                    m_xDocHolder->SetComponent( LoadDocumentFromStorage_Impl(), m_bReadOnly );
279
0
                }
280
0
                else
281
0
                {
282
                    // objects without persistence will be initialized internally
283
0
                    uno::Sequence < uno::Any > aArgs{ uno::Any(
284
0
                        uno::Reference < embed::XEmbeddedObject >( this )) };
285
0
                    uno::Reference< util::XCloseable > xDocument(
286
0
                            m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( GetDocumentServiceName(), aArgs, m_xContext),
287
0
                            uno::UNO_QUERY );
288
289
0
                    uno::Reference < container::XChild > xChild( xDocument, uno::UNO_QUERY );
290
0
                    if ( xChild.is() )
291
0
                        xChild->setParent( m_xParent );
292
293
0
                    m_xDocHolder->SetComponent( xDocument, m_bReadOnly );
294
0
                }
295
0
            }
296
297
0
            if ( !m_xDocHolder->GetComponent().is() )
298
0
                throw embed::UnreachableStateException(); //TODO: can't open document
299
300
0
            m_nObjectState = nNextState;
301
0
        }
302
0
        else
303
0
        {
304
0
            SAL_WARN( "embeddedobj.common", "Unacceptable state switch!" );
305
0
            throw uno::RuntimeException(u"invalid next state, only RUNNING state allowed"_ustr); // TODO
306
0
        }
307
0
    }
308
0
    else if ( m_nObjectState == embed::EmbedStates::RUNNING )
309
0
    {
310
0
        if ( nNextState == embed::EmbedStates::LOADED )
311
0
        {
312
0
            m_nClonedMapUnit = m_xDocHolder->GetMapUnit( embed::Aspects::MSOLE_CONTENT );
313
0
            m_bHasClonedSize = m_xDocHolder->GetExtent( embed::Aspects::MSOLE_CONTENT, &m_aClonedSize );
314
315
            // actually frame should not exist at this point
316
0
            m_xDocHolder->CloseDocument( false, false );
317
318
0
            m_nObjectState = nNextState;
319
0
        }
320
0
        else
321
0
        {
322
0
            if ( nNextState == embed::EmbedStates::INPLACE_ACTIVE )
323
0
            {
324
0
                SetInplaceActiveState();
325
0
            }
326
0
            else if ( nNextState == embed::EmbedStates::ACTIVE )
327
0
            {
328
0
                if ( !m_xClientSite.is() )
329
0
                    throw embed::WrongStateException(); //TODO: client site is not set!
330
331
                // create frame and load document in the frame
332
0
                m_xDocHolder->Show();
333
334
0
                m_xClientSite->visibilityChanged( true );
335
0
                m_nObjectState = nNextState;
336
0
            }
337
0
            else
338
0
            {
339
0
                SAL_WARN( "embeddedobj.common", "Unacceptable state switch!" );
340
0
                throw uno::RuntimeException(u"invalid next state,only LOADED/INPLACE_ACTIVE/ACTIVE allowed"_ustr); // TODO
341
0
            }
342
0
        }
343
0
    }
344
0
    else if ( m_nObjectState == embed::EmbedStates::INPLACE_ACTIVE )
345
0
    {
346
0
        if ( nNextState == embed::EmbedStates::RUNNING )
347
0
        {
348
0
            uno::Reference< embed::XInplaceClient > xInplaceClient( m_xClientSite, uno::UNO_QUERY_THROW );
349
350
0
            m_xClientSite->visibilityChanged( true );
351
352
0
            xInplaceClient->deactivatedInplace();
353
0
            Deactivate();
354
0
            m_nObjectState = nNextState;
355
0
        }
356
0
        else if ( nNextState == embed::EmbedStates::UI_ACTIVE )
357
0
        {
358
0
            if ( !(m_nMiscStatus & embed::EmbedMisc::MS_EMBED_NOUIACTIVATE) )
359
0
            {
360
0
                uno::Reference< embed::XInplaceClient > xInplaceClient( m_xClientSite, uno::UNO_QUERY_THROW );
361
                // TODO:
362
0
                uno::Reference< css::frame::XLayoutManager > xContainerLM =
363
0
                            xInplaceClient->getLayoutManager();
364
0
                if ( !xContainerLM.is() )
365
0
                    throw embed::WrongStateException(); //TODO: can't activate UI
366
                // dispatch provider may not be provided
367
0
                uno::Reference< frame::XDispatchProvider > xContainerDP = xInplaceClient->getInplaceDispatchProvider();
368
369
                // get the container module name
370
0
                OUString aModuleName;
371
0
                try
372
0
                {
373
0
                    uno::Reference< embed::XComponentSupplier > xCompSupl( m_xClientSite, uno::UNO_QUERY_THROW );
374
0
                    uno::Reference< uno::XInterface > xContDoc( xCompSupl->getComponent(), uno::UNO_QUERY_THROW );
375
376
0
                    uno::Reference< frame::XModuleManager2 > xManager( frame::ModuleManager::create( m_xContext ) );
377
378
0
                    aModuleName = xManager->identify( xContDoc );
379
0
                }
380
0
                catch( const uno::Exception& )
381
0
                {}
382
383
0
                if (!comphelper::LibreOfficeKit::isActive())
384
0
                {
385
                    // if currently another object is UIactive it will be deactivated; usually this will activate the LM of
386
                    // the container. Locking the LM will prevent flicker.
387
0
                    xContainerLM->lock();
388
0
                    xInplaceClient->activatingUI();
389
0
                    bool bOk = m_xDocHolder->ShowUI( xContainerLM, xContainerDP, aModuleName );
390
0
                    xContainerLM->unlock();
391
392
0
                    if ( bOk )
393
0
                    {
394
0
                        m_nObjectState = nNextState;
395
0
                        m_xDocHolder->ResizeHatchWindow();
396
0
                    }
397
0
                    else
398
0
                    {
399
0
                        xInplaceClient->deactivatedUI();
400
0
                        throw embed::WrongStateException(); //TODO: can't activate UI
401
0
                    }
402
0
                }
403
0
            }
404
0
        }
405
0
        else
406
0
        {
407
0
            SAL_WARN( "embeddedobj.common", "Unacceptable state switch!" );
408
0
            throw uno::RuntimeException(u"invalid next state,only RUNNING/UI_ACTIVE allowed"_ustr); // TODO
409
0
        }
410
0
    }
411
0
    else if ( m_nObjectState == embed::EmbedStates::ACTIVE )
412
0
    {
413
0
        if ( nNextState == embed::EmbedStates::RUNNING )
414
0
        {
415
0
            Deactivate();
416
0
            m_nObjectState = nNextState;
417
0
        }
418
0
        else
419
0
        {
420
0
            SAL_WARN( "embeddedobj.common", "Unacceptable state switch!" );
421
0
            throw uno::RuntimeException(u"invalid next state, only RUNNING state allowed"_ustr); // TODO
422
0
        }
423
0
    }
424
0
    else if ( m_nObjectState == embed::EmbedStates::UI_ACTIVE )
425
0
    {
426
0
        if ( nNextState == embed::EmbedStates::INPLACE_ACTIVE )
427
0
        {
428
0
            uno::Reference< embed::XInplaceClient > xInplaceClient( m_xClientSite, uno::UNO_QUERY_THROW );
429
0
            uno::Reference< css::frame::XLayoutManager > xContainerLM =
430
0
                        xInplaceClient->getLayoutManager();
431
432
0
            bool bOk = false;
433
0
            if ( xContainerLM.is() )
434
0
                bOk = m_xDocHolder->HideUI( xContainerLM );
435
436
0
            if ( !bOk )
437
0
                throw embed::WrongStateException(); //TODO: can't activate UI
438
0
            m_nObjectState = nNextState;
439
0
            m_xDocHolder->ResizeHatchWindow();
440
0
            xInplaceClient->deactivatedUI();
441
0
        }
442
0
    }
443
0
    else
444
0
        throw embed::WrongStateException( u"The object is in unacceptable state!"_ustr,
445
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
446
0
}
447
448
449
uno::Sequence< sal_Int32 > const & OCommonEmbeddedObject::GetIntermediateStatesSequence_Impl( sal_Int32 nNewState )
450
0
{
451
0
    sal_Int32 nCurInd = 0;
452
0
    auto & rAcceptedStates = getAcceptedStates();
453
0
    for ( nCurInd = 0; nCurInd < rAcceptedStates.getLength(); nCurInd++ )
454
0
        if ( rAcceptedStates[nCurInd] == m_nObjectState )
455
0
            break;
456
457
0
    if ( nCurInd == rAcceptedStates.getLength() )
458
0
        throw embed::WrongStateException( u"The object is in unacceptable state!"_ustr,
459
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
460
461
0
    sal_Int32 nDestInd = 0;
462
0
    for ( nDestInd = 0; nDestInd < rAcceptedStates.getLength(); nDestInd++ )
463
0
        if ( rAcceptedStates[nDestInd] == nNewState )
464
0
            break;
465
466
0
    if ( nDestInd == rAcceptedStates.getLength() )
467
0
        throw embed::UnreachableStateException(
468
0
            u"The state either not reachable, or the object allows the state only as an intermediate one!"_ustr,
469
0
            static_cast< ::cppu::OWeakObject* >(this),
470
0
            m_nObjectState,
471
0
            nNewState );
472
473
0
    return getIntermediateStatesMap()[nCurInd][nDestInd];
474
0
}
475
476
477
void SAL_CALL OCommonEmbeddedObject::changeState( sal_Int32 nNewState )
478
0
{
479
0
    if ( officecfg::Office::Common::Security::Scripting::DisableActiveContent::get()
480
0
        && nNewState != embed::EmbedStates::LOADED )
481
0
        throw embed::UnreachableStateException();
482
0
    ::osl::ResettableMutexGuard aGuard( m_aMutex );
483
0
    if ( m_bDisposed )
484
0
        throw lang::DisposedException(); // TODO
485
486
0
    if ( m_nObjectState == -1 )
487
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
488
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
489
490
0
    sal_Int32 nOldState = m_nObjectState;
491
492
0
    if ( m_nTargetState != -1 )
493
0
    {
494
        // means that the object is currently trying to reach the target state
495
0
        throw embed::StateChangeInProgressException( OUString(),
496
0
                                                    uno::Reference< uno::XInterface >(),
497
0
                                                    m_nTargetState );
498
0
    }
499
0
    else
500
0
    {
501
0
        TargetStateControl_Impl aControl( m_nTargetState, nNewState );
502
503
        // in case the object is already in requested state
504
0
        if ( m_nObjectState == nNewState )
505
0
        {
506
            // if active object is activated again, bring its window to top
507
0
            if ( m_nObjectState == embed::EmbedStates::ACTIVE )
508
0
                m_xDocHolder->Show();
509
510
0
            return;
511
0
        }
512
513
        // retrieve sequence of states that should be passed to reach desired state
514
0
        uno::Sequence< sal_Int32 > aIntermediateStates = GetIntermediateStatesSequence_Impl( nNewState );
515
516
        // notify listeners that the object is going to change the state
517
0
        StateChangeNotification_Impl( true, nOldState, nNewState,aGuard );
518
519
0
        try {
520
0
            for (sal_Int32 state : aIntermediateStates)
521
0
                SwitchStateTo_Impl( state );
522
523
0
            SwitchStateTo_Impl( nNewState );
524
0
        }
525
0
        catch( const uno::Exception& )
526
0
        {
527
0
            if ( nOldState != m_nObjectState )
528
                // notify listeners that the object has changed the state
529
0
                StateChangeNotification_Impl( false, nOldState, m_nObjectState, aGuard );
530
531
0
            throw;
532
0
        }
533
0
    }
534
535
    // notify listeners that the object has changed the state
536
0
    StateChangeNotification_Impl( false, nOldState, nNewState, aGuard );
537
538
    // let the object window be shown
539
0
    if ( nNewState == embed::EmbedStates::UI_ACTIVE || nNewState == embed::EmbedStates::INPLACE_ACTIVE )
540
0
        PostEvent_Impl( u"OnVisAreaChanged"_ustr );
541
0
}
542
543
544
uno::Sequence< sal_Int32 > SAL_CALL OCommonEmbeddedObject::getReachableStates()
545
0
{
546
0
    if ( m_bDisposed )
547
0
        throw lang::DisposedException(); // TODO
548
549
0
    if ( m_nObjectState == -1 )
550
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
551
0
                                           static_cast< ::cppu::OWeakObject* >(this) );
552
553
0
    return getAcceptedStates();
554
0
}
555
556
557
sal_Int32 SAL_CALL OCommonEmbeddedObject::getCurrentState()
558
0
{
559
0
    if ( m_bDisposed )
560
0
        throw lang::DisposedException(); // TODO
561
562
0
    if ( m_nObjectState == -1 )
563
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
564
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
565
566
0
    return m_nObjectState;
567
0
}
568
569
570
void SAL_CALL OCommonEmbeddedObject::doVerb( sal_Int32 nVerbID )
571
0
{
572
0
    SolarMutexGuard aSolarGuard;
573
        //TODO: a gross hack to avoid deadlocks when this is called from the
574
        // outside and OCommonEmbeddedObject::changeState, with m_aMutex locked,
575
        // calls into framework code that tries to lock the solar mutex, while
576
        // another thread (through Window::ImplCallPaint, say) calls
577
        // OCommonEmbeddedObject::getComponent with the solar mutex locked and
578
        // then tries to lock m_aMutex (see fdo#56818); the alternative would be
579
        // to get locking done right in this class, but that looks like a
580
        // daunting task
581
582
0
    osl::ClearableMutexGuard aGuard( m_aMutex );
583
0
    if ( m_bDisposed )
584
0
        throw lang::DisposedException(); // TODO
585
586
0
    if ( m_nObjectState == -1 )
587
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
588
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
589
590
    // for internal documents this call is just a duplicate of changeState
591
0
    sal_Int32 nNewState = -1;
592
0
    try
593
0
    {
594
0
        nNewState = ConvertVerbToState_Impl( nVerbID );
595
0
    }
596
0
    catch( const uno::Exception& )
597
0
    {}
598
599
0
    if ( nNewState == -1 )
600
0
    {
601
        // TODO/LATER: Save Copy as... verb ( -8 ) is implemented by container
602
        // TODO/LATER: check if the verb is a supported one and if it is produce related operation
603
0
    }
604
0
    else
605
0
    {
606
0
        aGuard.clear();
607
0
        changeState( nNewState );
608
0
    }
609
0
}
610
611
612
uno::Sequence< embed::VerbDescriptor > SAL_CALL OCommonEmbeddedObject::getSupportedVerbs()
613
0
{
614
0
    if ( m_bDisposed )
615
0
        throw lang::DisposedException(); // TODO
616
617
0
    if ( m_nObjectState == -1 )
618
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
619
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
620
621
0
    return m_aObjectVerbs;
622
0
}
623
624
625
void SAL_CALL OCommonEmbeddedObject::setClientSite(
626
                const uno::Reference< embed::XEmbeddedClient >& xClient )
627
0
{
628
0
    ::osl::MutexGuard aGuard( m_aMutex );
629
0
    if ( m_bDisposed )
630
0
        throw lang::DisposedException(); // TODO
631
632
0
    if ( m_xClientSite != xClient)
633
0
    {
634
0
        if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
635
0
            throw embed::WrongStateException(
636
0
                                    u"The client site can not be set currently!"_ustr,
637
0
                                     static_cast< ::cppu::OWeakObject* >(this) );
638
639
0
        m_xClientSite = xClient;
640
0
    }
641
0
}
642
643
644
uno::Reference< embed::XEmbeddedClient > SAL_CALL OCommonEmbeddedObject::getClientSite()
645
0
{
646
0
    if ( m_bDisposed )
647
0
        throw lang::DisposedException(); // TODO
648
649
0
    if ( m_nObjectState == -1 )
650
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
651
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
652
653
0
    return m_xClientSite;
654
0
}
655
656
657
void SAL_CALL OCommonEmbeddedObject::update()
658
0
{
659
0
    ::osl::MutexGuard aGuard( m_aMutex );
660
0
    if ( m_bDisposed )
661
0
        throw lang::DisposedException(); // TODO
662
663
0
    if ( m_nObjectState == -1 )
664
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
665
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
666
667
0
    PostEvent_Impl( u"OnVisAreaChanged"_ustr );
668
0
}
669
670
671
void SAL_CALL OCommonEmbeddedObject::setUpdateMode( sal_Int32 nMode )
672
0
{
673
0
    ::osl::MutexGuard aGuard( m_aMutex );
674
0
    if ( m_bDisposed )
675
0
        throw lang::DisposedException(); // TODO
676
677
0
    if ( m_nObjectState == -1 )
678
0
        throw embed::WrongStateException( u"The object has no persistence!"_ustr,
679
0
                                          static_cast< ::cppu::OWeakObject* >(this) );
680
681
0
    OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
682
0
                    || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
683
0
                "Unknown update mode!" );
684
0
    m_nUpdateMode = nMode;
685
0
}
686
687
688
sal_Int64 SAL_CALL OCommonEmbeddedObject::getStatus( sal_Int64 )
689
0
{
690
0
    if ( m_bDisposed )
691
0
        throw lang::DisposedException(); // TODO
692
693
0
    return m_nMiscStatus;
694
0
}
695
696
697
void SAL_CALL OCommonEmbeddedObject::setContainerName( const OUString& sName )
698
0
{
699
0
    ::osl::MutexGuard aGuard( m_aMutex );
700
0
    if ( m_bDisposed )
701
0
        throw lang::DisposedException(); // TODO
702
703
0
    m_aContainerName = sName;
704
0
}
705
706
void OCommonEmbeddedObject::SetOleState(bool bIsOleUpdate)
707
0
{
708
0
    ::osl::MutexGuard aGuard( m_aMutex );
709
710
0
    m_bOleUpdate = bIsOleUpdate;
711
0
}
712
713
css::uno::Reference< css::uno::XInterface > SAL_CALL OCommonEmbeddedObject::getParent()
714
0
{
715
0
    return m_xParent;
716
0
}
717
718
void SAL_CALL OCommonEmbeddedObject::setParent( const css::uno::Reference< css::uno::XInterface >& xParent )
719
0
{
720
0
    m_xParent = xParent;
721
0
    if ( m_nObjectState != -1 && m_nObjectState != embed::EmbedStates::LOADED )
722
0
    {
723
0
        uno::Reference < container::XChild > xChild( m_xDocHolder->GetComponent(), uno::UNO_QUERY );
724
0
        if ( xChild.is() )
725
0
            xChild->setParent( xParent );
726
0
    }
727
0
}
728
729
// XDefaultSizeTransmitter
730
void SAL_CALL OCommonEmbeddedObject::setDefaultSize( const css::awt::Size& rSize_100TH_MM )
731
0
{
732
    //#i103460# charts do not necessarily have an own size within ODF files, in this case they need to use the size settings from the surrounding frame, which is made available with this method
733
0
    m_aDefaultSizeForChart_In_100TH_MM = rSize_100TH_MM;
734
0
}
735
736
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */