Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / embeddedobj / source / commonembedding / miscobj.cxx
blob3d0cbb98b83930c5650a3290ae4dc90b949b6241
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <commonembobj.hxx>
21 #include <com/sun/star/embed/EmbedStates.hpp>
22 #include <com/sun/star/embed/EmbedVerbs.hpp>
23 #include <com/sun/star/embed/XStorage.hpp>
24 #include <com/sun/star/embed/EmbedUpdateModes.hpp>
25 #include <com/sun/star/embed/XInplaceClient.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/lang/NoSupportException.hpp>
28 #include <com/sun/star/beans/NamedValue.hpp>
30 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <comphelper/storagehelper.hxx>
34 #include <cppuhelper/queryinterface.hxx>
35 #include <cppuhelper/interfacecontainer.h>
36 #include <comphelper/mimeconfighelper.hxx>
38 #include <vcl/svapp.hxx>
40 #include "persistence.hxx"
42 using namespace ::com::sun::star;
45 OCommonEmbeddedObject::OCommonEmbeddedObject( const uno::Reference< uno::XComponentContext >& rxContext,
46 const uno::Sequence< beans::NamedValue >& aObjProps )
47 : m_pInterfaceContainer( nullptr )
48 , m_bReadOnly( false )
49 , m_bDisposed( false )
50 , m_bClosed( false )
51 , m_nObjectState( -1 )
52 , m_nTargetState( -1 )
53 , m_nUpdateMode ( embed::EmbedUpdateModes::ALWAYS_UPDATE )
54 , m_xContext( rxContext )
55 , m_nMiscStatus( 0 )
56 , m_bEmbeddedScriptSupport( true )
57 , m_bDocumentRecoverySupport( true )
58 , m_bWaitSaveCompleted( false )
59 , m_bIsLinkURL( false )
60 , m_bLinkTempFileChanged( false )
61 , m_bLinkHasPassword( false )
62 , m_aLinkTempFile( )
63 , m_bHasClonedSize( false )
64 , m_nClonedMapUnit( 0 )
66 CommonInit_Impl( aObjProps );
70 OCommonEmbeddedObject::OCommonEmbeddedObject(
71 const uno::Reference< uno::XComponentContext >& rxContext,
72 const uno::Sequence< beans::NamedValue >& aObjProps,
73 const uno::Sequence< beans::PropertyValue >& aMediaDescr,
74 const uno::Sequence< beans::PropertyValue >& aObjectDescr )
75 : m_pInterfaceContainer( nullptr )
76 , m_bReadOnly( false )
77 , m_bDisposed( false )
78 , m_bClosed( false )
79 , m_nObjectState( embed::EmbedStates::LOADED )
80 , m_nTargetState( -1 )
81 , m_nUpdateMode ( embed::EmbedUpdateModes::ALWAYS_UPDATE )
82 , m_xContext( rxContext )
83 , m_nMiscStatus( 0 )
84 , m_bEmbeddedScriptSupport( true )
85 , m_bDocumentRecoverySupport( true )
86 , m_bWaitSaveCompleted( false )
87 , m_bIsLinkURL( true )
88 , m_bLinkTempFileChanged( false )
89 , m_bLinkHasPassword( false )
90 , m_aLinkTempFile( )
91 , m_bHasClonedSize( false )
92 , m_nClonedMapUnit( 0 )
94 // linked object has no own persistence so it is in loaded state starting from creation
95 LinkInit_Impl( aObjProps, aMediaDescr, aObjectDescr );
99 void OCommonEmbeddedObject::CommonInit_Impl( const uno::Sequence< beans::NamedValue >& aObjectProps )
101 OSL_ENSURE( m_xContext.is(), "No ServiceFactory is provided!" );
102 if ( !m_xContext.is() )
103 throw uno::RuntimeException();
105 m_xDocHolder = new DocumentHolder( m_xContext, this );
107 // parse configuration entries
108 // TODO/LATER: in future UI names can be also provided here
109 for ( beans::NamedValue const & prop : aObjectProps )
111 if ( prop.Name == "ClassID" )
112 prop.Value >>= m_aClassID;
113 else if ( prop.Name == "ObjectDocumentServiceName" )
114 prop.Value >>= m_aDocServiceName;
115 else if ( prop.Name == "ObjectDocumentFilterName" )
116 prop.Value >>= m_aPresetFilterName;
117 else if ( prop.Name == "ObjectMiscStatus" )
118 prop.Value >>= m_nMiscStatus;
119 else if ( prop.Name == "ObjectVerbs" )
120 prop.Value >>= m_aObjectVerbs;
123 if ( m_aClassID.getLength() != 16 /*|| !m_aDocServiceName.getLength()*/ )
124 throw uno::RuntimeException(); // something goes really wrong
126 // accepted states
127 m_aAcceptedStates.realloc( NUM_SUPPORTED_STATES );
129 m_aAcceptedStates[0] = embed::EmbedStates::LOADED;
130 m_aAcceptedStates[1] = embed::EmbedStates::RUNNING;
131 m_aAcceptedStates[2] = embed::EmbedStates::INPLACE_ACTIVE;
132 m_aAcceptedStates[3] = embed::EmbedStates::UI_ACTIVE;
133 m_aAcceptedStates[4] = embed::EmbedStates::ACTIVE;
136 // intermediate states
137 // In the following table the first index points to starting state,
138 // the second one to the target state, and the sequence referenced by
139 // first two indexes contains intermediate states, that should be
140 // passed by object to reach the target state.
141 // If the sequence is empty that means that indirect switch from start
142 // state to the target state is forbidden, only if direct switch is possible
143 // the state can be reached.
145 m_pIntermediateStatesSeqs[0][2].realloc( 1 );
146 m_pIntermediateStatesSeqs[0][2][0] = embed::EmbedStates::RUNNING;
148 m_pIntermediateStatesSeqs[0][3].realloc( 2 );
149 m_pIntermediateStatesSeqs[0][3][0] = embed::EmbedStates::RUNNING;
150 m_pIntermediateStatesSeqs[0][3][1] = embed::EmbedStates::INPLACE_ACTIVE;
152 m_pIntermediateStatesSeqs[0][4].realloc( 1 );
153 m_pIntermediateStatesSeqs[0][4][0] = embed::EmbedStates::RUNNING;
155 m_pIntermediateStatesSeqs[1][3].realloc( 1 );
156 m_pIntermediateStatesSeqs[1][3][0] = embed::EmbedStates::INPLACE_ACTIVE;
158 m_pIntermediateStatesSeqs[2][0].realloc( 1 );
159 m_pIntermediateStatesSeqs[2][0][0] = embed::EmbedStates::RUNNING;
161 m_pIntermediateStatesSeqs[3][0].realloc( 2 );
162 m_pIntermediateStatesSeqs[3][0][0] = embed::EmbedStates::INPLACE_ACTIVE;
163 m_pIntermediateStatesSeqs[3][0][1] = embed::EmbedStates::RUNNING;
165 m_pIntermediateStatesSeqs[3][1].realloc( 1 );
166 m_pIntermediateStatesSeqs[3][1][0] = embed::EmbedStates::INPLACE_ACTIVE;
168 m_pIntermediateStatesSeqs[4][0].realloc( 1 );
169 m_pIntermediateStatesSeqs[4][0][0] = embed::EmbedStates::RUNNING;
171 // verbs table
172 for ( auto const & verb : std::as_const(m_aObjectVerbs) )
174 if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_PRIMARY )
176 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::UI_ACTIVE } );
178 else if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_SHOW )
180 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::UI_ACTIVE } );
182 else if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
184 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::ACTIVE } );
186 else if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_IPACTIVATE )
188 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::INPLACE_ACTIVE } );
190 else if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_UIACTIVATE )
192 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::UI_ACTIVE } );
194 else if ( verb.VerbID == embed::EmbedVerbs::MS_OLEVERB_HIDE )
196 m_aVerbTable.insert( { verb.VerbID, embed::EmbedStates::RUNNING } );
202 void OCommonEmbeddedObject::LinkInit_Impl(
203 const uno::Sequence< beans::NamedValue >& aObjectProps,
204 const uno::Sequence< beans::PropertyValue >& aMediaDescr,
205 const uno::Sequence< beans::PropertyValue >& aObjectDescr )
207 // setPersistance has no effect on own links, so the complete initialization must be done here
209 for ( beans::PropertyValue const & prop : aMediaDescr )
210 if ( prop.Name == "URL" )
211 prop.Value >>= m_aLinkURL;
212 else if ( prop.Name == "FilterName" )
213 prop.Value >>= m_aLinkFilterName;
215 OSL_ENSURE( m_aLinkURL.getLength() && m_aLinkFilterName.getLength(), "Filter and URL must be provided!" );
217 m_bReadOnly = true;
218 if ( m_aLinkFilterName.getLength() )
220 ::comphelper::MimeConfigurationHelper aHelper( m_xContext );
221 OUString aExportFilterName = aHelper.GetExportFilterFromImportFilter( m_aLinkFilterName );
222 m_bReadOnly = aExportFilterName != m_aLinkFilterName;
225 if(m_bIsLinkURL && !m_bReadOnly)
227 // tdf#141529 we have a linked OLE object. To prevent the original OLE
228 // data to be changed each time the OLE gets changed (at deactivate), copy it to
229 // a temporary file. That file will be changed on activated OLE changes then.
230 // The moment the original gets changed itself will now be associated with the
231 // file/document embedding the OLE being changed (see other additions to the
232 // task-ID above)
234 // open OLE original data as read input file
235 uno::Reference< ucb::XSimpleFileAccess3 > xTempAccess( ucb::SimpleFileAccess::create( m_xContext ) );
236 uno::Reference< io::XInputStream > xInStream( xTempAccess->openFileRead( m_aLinkURL ) );
238 if(xInStream.is())
240 // create temporary file
241 m_aLinkTempFile = io::TempFile::create(m_xContext);
243 if(m_aLinkTempFile.is())
245 // completely copy content of original OLE data
246 uno::Reference < io::XOutputStream > xTempOut = m_aLinkTempFile->getOutputStream();
247 ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOut );
248 xTempOut->flush();
249 xTempOut->closeOutput();
251 // reset flag m_bLinkTempFileChanged, so it will also work for multiple
252 // save op's of the containing file/document
253 m_bLinkTempFileChanged = false;
258 if(m_aLinkTempFile.is())
260 uno::Sequence< beans::PropertyValue > aAlternativeMediaDescr(aMediaDescr.getLength());
262 for ( sal_Int32 a(0); a < aMediaDescr.getLength(); a++ )
264 const beans::PropertyValue& rSource(aMediaDescr[a]);
265 beans::PropertyValue& rDestination(aAlternativeMediaDescr[a]);
267 rDestination.Name = rSource.Name;
268 if(rSource.Name == "URL")
269 rDestination.Value <<= m_aLinkTempFile->getUri();
270 else
271 rDestination.Value = rSource.Value;
274 m_aDocMediaDescriptor = GetValuableArgs_Impl( aAlternativeMediaDescr, false );
276 else
278 m_aDocMediaDescriptor = GetValuableArgs_Impl( aMediaDescr, false );
281 uno::Reference< frame::XDispatchProviderInterceptor > xDispatchInterceptor;
282 for ( beans::PropertyValue const & prop : aObjectDescr )
283 if ( prop.Name == "OutplaceDispatchInterceptor" )
285 prop.Value >>= xDispatchInterceptor;
286 break;
288 else if ( prop.Name == "Parent" )
290 prop.Value >>= m_xParent;
293 CommonInit_Impl( aObjectProps );
295 if ( xDispatchInterceptor.is() )
296 m_xDocHolder->SetOutplaceDispatchInterceptor( xDispatchInterceptor );
300 OCommonEmbeddedObject::~OCommonEmbeddedObject()
302 if ( !(m_pInterfaceContainer || m_xDocHolder.is()) )
303 return;
305 osl_atomic_increment(&m_refCount);
306 try {
307 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
309 if ( m_pInterfaceContainer )
311 m_pInterfaceContainer->disposeAndClear( aSource );
313 delete m_pInterfaceContainer;
314 m_pInterfaceContainer = nullptr;
316 } catch( const uno::Exception& ) {}
318 try {
319 if ( m_xDocHolder.is() )
321 m_xDocHolder->CloseFrame();
322 try {
323 m_xDocHolder->CloseDocument( true, true );
324 } catch ( const uno::Exception& ) {}
325 m_xDocHolder->FreeOffice();
327 m_xDocHolder.clear();
329 } catch( const uno::Exception& ) {}
333 void OCommonEmbeddedObject::requestPositioning( const awt::Rectangle& aRect )
335 // the method is called in case object is inplace active and the object window was resized
337 OSL_ENSURE( m_xClientSite.is(), "The client site must be set for inplace active object!" );
338 if ( !m_xClientSite.is() )
339 return;
341 uno::Reference< embed::XInplaceClient > xInplaceClient( m_xClientSite, uno::UNO_QUERY );
343 OSL_ENSURE( xInplaceClient.is(), "The client site must support XInplaceClient to allow inplace activation!" );
344 if ( xInplaceClient.is() )
346 try {
347 xInplaceClient->changedPlacement( aRect );
349 catch( const uno::Exception& )
351 OSL_FAIL( "Exception on request to resize!" );
357 void OCommonEmbeddedObject::PostEvent_Impl( const OUString& aEventName )
359 if ( !m_pInterfaceContainer )
360 return;
362 ::cppu::OInterfaceContainerHelper* pIC = m_pInterfaceContainer->getContainer(
363 cppu::UnoType<document::XEventListener>::get());
364 if( !pIC )
365 return;
367 document::EventObject aEvent;
368 aEvent.EventName = aEventName;
369 aEvent.Source.set( static_cast< ::cppu::OWeakObject* >( this ) );
370 // For now all the events are sent as object events
371 // aEvent.Source = ( xSource.is() ? xSource
372 // : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >( this ) ) );
373 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
374 while( aIt.hasMoreElements() )
378 static_cast<document::XEventListener *>(aIt.next())->notifyEvent( aEvent );
380 catch( const uno::RuntimeException& )
382 aIt.remove();
385 // the listener could dispose the object.
386 if ( m_bDisposed )
387 return;
392 uno::Any SAL_CALL OCommonEmbeddedObject::queryInterface( const uno::Type& rType )
394 uno::Any aReturn;
396 if ( rType == cppu::UnoType<embed::XEmbeddedObject>::get() )
398 void * p = static_cast< embed::XEmbeddedObject * >( this );
399 return uno::Any( &p, rType );
401 else if (rType == cppu::UnoType<embed::XEmbedPersist2>::get())
403 void* p = static_cast<embed::XEmbedPersist2*>(this);
404 return uno::Any(&p, rType);
406 else
407 aReturn = ::cppu::queryInterface(
408 rType,
409 static_cast< embed::XInplaceObject* >( this ),
410 static_cast< embed::XVisualObject* >( this ),
411 static_cast< embed::XCommonEmbedPersist* >( static_cast< embed::XEmbedPersist* >( this ) ),
412 static_cast< embed::XEmbedPersist* >( this ),
413 static_cast< embed::XLinkageSupport* >( this ),
414 static_cast< embed::XStateChangeBroadcaster* >( this ),
415 static_cast< embed::XClassifiedObject* >( this ),
416 static_cast< embed::XComponentSupplier* >( this ),
417 static_cast< util::XCloseable* >( this ),
418 static_cast< container::XChild* >( this ),
419 static_cast< chart2::XDefaultSizeTransmitter* >( this ),
420 static_cast< document::XEventBroadcaster* >( this ) );
422 if ( aReturn.hasValue() )
423 return aReturn;
424 else
425 return ::cppu::OWeakObject::queryInterface( rType ) ;
430 void SAL_CALL OCommonEmbeddedObject::acquire()
431 throw()
433 ::cppu::OWeakObject::acquire() ;
437 void SAL_CALL OCommonEmbeddedObject::release()
438 throw()
440 ::cppu::OWeakObject::release() ;
444 uno::Sequence< sal_Int8 > SAL_CALL OCommonEmbeddedObject::getClassID()
446 if ( m_bDisposed )
447 throw lang::DisposedException();
449 return m_aClassID;
452 OUString SAL_CALL OCommonEmbeddedObject::getClassName()
454 if ( m_bDisposed )
455 throw lang::DisposedException();
457 return m_aClassName;
460 void SAL_CALL OCommonEmbeddedObject::setClassInfo(
461 const uno::Sequence< sal_Int8 >& /*aClassID*/, const OUString& /*aClassName*/ )
463 // the object class info can not be changed explicitly
464 throw lang::NoSupportException(); //TODO:
468 uno::Reference< util::XCloseable > SAL_CALL OCommonEmbeddedObject::getComponent()
470 SolarMutexGuard aGuard;
471 if ( m_bDisposed )
472 throw lang::DisposedException(); // TODO
474 // add an exception
475 if ( m_nObjectState == -1 )
477 // the object is still not loaded
478 throw uno::RuntimeException( "Can't store object without persistence!",
479 static_cast< ::cppu::OWeakObject* >(this) );
482 return m_xDocHolder->GetComponent();
486 void SAL_CALL OCommonEmbeddedObject::addStateChangeListener( const uno::Reference< embed::XStateChangeListener >& xListener )
488 SolarMutexGuard aGuard;
489 if ( m_bDisposed )
490 throw lang::DisposedException(); // TODO
492 if ( !m_pInterfaceContainer )
493 m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper( m_aMutex );
495 m_pInterfaceContainer->addInterface( cppu::UnoType<embed::XStateChangeListener>::get(),
496 xListener );
500 void SAL_CALL OCommonEmbeddedObject::removeStateChangeListener(
501 const uno::Reference< embed::XStateChangeListener >& xListener )
503 SolarMutexGuard aGuard;
504 if ( m_pInterfaceContainer )
505 m_pInterfaceContainer->removeInterface( cppu::UnoType<embed::XStateChangeListener>::get(),
506 xListener );
510 void SAL_CALL OCommonEmbeddedObject::close( sal_Bool bDeliverOwnership )
512 SolarMutexGuard aGuard;
513 if ( m_bClosed )
514 throw lang::DisposedException(); // TODO
516 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >( this ) );
517 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >( this ) );
519 if ( m_pInterfaceContainer )
521 ::cppu::OInterfaceContainerHelper* pContainer =
522 m_pInterfaceContainer->getContainer( cppu::UnoType<util::XCloseListener>::get());
523 if ( pContainer != nullptr )
525 ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
526 while (pIterator.hasMoreElements())
530 static_cast<util::XCloseListener*>(pIterator.next())->queryClosing( aSource, bDeliverOwnership );
532 catch( const uno::RuntimeException& )
534 pIterator.remove();
539 pContainer = m_pInterfaceContainer->getContainer(
540 cppu::UnoType<util::XCloseListener>::get());
541 if ( pContainer != nullptr )
543 ::cppu::OInterfaceIteratorHelper pCloseIterator(*pContainer);
544 while (pCloseIterator.hasMoreElements())
548 static_cast<util::XCloseListener*>(pCloseIterator.next())->notifyClosing( aSource );
550 catch( const uno::RuntimeException& )
552 pCloseIterator.remove();
557 m_pInterfaceContainer->disposeAndClear( aSource );
560 m_bDisposed = true; // the object is disposed now for outside
562 // it is possible that the document can not be closed, in this case if the argument is false
563 // the exception will be thrown otherwise in addition to exception the object must register itself
564 // as termination listener and listen for document events
566 if ( m_xDocHolder.is() )
568 m_xDocHolder->CloseFrame();
570 try {
571 m_xDocHolder->CloseDocument( bDeliverOwnership, bDeliverOwnership );
573 catch( const uno::Exception& )
575 if ( bDeliverOwnership )
577 m_xDocHolder.clear();
578 m_bClosed = true;
581 throw;
584 m_xDocHolder->FreeOffice();
586 m_xDocHolder.clear();
589 // TODO: for now the storage will be disposed by the object, but after the document
590 // will use the storage, the storage will be disposed by the document and recreated by the object
591 if ( m_xObjectStorage.is() )
593 try {
594 m_xObjectStorage->dispose();
595 } catch ( const uno::Exception& ) {}
597 m_xObjectStorage.clear();
598 m_xRecoveryStorage.clear();
601 m_bClosed = true; // the closing succeeded
605 void SAL_CALL OCommonEmbeddedObject::addCloseListener( const uno::Reference< util::XCloseListener >& xListener )
607 SolarMutexGuard aGuard;
608 if ( m_bDisposed )
609 throw lang::DisposedException(); // TODO
611 if ( !m_pInterfaceContainer )
612 m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper(m_aMutex);
614 m_pInterfaceContainer->addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
618 void SAL_CALL OCommonEmbeddedObject::removeCloseListener( const uno::Reference< util::XCloseListener >& xListener )
620 SolarMutexGuard aGuard;
621 if ( m_pInterfaceContainer )
622 m_pInterfaceContainer->removeInterface( cppu::UnoType<util::XCloseListener>::get(),
623 xListener );
627 void SAL_CALL OCommonEmbeddedObject::addEventListener( const uno::Reference< document::XEventListener >& xListener )
629 SolarMutexGuard aGuard;
630 if ( m_bDisposed )
631 throw lang::DisposedException(); // TODO
633 if ( !m_pInterfaceContainer )
634 m_pInterfaceContainer = new ::cppu::OMultiTypeInterfaceContainerHelper(m_aMutex);
636 m_pInterfaceContainer->addInterface( cppu::UnoType<document::XEventListener>::get(), xListener );
640 void SAL_CALL OCommonEmbeddedObject::removeEventListener( const uno::Reference< document::XEventListener >& xListener )
642 SolarMutexGuard aGuard;
643 if ( m_pInterfaceContainer )
644 m_pInterfaceContainer->removeInterface( cppu::UnoType<document::XEventListener>::get(),
645 xListener );
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */