Line data Source code
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 <oleembobj.hxx>
21 : #include <com/sun/star/embed/EmbedStates.hpp>
22 : #include <com/sun/star/embed/EmbedVerbs.hpp>
23 : #include <com/sun/star/embed/EntryInitModes.hpp>
24 : #include <com/sun/star/embed/XStorage.hpp>
25 : #include <com/sun/star/embed/ElementModes.hpp>
26 : #include <com/sun/star/embed/EmbedUpdateModes.hpp>
27 : #include <com/sun/star/embed/Aspects.hpp>
28 : #include <com/sun/star/embed/NeedsRunningStateException.hpp>
29 : #include <com/sun/star/embed/StateChangeInProgressException.hpp>
30 : #include <com/sun/star/embed/EmbedMisc.hpp>
31 : #include <com/sun/star/embed/XEmbedObjectCreator.hpp>
32 : #include <com/sun/star/io/TempFile.hpp>
33 : #include <com/sun/star/io/XSeekable.hpp>
34 : #include <com/sun/star/lang/DisposedException.hpp>
35 : #include <com/sun/star/beans/NamedValue.hpp>
36 : #include <com/sun/star/beans/XPropertySet.hpp>
37 : #include <com/sun/star/frame/XLoadable.hpp>
38 : #include <com/sun/star/document/XStorageBasedDocument.hpp>
39 : #include <com/sun/star/ucb/SimpleFileAccess.hpp>
40 : #include <com/sun/star/container/XNameAccess.hpp>
41 : #include <com/sun/star/container/XNameContainer.hpp>
42 : #include <com/sun/star/system/SystemShellExecute.hpp>
43 : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
44 :
45 : #include <cppuhelper/interfacecontainer.h>
46 : #include <comphelper/processfactory.hxx>
47 : #include <comphelper/mimeconfighelper.hxx>
48 : #include <comphelper/storagehelper.hxx>
49 :
50 :
51 : #include <targetstatecontrol.hxx>
52 :
53 : #include "ownview.hxx"
54 :
55 : #if defined WNT
56 : #include <olecomponent.hxx>
57 : #endif
58 :
59 : using namespace ::com::sun::star;
60 :
61 : #ifdef WNT
62 :
63 : void OleEmbeddedObject::SwitchComponentToRunningState_Impl()
64 : {
65 : if ( m_pOleComponent )
66 : {
67 : try
68 : {
69 : m_pOleComponent->RunObject();
70 : }
71 : catch( const embed::UnreachableStateException& )
72 : {
73 : GetRidOfComponent();
74 : throw;
75 : }
76 : catch( const embed::WrongStateException& )
77 : {
78 : GetRidOfComponent();
79 : throw;
80 : }
81 : }
82 : else
83 : {
84 : throw embed::UnreachableStateException();
85 : }
86 : }
87 :
88 :
89 : uno::Sequence< sal_Int32 > OleEmbeddedObject::GetReachableStatesList_Impl(
90 : const uno::Sequence< embed::VerbDescriptor >& aVerbList )
91 : {
92 : uno::Sequence< sal_Int32 > aStates(2);
93 : aStates[0] = embed::EmbedStates::LOADED;
94 : aStates[1] = embed::EmbedStates::RUNNING;
95 : for ( sal_Int32 nInd = 0; nInd < aVerbList.getLength(); nInd++ )
96 : if ( aVerbList[nInd].VerbID == embed::EmbedVerbs::MS_OLEVERB_OPEN )
97 : {
98 : aStates.realloc(3);
99 : aStates[2] = embed::EmbedStates::ACTIVE;
100 : }
101 :
102 : return aStates;
103 : }
104 :
105 :
106 : uno::Sequence< sal_Int32 > OleEmbeddedObject::GetIntermediateVerbsSequence_Impl( sal_Int32 nNewState )
107 : {
108 : SAL_WARN_IF( m_nObjectState == embed::EmbedStates::LOADED, "embeddedobj.ole", "Loaded object is switched to running state without verbs using!" );
109 :
110 : // actually there will be only one verb
111 : if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
112 : {
113 : uno::Sequence< sal_Int32 > aVerbs( 1 );
114 : aVerbs[0] = embed::EmbedVerbs::MS_OLEVERB_OPEN;
115 : }
116 :
117 : return uno::Sequence< sal_Int32 >();
118 : }
119 : #endif
120 :
121 0 : void OleEmbeddedObject::MoveListeners()
122 : {
123 0 : if ( m_pInterfaceContainer )
124 : {
125 : // move state change listeners
126 : {
127 : ::cppu::OInterfaceContainerHelper* pStateChangeContainer =
128 0 : m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< embed::XStateChangeListener >*) NULL ) );
129 0 : if ( pStateChangeContainer != NULL )
130 : {
131 0 : uno::Reference< embed::XStateChangeBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
132 0 : if ( xWrappedObject.is() )
133 : {
134 0 : ::cppu::OInterfaceIteratorHelper pIterator( *pStateChangeContainer );
135 0 : while ( pIterator.hasMoreElements() )
136 : {
137 : try
138 : {
139 0 : xWrappedObject->addStateChangeListener( (embed::XStateChangeListener*)pIterator.next() );
140 : }
141 0 : catch( const uno::RuntimeException& )
142 : {
143 0 : pIterator.remove();
144 : }
145 0 : }
146 0 : }
147 : }
148 : }
149 :
150 : // move event listeners
151 : {
152 : ::cppu::OInterfaceContainerHelper* pEventContainer =
153 0 : m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< document::XEventListener >*) NULL ) );
154 0 : if ( pEventContainer != NULL )
155 : {
156 0 : uno::Reference< document::XEventBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
157 0 : if ( xWrappedObject.is() )
158 : {
159 0 : ::cppu::OInterfaceIteratorHelper pIterator( *pEventContainer );
160 0 : while ( pIterator.hasMoreElements() )
161 : {
162 : try
163 : {
164 0 : xWrappedObject->addEventListener( (document::XEventListener*)pIterator.next() );
165 : }
166 0 : catch( const uno::RuntimeException& )
167 : {
168 0 : pIterator.remove();
169 : }
170 0 : }
171 0 : }
172 : }
173 : }
174 :
175 : // move close listeners
176 : {
177 : ::cppu::OInterfaceContainerHelper* pCloseContainer =
178 0 : m_pInterfaceContainer->getContainer( ::getCppuType( ( const uno::Reference< util::XCloseListener >*) NULL ) );
179 0 : if ( pCloseContainer != NULL )
180 : {
181 0 : uno::Reference< util::XCloseBroadcaster > xWrappedObject( m_xWrappedObject, uno::UNO_QUERY );
182 0 : if ( xWrappedObject.is() )
183 : {
184 0 : ::cppu::OInterfaceIteratorHelper pIterator( *pCloseContainer );
185 0 : while ( pIterator.hasMoreElements() )
186 : {
187 : try
188 : {
189 0 : xWrappedObject->addCloseListener( (util::XCloseListener*)pIterator.next() );
190 : }
191 0 : catch( const uno::RuntimeException& )
192 : {
193 0 : pIterator.remove();
194 : }
195 0 : }
196 0 : }
197 : }
198 : }
199 :
200 0 : delete m_pInterfaceContainer;
201 0 : m_pInterfaceContainer = NULL;
202 : }
203 0 : }
204 :
205 :
206 0 : uno::Reference< embed::XStorage > OleEmbeddedObject::CreateTemporarySubstorage( OUString& o_aStorageName )
207 : {
208 0 : uno::Reference< embed::XStorage > xResult;
209 :
210 0 : for ( sal_Int32 nInd = 0; nInd < 32000 && !xResult.is(); nInd++ )
211 : {
212 0 : OUString aName = OUString::number( nInd ) + "TMPSTOR" + m_aEntryName;
213 0 : if ( !m_xParentStorage->hasByName( aName ) )
214 : {
215 0 : xResult = m_xParentStorage->openStorageElement( aName, embed::ElementModes::READWRITE );
216 0 : o_aStorageName = aName;
217 : }
218 0 : }
219 :
220 0 : if ( !xResult.is() )
221 : {
222 0 : o_aStorageName = OUString();
223 0 : throw uno::RuntimeException();
224 : }
225 :
226 0 : return xResult;
227 : }
228 :
229 :
230 0 : OUString OleEmbeddedObject::MoveToTemporarySubstream()
231 : {
232 0 : OUString aResult;
233 0 : for ( sal_Int32 nInd = 0; nInd < 32000 && aResult.isEmpty(); nInd++ )
234 : {
235 0 : OUString aName = OUString::number( nInd ) + "TMPSTREAM" + m_aEntryName;
236 0 : if ( !m_xParentStorage->hasByName( aName ) )
237 : {
238 0 : m_xParentStorage->renameElement( m_aEntryName, aName );
239 0 : aResult = aName;
240 : }
241 0 : }
242 :
243 0 : if ( aResult.isEmpty() )
244 0 : throw uno::RuntimeException();
245 :
246 0 : return aResult;
247 : }
248 :
249 :
250 0 : sal_Bool OleEmbeddedObject::TryToConvertToOOo()
251 : {
252 0 : sal_Bool bResult = sal_False;
253 :
254 0 : OUString aStorageName;
255 0 : OUString aTmpStreamName;
256 0 : sal_Int32 nStep = 0;
257 :
258 0 : if ( m_pOleComponent || m_bReadOnly )
259 0 : return sal_False;
260 :
261 : try
262 : {
263 0 : changeState( embed::EmbedStates::LOADED );
264 :
265 : // the stream must be seekable
266 0 : uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY_THROW );
267 0 : xSeekable->seek( 0 );
268 0 : OUString aFilterName = OwnView_Impl::GetFilterNameFromExtentionAndInStream( m_xFactory, OUString(), m_xObjectStream->getInputStream() );
269 :
270 : // use the solution only for OOXML format currently
271 0 : if ( !aFilterName.isEmpty()
272 0 : && ( aFilterName == "Calc MS Excel 2007 XML" || aFilterName == "Impress MS PowerPoint 2007 XML" || aFilterName == "MS Word 2007 XML" ) )
273 : {
274 : uno::Reference< container::XNameAccess > xFilterFactory(
275 0 : m_xFactory->createInstance("com.sun.star.document.FilterFactory"),
276 0 : uno::UNO_QUERY_THROW );
277 :
278 0 : OUString aDocServiceName;
279 0 : uno::Any aFilterAnyData = xFilterFactory->getByName( aFilterName );
280 0 : uno::Sequence< beans::PropertyValue > aFilterData;
281 0 : if ( aFilterAnyData >>= aFilterData )
282 : {
283 0 : for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
284 0 : if ( aFilterData[nInd].Name == "DocumentService" )
285 0 : aFilterData[nInd].Value >>= aDocServiceName;
286 : }
287 :
288 0 : if ( !aDocServiceName.isEmpty() )
289 : {
290 : // create the model
291 0 : uno::Sequence< uno::Any > aArguments(1);
292 0 : aArguments[0] <<= beans::NamedValue( OUString( "EmbeddedObject" ), uno::makeAny( (sal_Bool)sal_True ));
293 :
294 0 : uno::Reference< util::XCloseable > xDocument( m_xFactory->createInstanceWithArguments( aDocServiceName, aArguments ), uno::UNO_QUERY_THROW );
295 0 : uno::Reference< frame::XLoadable > xLoadable( xDocument, uno::UNO_QUERY_THROW );
296 0 : uno::Reference< document::XStorageBasedDocument > xStorDoc( xDocument, uno::UNO_QUERY_THROW );
297 :
298 : // let the model behave as embedded one
299 0 : uno::Reference< frame::XModel > xModel( xDocument, uno::UNO_QUERY_THROW );
300 0 : uno::Sequence< beans::PropertyValue > aSeq( 1 );
301 0 : aSeq[0].Name = "SetEmbedded";
302 0 : aSeq[0].Value <<= sal_True;
303 0 : xModel->attachResource( OUString(), aSeq );
304 :
305 : // load the model from the stream
306 0 : uno::Sequence< beans::PropertyValue > aArgs( 5 );
307 0 : aArgs[0].Name = "HierarchicalDocumentName";
308 0 : aArgs[0].Value <<= m_aEntryName;
309 0 : aArgs[1].Name = "ReadOnly";
310 0 : aArgs[1].Value <<= sal_True;
311 0 : aArgs[2].Name = "FilterName";
312 0 : aArgs[2].Value <<= aFilterName;
313 0 : aArgs[3].Name = "URL";
314 0 : aArgs[3].Value <<= OUString( "private:stream" );
315 0 : aArgs[4].Name = "InputStream";
316 0 : aArgs[4].Value <<= m_xObjectStream->getInputStream();
317 :
318 0 : xSeekable->seek( 0 );
319 0 : xLoadable->load( aArgs );
320 :
321 : // the model is successfully loaded, create a new storage and store the model to the storage
322 0 : uno::Reference< embed::XStorage > xTmpStorage = CreateTemporarySubstorage( aStorageName );
323 0 : xStorDoc->storeToStorage( xTmpStorage, uno::Sequence< beans::PropertyValue >() );
324 0 : xDocument->close( sal_True );
325 0 : uno::Reference< beans::XPropertySet > xStorProps( xTmpStorage, uno::UNO_QUERY_THROW );
326 0 : OUString aMediaType;
327 0 : xStorProps->getPropertyValue("MediaType") >>= aMediaType;
328 0 : xTmpStorage->dispose();
329 :
330 : // look for the related embedded object factory
331 0 : ::comphelper::MimeConfigurationHelper aConfigHelper( comphelper::getComponentContext(m_xFactory) );
332 0 : OUString aEmbedFactory;
333 0 : if ( !aMediaType.isEmpty() )
334 0 : aEmbedFactory = aConfigHelper.GetFactoryNameByMediaType( aMediaType );
335 :
336 0 : if ( aEmbedFactory.isEmpty() )
337 0 : throw uno::RuntimeException();
338 :
339 0 : uno::Reference< uno::XInterface > xFact = m_xFactory->createInstance( aEmbedFactory );
340 :
341 0 : uno::Reference< embed::XEmbedObjectCreator > xEmbCreator( xFact, uno::UNO_QUERY_THROW );
342 :
343 : // now the object should be adjusted to become the wrapper
344 0 : nStep = 1;
345 0 : uno::Reference< lang::XComponent > xComp( m_xObjectStream, uno::UNO_QUERY_THROW );
346 0 : xComp->dispose();
347 0 : m_xObjectStream = uno::Reference< io::XStream >();
348 0 : m_nObjectState = -1;
349 :
350 0 : nStep = 2;
351 0 : aTmpStreamName = MoveToTemporarySubstream();
352 :
353 0 : nStep = 3;
354 0 : m_xParentStorage->renameElement( aStorageName, m_aEntryName );
355 :
356 0 : nStep = 4;
357 0 : m_xWrappedObject.set( xEmbCreator->createInstanceInitFromEntry( m_xParentStorage, m_aEntryName, uno::Sequence< beans::PropertyValue >(), uno::Sequence< beans::PropertyValue >() ), uno::UNO_QUERY_THROW );
358 :
359 0 : bResult = sal_True; // the change is no more revertable
360 : try
361 : {
362 0 : m_xParentStorage->removeElement( aTmpStreamName );
363 : }
364 0 : catch( const uno::Exception& )
365 : {
366 : // the success of the removing is not so important
367 0 : }
368 0 : }
369 0 : }
370 : }
371 0 : catch( const uno::Exception& )
372 : {
373 : // repair the object if necessary
374 0 : switch( nStep )
375 : {
376 : case 4:
377 : case 3:
378 0 : if ( !aTmpStreamName.isEmpty() && aTmpStreamName != m_aEntryName )
379 : try
380 : {
381 0 : if ( m_xParentStorage->hasByName( m_aEntryName ) )
382 0 : m_xParentStorage->removeElement( m_aEntryName );
383 0 : m_xParentStorage->renameElement( aTmpStreamName, m_aEntryName );
384 : }
385 0 : catch ( const uno::Exception& )
386 : {
387 : try {
388 0 : close( sal_True );
389 0 : } catch( const uno::Exception& ) {}
390 :
391 0 : m_xParentStorage->dispose(); // ??? the storage has information loss, it should be closed without commiting!
392 0 : throw uno::RuntimeException(); // the repairing is not possible
393 : }
394 : case 2:
395 : try
396 : {
397 0 : m_xObjectStream = m_xParentStorage->openStreamElement( m_aEntryName, m_bReadOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
398 0 : m_nObjectState = embed::EmbedStates::LOADED;
399 : }
400 0 : catch( const uno::Exception& )
401 : {
402 : try {
403 0 : close( sal_True );
404 0 : } catch( const uno::Exception& ) {}
405 :
406 0 : throw uno::RuntimeException(); // the repairing is not possible
407 : }
408 : // no break as designed!
409 :
410 : case 1:
411 : case 0:
412 0 : if ( !aStorageName.isEmpty() )
413 : try {
414 0 : m_xParentStorage->removeElement( aStorageName );
415 0 : } catch( const uno::Exception& ) { SAL_WARN( "embeddedobj.ole", "Can not remove temporary storage!" ); }
416 0 : break;
417 : }
418 : }
419 :
420 0 : if ( bResult )
421 : {
422 : // the conversion was done successfully, now the additional initializations should happen
423 :
424 0 : MoveListeners();
425 0 : m_xWrappedObject->setClientSite( m_xClientSite );
426 0 : if ( m_xParent.is() )
427 : {
428 0 : uno::Reference< container::XChild > xChild( m_xWrappedObject, uno::UNO_QUERY );
429 0 : if ( xChild.is() )
430 0 : xChild->setParent( m_xParent );
431 : }
432 :
433 : }
434 :
435 0 : return bResult;
436 : }
437 :
438 :
439 0 : void SAL_CALL OleEmbeddedObject::changeState( sal_Int32 nNewState )
440 : throw ( embed::UnreachableStateException,
441 : embed::WrongStateException,
442 : uno::Exception,
443 : uno::RuntimeException, std::exception )
444 : {
445 : SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::changeState" );
446 :
447 : // begin wrapping related part ====================
448 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
449 0 : if ( xWrappedObject.is() )
450 : {
451 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
452 0 : xWrappedObject->changeState( nNewState );
453 0 : return;
454 : }
455 : // end wrapping related part ====================
456 :
457 0 : ::osl::ResettableMutexGuard aGuard( m_aMutex );
458 :
459 0 : if ( m_bDisposed )
460 0 : throw lang::DisposedException(); // TODO
461 :
462 0 : if ( m_nObjectState == -1 )
463 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
464 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
465 :
466 : // in case the object is already in requested state
467 0 : if ( m_nObjectState == nNewState )
468 0 : return;
469 :
470 : #ifdef WNT
471 : if ( m_pOleComponent )
472 : {
473 : if ( m_nTargetState != -1 )
474 : {
475 : // means that the object is currently trying to reach the target state
476 : throw embed::StateChangeInProgressException( OUString(),
477 : uno::Reference< uno::XInterface >(),
478 : m_nTargetState );
479 : }
480 :
481 : TargetStateControl_Impl aControl( m_nTargetState, nNewState );
482 :
483 : // TODO: additional verbs can be a problem, since nobody knows how the object
484 : // will behave after activation
485 :
486 : sal_Int32 nOldState = m_nObjectState;
487 : aGuard.clear();
488 : StateChangeNotification_Impl( sal_True, nOldState, nNewState );
489 : aGuard.reset();
490 :
491 : try
492 : {
493 : if ( nNewState == embed::EmbedStates::LOADED )
494 : {
495 : // This means just closing of the current object
496 : // If component can not be closed the object stays in loaded state
497 : // and it holds reference to "incomplete" component
498 : // If the object is switched to running state later
499 : // the component will become "complete"
500 :
501 : // the loaded state must be set before, because of notifications!
502 : m_nObjectState = nNewState;
503 :
504 : {
505 : VerbExecutionControllerGuard aVerbGuard( m_aVerbExecutionController );
506 : m_pOleComponent->CloseObject();
507 : }
508 :
509 : aGuard.clear();
510 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
511 : aGuard.reset();
512 : }
513 : else if ( nNewState == embed::EmbedStates::RUNNING || nNewState == embed::EmbedStates::ACTIVE )
514 : {
515 : if ( m_nObjectState == embed::EmbedStates::LOADED )
516 : {
517 : // if the target object is in loaded state and a different state is specified
518 : // as a new one the object first must be switched to running state.
519 :
520 : // the component can exist already in nonrunning state
521 : // it can be created during loading to detect type of object
522 : CreateOleComponentAndLoad_Impl( m_pOleComponent );
523 :
524 : SwitchComponentToRunningState_Impl();
525 : m_nObjectState = embed::EmbedStates::RUNNING;
526 : aGuard.clear();
527 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
528 : aGuard.reset();
529 :
530 : if ( m_pOleComponent && m_bHasSizeToSet )
531 : {
532 : aGuard.clear();
533 : try {
534 : m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
535 : m_bHasSizeToSet = sal_False;
536 : }
537 : catch( const uno::Exception& ) {}
538 : aGuard.reset();
539 : }
540 :
541 : if ( m_nObjectState == nNewState )
542 : return;
543 : }
544 :
545 : // so now the object is either switched from Active to Running state or vise versa
546 : // the notification about object state change will be done asynchronously
547 : if ( m_nObjectState == embed::EmbedStates::RUNNING && nNewState == embed::EmbedStates::ACTIVE )
548 : {
549 : // execute OPEN verb, if object does not reach active state it is an object's problem
550 : aGuard.clear();
551 : m_pOleComponent->ExecuteVerb( embed::EmbedVerbs::MS_OLEVERB_OPEN );
552 : aGuard.reset();
553 :
554 : // some objects do not allow to set the size even in running state
555 : if ( m_pOleComponent && m_bHasSizeToSet )
556 : {
557 : aGuard.clear();
558 : try {
559 : m_pOleComponent->SetExtent( m_aSizeToSet, m_nAspectToSet );
560 : m_bHasSizeToSet = sal_False;
561 : }
562 : catch( uno::Exception& ) {}
563 : aGuard.reset();
564 : }
565 :
566 : m_nObjectState = nNewState;
567 : }
568 : else if ( m_nObjectState == embed::EmbedStates::ACTIVE && nNewState == embed::EmbedStates::RUNNING )
569 : {
570 : aGuard.clear();
571 : m_pOleComponent->CloseObject();
572 : m_pOleComponent->RunObject(); // Should not fail, the object already was active
573 : aGuard.reset();
574 : m_nObjectState = nNewState;
575 : }
576 : else
577 : {
578 : throw embed::UnreachableStateException();
579 : }
580 : }
581 : else
582 : throw embed::UnreachableStateException();
583 : }
584 : catch( uno::Exception& )
585 : {
586 : aGuard.clear();
587 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
588 : throw;
589 : }
590 : }
591 : else
592 : #endif
593 : {
594 0 : throw embed::UnreachableStateException();
595 0 : }
596 : }
597 :
598 :
599 0 : uno::Sequence< sal_Int32 > SAL_CALL OleEmbeddedObject::getReachableStates()
600 : throw ( embed::WrongStateException,
601 : uno::RuntimeException, std::exception )
602 : {
603 : SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::getReachableStates" );
604 :
605 : // begin wrapping related part ====================
606 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
607 0 : if ( xWrappedObject.is() )
608 : {
609 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
610 0 : return xWrappedObject->getReachableStates();
611 : }
612 : // end wrapping related part ====================
613 :
614 0 : ::osl::MutexGuard aGuard( m_aMutex );
615 0 : if ( m_bDisposed )
616 0 : throw lang::DisposedException(); // TODO
617 :
618 0 : if ( m_nObjectState == -1 )
619 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
620 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
621 :
622 : #ifdef WNT
623 : if ( m_pOleComponent )
624 : {
625 : if ( m_nObjectState == embed::EmbedStates::LOADED )
626 : {
627 : // the list of supported verbs can be retrieved only when object is in running state
628 : throw embed::NeedsRunningStateException(); // TODO:
629 : }
630 :
631 : // the list of states can only be guessed based on standard verbs,
632 : // since there is no way to detect what additional verbs do
633 : return GetReachableStatesList_Impl( m_pOleComponent->GetVerbList() );
634 : }
635 : else
636 : #endif
637 : {
638 0 : return uno::Sequence< sal_Int32 >();
639 0 : }
640 : }
641 :
642 :
643 0 : sal_Int32 SAL_CALL OleEmbeddedObject::getCurrentState()
644 : throw ( embed::WrongStateException,
645 : uno::RuntimeException, std::exception )
646 : {
647 : // begin wrapping related part ====================
648 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
649 0 : if ( xWrappedObject.is() )
650 : {
651 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
652 0 : return xWrappedObject->getCurrentState();
653 : }
654 : // end wrapping related part ====================
655 :
656 0 : ::osl::MutexGuard aGuard( m_aMutex );
657 0 : if ( m_bDisposed )
658 0 : throw lang::DisposedException(); // TODO
659 :
660 0 : if ( m_nObjectState == -1 )
661 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
662 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
663 :
664 : // TODO: Shouldn't we ask object? ( I guess no )
665 0 : return m_nObjectState;
666 : }
667 :
668 : namespace
669 : {
670 0 : bool lcl_CopyStream(uno::Reference<io::XInputStream> xIn, uno::Reference<io::XOutputStream> xOut)
671 : {
672 0 : const sal_Int32 nChunkSize = 4096;
673 0 : uno::Sequence< sal_Int8 > aData(nChunkSize);
674 0 : sal_Int32 nTotalRead = 0;
675 : sal_Int32 nRead;
676 0 : do
677 : {
678 0 : nRead = xIn->readBytes(aData, nChunkSize);
679 0 : nTotalRead += nRead;
680 0 : xOut->writeBytes(aData);
681 : } while (nRead == nChunkSize);
682 0 : return nTotalRead != 0;
683 : }
684 :
685 : //Dump the objects content to a tempfile, just the "CONTENTS" stream if
686 : //there is one for non-compound documents, otherwise the whole content.
687 : //On success a file is returned which must be removed by the caller
688 0 : OUString lcl_ExtractObject(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xFactory,
689 : ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > xObjectStream)
690 : {
691 0 : OUString sUrl;
692 :
693 : // the solution is only active for Unix systems
694 : #ifndef WNT
695 : uno::Reference <beans::XPropertySet> xNativeTempFile(
696 : io::TempFile::create(comphelper::getComponentContext(xFactory)),
697 0 : uno::UNO_QUERY_THROW);
698 0 : uno::Reference < io::XStream > xStream(xNativeTempFile, uno::UNO_QUERY_THROW);
699 :
700 0 : uno::Sequence< uno::Any > aArgs( 2 );
701 0 : aArgs[0] <<= xObjectStream;
702 0 : aArgs[1] <<= (sal_Bool)sal_True; // do not create copy
703 : uno::Reference< container::XNameContainer > xNameContainer(
704 0 : xFactory->createInstanceWithArguments(
705 : OUString("com.sun.star.embed.OLESimpleStorage"),
706 0 : aArgs ), uno::UNO_QUERY_THROW );
707 :
708 0 : uno::Reference< io::XStream > xCONTENTS;
709 : try
710 : {
711 0 : xNameContainer->getByName("CONTENTS") >>= xCONTENTS;
712 : }
713 0 : catch (container::NoSuchElementException const&)
714 : {
715 : // ignore
716 : }
717 :
718 0 : sal_Bool bCopied = xCONTENTS.is() && lcl_CopyStream(xCONTENTS->getInputStream(), xStream->getOutputStream());
719 :
720 0 : uno::Reference< io::XSeekable > xSeekableStor(xObjectStream, uno::UNO_QUERY);
721 0 : if (xSeekableStor.is())
722 0 : xSeekableStor->seek(0);
723 :
724 0 : if (!bCopied)
725 0 : bCopied = lcl_CopyStream(xObjectStream->getInputStream(), xStream->getOutputStream());
726 :
727 0 : if (bCopied)
728 : {
729 0 : xNativeTempFile->setPropertyValue("RemoveFile",
730 0 : uno::makeAny(sal_False));
731 0 : uno::Any aUrl = xNativeTempFile->getPropertyValue("Uri");
732 0 : aUrl >>= sUrl;
733 :
734 0 : xNativeTempFile = uno::Reference<beans::XPropertySet>();
735 :
736 : uno::Reference < ucb::XSimpleFileAccess3 > xSimpleFileAccess(
737 0 : ucb::SimpleFileAccess::create( comphelper::getComponentContext(xFactory) ) );
738 :
739 0 : xSimpleFileAccess->setReadOnly(sUrl, sal_True);
740 : }
741 : else
742 : {
743 0 : xNativeTempFile->setPropertyValue("RemoveFile",
744 0 : uno::makeAny(sal_True));
745 : }
746 : #else
747 : (void) xFactory;
748 : (void) xObjectStream;
749 : #endif
750 0 : return sUrl;
751 : }
752 : }
753 :
754 :
755 0 : void SAL_CALL OleEmbeddedObject::doVerb( sal_Int32 nVerbID )
756 : throw ( lang::IllegalArgumentException,
757 : embed::WrongStateException,
758 : embed::UnreachableStateException,
759 : uno::Exception,
760 : uno::RuntimeException, std::exception )
761 : {
762 : SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::doVerb" );
763 :
764 : // begin wrapping related part ====================
765 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
766 0 : if ( xWrappedObject.is() )
767 : {
768 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
769 0 : xWrappedObject->doVerb( nVerbID );
770 0 : return;
771 : }
772 : // end wrapping related part ====================
773 :
774 0 : ::osl::ResettableMutexGuard aGuard( m_aMutex );
775 0 : if ( m_bDisposed )
776 0 : throw lang::DisposedException(); // TODO
777 :
778 0 : if ( m_nObjectState == -1 )
779 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
780 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
781 :
782 : #ifdef WNT
783 : if ( m_pOleComponent )
784 : {
785 : sal_Int32 nOldState = m_nObjectState;
786 :
787 : // TODO/LATER detect target state here and do a notification
788 : // StateChangeNotification_Impl( sal_True, nOldState, nNewState );
789 : if ( m_nObjectState == embed::EmbedStates::LOADED )
790 : {
791 : // if the target object is in loaded state
792 : // it must be switched to running state to execute verb
793 : aGuard.clear();
794 : changeState( embed::EmbedStates::RUNNING );
795 : aGuard.reset();
796 : }
797 :
798 : try {
799 : if ( !m_pOleComponent )
800 : throw uno::RuntimeException();
801 :
802 : // ==== the STAMPIT related solution =============================
803 : m_aVerbExecutionController.StartControlExecution();
804 :
805 :
806 : m_pOleComponent->ExecuteVerb( nVerbID );
807 :
808 : // ==== the STAMPIT related solution =============================
809 : sal_Bool bModifiedOnExecution = m_aVerbExecutionController.EndControlExecution_WasModified();
810 :
811 : // this workaround is implemented for STAMPIT object
812 : // if object was modified during verb execution it is saved here
813 : if ( bModifiedOnExecution && m_pOleComponent->IsDirty() )
814 : SaveObject_Impl();
815 :
816 : }
817 : catch( uno::Exception& )
818 : {
819 : // ==== the STAMPIT related solution =============================
820 : m_aVerbExecutionController.EndControlExecution_WasModified();
821 :
822 :
823 : aGuard.clear();
824 : StateChangeNotification_Impl( sal_False, nOldState, m_nObjectState );
825 : throw;
826 : }
827 :
828 : }
829 : else
830 : #endif
831 : {
832 0 : if ( nVerbID == -9 )
833 : {
834 : // the workaround verb to show the object in case no server is available
835 :
836 : // if it is possible, the object will be converted to OOo format
837 0 : if ( !m_bTriedConversion )
838 : {
839 0 : m_bTriedConversion = sal_True;
840 0 : if ( TryToConvertToOOo() )
841 : {
842 0 : changeState( embed::EmbedStates::UI_ACTIVE );
843 0 : return;
844 : }
845 : }
846 :
847 0 : if ( !m_pOwnView && m_xObjectStream.is() )
848 : {
849 : try {
850 0 : uno::Reference< io::XSeekable > xSeekable( m_xObjectStream, uno::UNO_QUERY );
851 0 : if ( xSeekable.is() )
852 0 : xSeekable->seek( 0 );
853 :
854 0 : m_pOwnView = new OwnView_Impl( m_xFactory, m_xObjectStream->getInputStream() );
855 0 : m_pOwnView->acquire();
856 : }
857 0 : catch( uno::RuntimeException& )
858 : {
859 0 : throw;
860 : }
861 0 : catch (uno::Exception const& e)
862 : {
863 : SAL_WARN("embeddedobj.ole", "OleEmbeddedObject::doVerb: "
864 : "-9 fallback path: exception caught: " << e.Message);
865 : }
866 : }
867 :
868 0 : if ( !m_pOwnView || !m_pOwnView->Open() )
869 : {
870 : //Make a RO copy and see if the OS can find something to at
871 : //least display the content for us
872 0 : if (m_aTempDumpURL.isEmpty())
873 0 : m_aTempDumpURL = lcl_ExtractObject(m_xFactory, m_xObjectStream);
874 :
875 0 : if (!m_aTempDumpURL.isEmpty())
876 : {
877 : uno::Reference< ::com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
878 0 : ::com::sun::star::system::SystemShellExecute::create(comphelper::getComponentContext(m_xFactory)) );
879 0 : xSystemShellExecute->execute(m_aTempDumpURL, OUString(), ::com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY);
880 : }
881 : else
882 0 : throw embed::UnreachableStateException();
883 : }
884 : }
885 : else
886 : {
887 :
888 0 : throw embed::UnreachableStateException();
889 : }
890 0 : }
891 : }
892 :
893 :
894 0 : uno::Sequence< embed::VerbDescriptor > SAL_CALL OleEmbeddedObject::getSupportedVerbs()
895 : throw ( embed::WrongStateException,
896 : uno::RuntimeException, std::exception )
897 : {
898 : SAL_INFO( "embeddedobj.ole", "embeddedobj (mv76033) OleEmbeddedObject::getSupportedVerb" );
899 :
900 : // begin wrapping related part ====================
901 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
902 0 : if ( xWrappedObject.is() )
903 : {
904 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
905 0 : return xWrappedObject->getSupportedVerbs();
906 : }
907 : // end wrapping related part ====================
908 :
909 0 : ::osl::MutexGuard aGuard( m_aMutex );
910 0 : if ( m_bDisposed )
911 0 : throw lang::DisposedException(); // TODO
912 :
913 0 : if ( m_nObjectState == -1 )
914 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
915 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
916 : #ifdef WNT
917 : if ( m_pOleComponent )
918 : {
919 : // registry could be used in this case
920 : // if ( m_nObjectState == embed::EmbedStates::LOADED )
921 : // {
922 : // // the list of supported verbs can be retrieved only when object is in running state
923 : // throw embed::NeedsRunningStateException(); // TODO:
924 : // }
925 :
926 : return m_pOleComponent->GetVerbList();
927 : }
928 : else
929 : #endif
930 : {
931 0 : return uno::Sequence< embed::VerbDescriptor >();
932 0 : }
933 : }
934 :
935 :
936 0 : void SAL_CALL OleEmbeddedObject::setClientSite(
937 : const uno::Reference< embed::XEmbeddedClient >& xClient )
938 : throw ( embed::WrongStateException,
939 : uno::RuntimeException, std::exception )
940 : {
941 : // begin wrapping related part ====================
942 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
943 0 : if ( xWrappedObject.is() )
944 : {
945 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
946 0 : xWrappedObject->setClientSite( xClient );
947 0 : return;
948 : }
949 : // end wrapping related part ====================
950 :
951 0 : ::osl::MutexGuard aGuard( m_aMutex );
952 0 : if ( m_bDisposed )
953 0 : throw lang::DisposedException(); // TODO
954 :
955 0 : if ( m_xClientSite != xClient)
956 : {
957 0 : if ( m_nObjectState != embed::EmbedStates::LOADED && m_nObjectState != embed::EmbedStates::RUNNING )
958 : throw embed::WrongStateException(
959 : OUString( "The client site can not be set currently!\n" ),
960 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
961 :
962 0 : m_xClientSite = xClient;
963 0 : }
964 : }
965 :
966 :
967 0 : uno::Reference< embed::XEmbeddedClient > SAL_CALL OleEmbeddedObject::getClientSite()
968 : throw ( embed::WrongStateException,
969 : uno::RuntimeException, std::exception )
970 : {
971 : // begin wrapping related part ====================
972 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
973 0 : if ( xWrappedObject.is() )
974 : {
975 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
976 0 : return xWrappedObject->getClientSite();
977 : }
978 : // end wrapping related part ====================
979 :
980 0 : ::osl::MutexGuard aGuard( m_aMutex );
981 0 : if ( m_bDisposed )
982 0 : throw lang::DisposedException(); // TODO
983 :
984 0 : if ( m_nObjectState == -1 )
985 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
986 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
987 :
988 0 : return m_xClientSite;
989 : }
990 :
991 :
992 0 : void SAL_CALL OleEmbeddedObject::update()
993 : throw ( embed::WrongStateException,
994 : uno::Exception,
995 : uno::RuntimeException, std::exception )
996 : {
997 : // begin wrapping related part ====================
998 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
999 0 : if ( xWrappedObject.is() )
1000 : {
1001 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1002 0 : xWrappedObject->update();
1003 0 : return;
1004 : }
1005 : // end wrapping related part ====================
1006 :
1007 0 : ::osl::MutexGuard aGuard( m_aMutex );
1008 0 : if ( m_bDisposed )
1009 0 : throw lang::DisposedException(); // TODO
1010 :
1011 0 : if ( m_nObjectState == -1 )
1012 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
1013 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1014 :
1015 0 : if ( m_nUpdateMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE )
1016 : {
1017 : // TODO: update view representation
1018 : }
1019 : else
1020 : {
1021 : // the object must be up to date
1022 : SAL_WARN_IF( m_nUpdateMode != embed::EmbedUpdateModes::ALWAYS_UPDATE, "embeddedobj.ole", "Unknown update mode!" );
1023 0 : }
1024 : }
1025 :
1026 :
1027 0 : void SAL_CALL OleEmbeddedObject::setUpdateMode( sal_Int32 nMode )
1028 : throw ( embed::WrongStateException,
1029 : uno::RuntimeException, std::exception )
1030 : {
1031 : // begin wrapping related part ====================
1032 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1033 0 : if ( xWrappedObject.is() )
1034 : {
1035 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1036 0 : xWrappedObject->setUpdateMode( nMode );
1037 0 : return;
1038 : }
1039 : // end wrapping related part ====================
1040 :
1041 0 : ::osl::MutexGuard aGuard( m_aMutex );
1042 0 : if ( m_bDisposed )
1043 0 : throw lang::DisposedException(); // TODO
1044 :
1045 0 : if ( m_nObjectState == -1 )
1046 : throw embed::WrongStateException( OUString( "The object has no persistence!\n" ),
1047 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1048 :
1049 : OSL_ENSURE( nMode == embed::EmbedUpdateModes::ALWAYS_UPDATE
1050 : || nMode == embed::EmbedUpdateModes::EXPLICIT_UPDATE,
1051 : "Unknown update mode!\n" );
1052 0 : m_nUpdateMode = nMode;
1053 : }
1054 :
1055 :
1056 0 : sal_Int64 SAL_CALL OleEmbeddedObject::getStatus( sal_Int64
1057 : nAspect
1058 : )
1059 : throw ( embed::WrongStateException,
1060 : uno::RuntimeException, std::exception )
1061 : {
1062 : // begin wrapping related part ====================
1063 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1064 0 : if ( xWrappedObject.is() )
1065 : {
1066 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1067 0 : return xWrappedObject->getStatus( nAspect );
1068 : }
1069 : // end wrapping related part ====================
1070 :
1071 0 : ::osl::MutexGuard aGuard( m_aMutex );
1072 0 : if ( m_bDisposed )
1073 0 : throw lang::DisposedException(); // TODO
1074 :
1075 0 : if ( m_nObjectState == -1 )
1076 : throw embed::WrongStateException( OUString( "The object must be in running state!\n" ),
1077 0 : uno::Reference< uno::XInterface >( static_cast< ::cppu::OWeakObject* >(this) ) );
1078 :
1079 0 : sal_Int64 nResult = 0;
1080 :
1081 : #ifdef WNT
1082 : if ( m_bGotStatus && m_nStatusAspect == nAspect )
1083 : nResult = m_nStatus;
1084 : else if ( m_pOleComponent )
1085 : {
1086 :
1087 : m_nStatus = m_pOleComponent->GetMiscStatus( nAspect );
1088 : m_nStatusAspect = nAspect;
1089 : m_bGotStatus = sal_True;
1090 : nResult = m_nStatus;
1091 : }
1092 : #endif
1093 :
1094 : // this implementation needs size to be provided after object loading/creating to work in optimal way
1095 0 : return ( nResult | embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD );
1096 : }
1097 :
1098 :
1099 0 : void SAL_CALL OleEmbeddedObject::setContainerName( const OUString& sName )
1100 : throw ( uno::RuntimeException, std::exception )
1101 : {
1102 : // begin wrapping related part ====================
1103 0 : uno::Reference< embed::XEmbeddedObject > xWrappedObject = m_xWrappedObject;
1104 0 : if ( xWrappedObject.is() )
1105 : {
1106 : // the object was converted to OOo embedded object, the current implementation is now only a wrapper
1107 0 : xWrappedObject->setContainerName( sName );
1108 0 : return;
1109 : }
1110 : // end wrapping related part ====================
1111 :
1112 0 : ::osl::MutexGuard aGuard( m_aMutex );
1113 0 : if ( m_bDisposed )
1114 0 : throw lang::DisposedException(); // TODO
1115 :
1116 0 : m_aContainerName = sName;
1117 : }
1118 :
1119 :
1120 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|