rendered paste body/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * <http://www.openoffice.org/license.html> * for a copy of the LGPLv3 License. * ************************************************************************/// MARKER(update_precomp.py): autogen include statement, do not remove#include "precompiled_desktop.hxx"#include <sfx2/docfile.hxx>#include <sfx2/docfilt.hxx>#include <sfx2/fcontnr.hxx>#include "osl/file.hxx"#include <svl/fstathelper.hxx>#include "dispatchwatcher.hxx"#include <rtl/ustring.hxx>#include <tools/string.hxx>#include <comphelper/processfactory.hxx>#include <comphelper/synchronousdispatch.hxx>#include <com/sun/star/util/XCloseable.hpp>#include <com/sun/star/util/CloseVetoException.hpp>#include <com/sun/star/task/XInteractionHandler.hpp>#include <com/sun/star/util/URL.hpp>#include <com/sun/star/frame/XDesktop.hpp>#include <com/sun/star/container/XEnumeration.hpp>#include <com/sun/star/frame/XFramesSupplier.hpp>#include <com/sun/star/frame/XDispatch.hpp>#include <com/sun/star/frame/XComponentLoader.hpp>#include <com/sun/star/beans/PropertyValue.hpp>#include <com/sun/star/view/XPrintable.hpp>#include <com/sun/star/frame/XDispatchProvider.hpp>#include <com/sun/star/util/XURLTransformer.hpp>#include <com/sun/star/document/MacroExecMode.hpp>#include <com/sun/star/document/UpdateDocMode.hpp>#include <com/sun/star/frame/XStorable.hpp>#include <tools/urlobj.hxx>#include <comphelper/mediadescriptor.hxx>#include <vector>#include <osl/thread.hxx>namespace{static void impl_sleep( sal_uInt32 nSec ){ TimeValue aTime; aTime.Seconds = nSec; aTime.Nanosec = 0; osl::Thread::wait( aTime );}}using ::rtl::OUString;using namespace ::osl;using namespace ::com::sun::star::uno;using namespace ::com::sun::star::util;using namespace ::com::sun::star::lang;using namespace ::com::sun::star::frame;using namespace ::com::sun::star::container;using namespace ::com::sun::star::beans;using namespace ::com::sun::star::view;namespace desktop{String GetURL_Impl( const String& rName, boost::optional< rtl::OUString > const & cwdUrl );struct DispatchHolder{ DispatchHolder( const URL& rURL, Reference< XDispatch >& rDispatch ) : aURL( rURL ), xDispatch( rDispatch ) {} URL aURL; rtl::OUString cwdUrl; Reference< XDispatch > xDispatch;};static String impl_GetFilterFromExt( OUString aUrl, SfxFilterFlags nFlags, String aAppl ){ String aFilter; SfxMedium* pMedium = new SfxMedium( aUrl, STREAM_STD_READ, FALSE ); const SfxFilter *pSfxFilter = NULL; SfxFilterMatcher aMatcher; if( nFlags == SFX_FILTER_EXPORT ) aMatcher = SfxFilterMatcher( aAppl ); aMatcher.GuessFilterIgnoringContent( *pMedium, &pSfxFilter, nFlags, 0 ); if( pSfxFilter ) aFilter = ( nFlags == SFX_FILTER_EXPORT ) ? pSfxFilter->GetFilterName() : pSfxFilter->GetServiceName(); delete pMedium; return aFilter;}static OUString impl_GuessFilter( OUString aUrlIn, OUString aUrlOut ){ /* aAppl can also be set to Factory like scalc, swriter... */ String aAppl; aAppl = impl_GetFilterFromExt( aUrlIn, SFX_FILTER_IMPORT, aAppl ); return impl_GetFilterFromExt( aUrlOut, SFX_FILTER_EXPORT, aAppl );}Mutex* DispatchWatcher::pWatcherMutex = NULL;Mutex& DispatchWatcher::GetMutex(){ if ( !pWatcherMutex ) { ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); if ( !pWatcherMutex ) pWatcherMutex = new osl::Mutex(); } return *pWatcherMutex;}// Create or get the dispatch watcher implementation. This implementation must be // a singleton to prevent access to the framework after it wants to terminate.DispatchWatcher* DispatchWatcher::GetDispatchWatcher(){ static Reference< XInterface > xDispatchWatcher; static DispatchWatcher* pDispatchWatcher = NULL; if ( !xDispatchWatcher.is() ) { ::osl::MutexGuard aGuard( GetMutex() ); if ( !xDispatchWatcher.is() ) { pDispatchWatcher = new DispatchWatcher(); // We have to hold a reference to ourself forever to prevent our own destruction. xDispatchWatcher = static_cast< cppu::OWeakObject *>( pDispatchWatcher ); } } return pDispatchWatcher;}DispatchWatcher::DispatchWatcher() : m_nRequestCount(0){}DispatchWatcher::~DispatchWatcher(){}sal_Bool DispatchWatcher::executeDispatchRequests( const DispatchList& aDispatchRequestsList, bool bNoTerminate ){ Reference< XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), UNO_QUERY ); DispatchList::const_iterator p; std::vector< DispatchHolder > aDispatches; ::rtl::OUString aAsTemplateArg( RTL_CONSTASCII_USTRINGPARAM( "AsTemplate")); for ( p = aDispatchRequestsList.begin(); p != aDispatchRequestsList.end(); p++ ) { String aPrinterName; const DispatchRequest& aDispatchRequest = *p; // create parameter array sal_Int32 nCount = 4; if ( aDispatchRequest.aPreselectedFactory.getLength() ) nCount++; // we need more properties for a print/print to request if ( aDispatchRequest.aRequestType == REQUEST_PRINT || aDispatchRequest.aRequestType == REQUEST_PRINTTO || aDispatchRequest.aRequestType == REQUEST_CONVERSION) nCount++; Sequence < PropertyValue > aArgs( nCount ); // mark request as user interaction from outside aArgs[0].Name = ::rtl::OUString::createFromAscii("Referer"); aArgs[0].Value <<= ::rtl::OUString::createFromAscii("private:OpenEvent"); if ( aDispatchRequest.aRequestType == REQUEST_PRINT || aDispatchRequest.aRequestType == REQUEST_PRINTTO || aDispatchRequest.aRequestType == REQUEST_CONVERSION) { aArgs[1].Name = ::rtl::OUString::createFromAscii("ReadOnly"); aArgs[2].Name = ::rtl::OUString::createFromAscii("OpenNewView"); aArgs[3].Name = ::rtl::OUString::createFromAscii("Hidden"); aArgs[4].Name = ::rtl::OUString::createFromAscii("Silent"); } else { Reference < com::sun::star::task::XInteractionHandler > xInteraction( ::comphelper::getProcessServiceFactory()->createInstance( OUString::createFromAscii("com.sun.star.task.InteractionHandler") ), com::sun::star::uno::UNO_QUERY ); aArgs[1].Name = OUString::createFromAscii( "InteractionHandler" ); aArgs[1].Value <<= xInteraction; sal_Int16 nMacroExecMode = ::com::sun::star::document::MacroExecMode::USE_CONFIG; aArgs[2].Name = OUString::createFromAscii( "MacroExecutionMode" ); aArgs[2].Value <<= nMacroExecMode; sal_Int16 nUpdateDoc = ::com::sun::star::document::UpdateDocMode::ACCORDING_TO_CONFIG; aArgs[3].Name = OUString::createFromAscii( "UpdateDocMode" ); aArgs[3].Value <<= nUpdateDoc; } if ( aDispatchRequest.aPreselectedFactory.getLength() ) { aArgs[nCount-1].Name = ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE(); aArgs[nCount-1].Value <<= aDispatchRequest.aPreselectedFactory; } String aName( GetURL_Impl( aDispatchRequest.aURL, aDispatchRequest.aCwdUrl ) ); ::rtl::OUString aTarget( RTL_CONSTASCII_USTRINGPARAM("_default") ); if ( aDispatchRequest.aRequestType == REQUEST_PRINT || aDispatchRequest.aRequestType == REQUEST_PRINTTO || aDispatchRequest.aRequestType == REQUEST_CONVERSION) { // documents opened for printing are opened readonly because they must be opened as a new document and this // document could be open already aArgs[1].Value <<= sal_True; // always open a new document for printing, because it must be disposed afterwards aArgs[2].Value <<= sal_True; // printing is done in a hidden view aArgs[3].Value <<= sal_True; // load document for printing without user interaction aArgs[4].Value <<= sal_True; // hidden documents should never be put into open tasks aTarget = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_blank") ); } // load the document ... if they are loadable! // Otherwise try to dispatch it ... Reference < XPrintable > xDoc; if( ( aName.CompareToAscii( ".uno" , 4 ) == COMPARE_EQUAL ) || ( aName.CompareToAscii( "slot:" , 5 ) == COMPARE_EQUAL ) || ( aName.CompareToAscii( "macro:", 6 ) == COMPARE_EQUAL ) || ( aName.CompareToAscii("vnd.sun.star.script", 19) == COMPARE_EQUAL) ) { // Attention: URL must be parsed full. Otherwise some detections on it will fail! // It doesnt matter, if parser isn't available. Because; We try loading of URL then ... URL aURL ; aURL.Complete = aName; Reference < XDispatch > xDispatcher ; Reference < XDispatchProvider > xProvider ( xDesktop, UNO_QUERY ); Reference < XURLTransformer > xParser ( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer")) ), ::com::sun::star::uno::UNO_QUERY ); if( xParser.is() == sal_True ) xParser->parseStrict( aURL ); if( xProvider.is() == sal_True ) xDispatcher = xProvider->queryDispatch( aURL, ::rtl::OUString(), 0 ); if( xDispatcher.is() == sal_True ) { { ::osl::ClearableMutexGuard aGuard( GetMutex() ); // Remember request so we can find it in statusChanged! m_aRequestContainer.insert( DispatchWatcherHashMap::value_type( aURL.Complete, (sal_Int32)1 ) ); m_nRequestCount++; } // Use local vector to store dispatcher because we have to fill our request container before // we can dispatch. Otherwise it would be possible that statusChanged is called before we dispatched all requests!! aDispatches.push_back( DispatchHolder( aURL, xDispatcher )); } } else if ( ( aName.CompareToAscii( "service:" , 8 ) == COMPARE_EQUAL ) ) { // TODO: the dispatch has to be done for loadComponentFromURL as well. Please ask AS for more details. URL aURL ; aURL.Complete = aName; Reference < XDispatch > xDispatcher ; Reference < XDispatchProvider > xProvider ( xDesktop, UNO_QUERY ); Reference < XURLTransformer > xParser ( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer")) ), ::com::sun::star::uno::UNO_QUERY ); if( xParser.is() == sal_True ) xParser->parseStrict( aURL ); if( xProvider.is() == sal_True ) xDispatcher = xProvider->queryDispatch( aURL, ::rtl::OUString(), 0 ); if( xDispatcher.is() == sal_True ) { try { // We have to be listener to catch errors during dispatching URLs. // Otherwise it would be possible to have an office running without an open // window!! Sequence < PropertyValue > aArgs2(1); aArgs2[0].Name = ::rtl::OUString::createFromAscii("SynchronMode"); aArgs2[0].Value <<= sal_True; Reference < XNotifyingDispatch > xDisp( xDispatcher, UNO_QUERY ); if ( xDisp.is() ) xDisp->dispatchWithNotification( aURL, aArgs2, DispatchWatcher::GetDispatchWatcher() ); else xDispatcher->dispatch( aURL, aArgs2 ); } catch ( ::com::sun::star::uno::Exception& ) { OUString aMsg = OUString::createFromAscii( "Desktop::OpenDefault() IllegalArgumentException while calling XNotifyingDispatch: "); OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr()); } } } else { INetURLObject aObj( aName ); if ( aObj.GetProtocol() == INET_PROT_PRIVATE ) aTarget = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_default") ); // Set "AsTemplate" argument according to request type if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW || aDispatchRequest.aRequestType == REQUEST_FORCEOPEN ) { sal_Int32 nIndex = aArgs.getLength(); aArgs.realloc( nIndex+1 ); aArgs[nIndex].Name = aAsTemplateArg; if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW ) aArgs[nIndex].Value <<= sal_True; else aArgs[nIndex].Value <<= sal_False; } // if we are called in viewmode, open document read-only // #95425# if(aDispatchRequest.aRequestType == REQUEST_VIEW) { sal_Int32 nIndex = aArgs.getLength(); aArgs.realloc(nIndex+1); aArgs[nIndex].Name = OUString::createFromAscii("ReadOnly"); aArgs[nIndex].Value <<= sal_True; } // if we are called with -start set Start in mediadescriptor if(aDispatchRequest.aRequestType == REQUEST_START) { sal_Int32 nIndex = aArgs.getLength(); aArgs.realloc(nIndex+1); aArgs[nIndex].Name = OUString::createFromAscii("StartPresentation"); aArgs[nIndex].Value <<= sal_True; } // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism. try { xDoc = Reference < XPrintable >( ::comphelper::SynchronousDispatch::dispatch( xDesktop, aName, aTarget, 0, aArgs ), UNO_QUERY ); //xDoc = Reference < XPrintable >( xDesktop->loadComponentFromURL( aName, aTarget, 0, aArgs ), UNO_QUERY ); } catch ( ::com::sun::star::lang::IllegalArgumentException& iae) { OUString aMsg = OUString::createFromAscii( "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL: ") + iae.Message; OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr()); } catch (com::sun::star::io::IOException& ioe) { OUString aMsg = OUString::createFromAscii( "Dispatchwatcher IOException while calling loadComponentFromURL: ") + ioe.Message; OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr()); } if ( aDispatchRequest.aRequestType == REQUEST_OPEN || aDispatchRequest.aRequestType == REQUEST_VIEW || aDispatchRequest.aRequestType == REQUEST_START || aDispatchRequest.aRequestType == REQUEST_FORCEOPEN || aDispatchRequest.aRequestType == REQUEST_FORCENEW ) { // request is completed OfficeIPCThread::RequestsCompleted( 1 ); } else if ( aDispatchRequest.aRequestType == REQUEST_PRINT || aDispatchRequest.aRequestType == REQUEST_PRINTTO || aDispatchRequest.aRequestType == REQUEST_CONVERSION ) { if ( xDoc.is() ) { if ( aDispatchRequest.aRequestType == REQUEST_CONVERSION ) { Reference< XStorable > xStorable( xDoc, UNO_QUERY ); if ( xStorable.is() ) { rtl::OUString aParam = aDispatchRequest.aPrinterName; sal_Int32 nPathIndex = aParam.lastIndexOfAsciiL( ";", 1 ); sal_Int32 nFilterIndex = aParam.lastIndexOfAsciiL( ":", 1 ); rtl::OUString aFilterOut=aParam.copy( nPathIndex+1 ); rtl::OUString aFilter; rtl::OUString aFilterExt; sal_Bool bGuess = sal_False; if( nFilterIndex >= 0 ) { aFilter = aParam.copy( nFilterIndex+1, nPathIndex-nFilterIndex-1 ); aFilterExt = aParam.copy( 0, nFilterIndex ); } else { // Guess bGuess = sal_True; aFilterExt = aParam.copy( 0, nPathIndex ); } INetURLObject aOutFilename( aObj ); aOutFilename.SetExtension( aFilterExt ); FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut ); rtl::OUString aOutFile = aFilterOut+ ::rtl::OUString::createFromAscii( "/" )+ aOutFilename.getName(); //FileBase::getFileURLFromSystemPath( aOutFile, aOutFile ); if ( bGuess ) { aFilter = impl_GuessFilter( aName, aOutFile ); } Sequence<PropertyValue> conversionProperties( 2 ); conversionProperties[0].Name = ::rtl::OUString::createFromAscii( "Overwrite" ); conversionProperties[0].Value <<= sal_True; conversionProperties[1].Name = ::rtl::OUString::createFromAscii( "FilterName" ); conversionProperties[1].Value <<= aFilter; rtl::OUString aTempName; FileBase::getSystemPathFromFileURL( aName, aTempName ); rtl::OString aSource8 = ::rtl::OUStringToOString ( aTempName, RTL_TEXTENCODING_UTF8 ); FileBase::getSystemPathFromFileURL( aOutFile, aTempName ); rtl::OString aTargetURL8 = ::rtl::OUStringToOString(aTempName, RTL_TEXTENCODING_UTF8 ); printf("convert %s->%s using %s\n", aSource8.getStr(), aTargetURL8.getStr(), ::rtl::OUStringToOString( aFilter, RTL_TEXTENCODING_UTF8 ).getStr()); if( FStatHelper::IsDocument(aOutFile) ) printf("Overwriting: %s\n",::rtl::OUStringToOString( aTempName, RTL_TEXTENCODING_UTF8 ).getStr() ); try { xStorable->storeToURL( aOutFile, conversionProperties ); } catch ( Exception& ) { fprintf( stderr, "Error: Please reverify input parameters...\n" ); } } } else { if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO ) { // create the printer Sequence < PropertyValue > aPrinterArgs( 1 ); aPrinterArgs[0].Name = ::rtl::OUString::createFromAscii("Name"); aPrinterArgs[0].Value <<= ::rtl::OUString( aDispatchRequest.aPrinterName ); xDoc->setPrinter( aPrinterArgs ); } // print ( also without user interaction ) Sequence < PropertyValue > aPrinterArgs( 1 ); aPrinterArgs[0].Name = ::rtl::OUString::createFromAscii("Wait"); aPrinterArgs[0].Value <<= ( sal_Bool ) sal_True; xDoc->print( aPrinterArgs ); } } else { // place error message here ... } // remove the document try { Reference < XCloseable > xClose( xDoc, UNO_QUERY ); if ( xClose.is() ) xClose->close( sal_True ); else { Reference < XComponent > xComp( xDoc, UNO_QUERY ); if ( xComp.is() ) xComp->dispose(); } } catch ( com::sun::star::util::CloseVetoException& ) { } // request is completed OfficeIPCThread::RequestsCompleted( 1 ); } } } if ( aDispatches.size() > 0 ) { // Execute all asynchronous dispatches now after we placed them into our request container! Sequence < PropertyValue > aArgs( 2 ); aArgs[0].Name = ::rtl::OUString::createFromAscii("Referer"); aArgs[0].Value <<= ::rtl::OUString::createFromAscii("private:OpenEvent"); aArgs[1].Name = ::rtl::OUString::createFromAscii("SynchronMode"); aArgs[1].Value <<= sal_True; for ( sal_uInt32 n = 0; n < aDispatches.size(); n++ ) { Reference< XDispatch > xDispatch = aDispatches[n].xDispatch; Reference < XNotifyingDispatch > xDisp( xDispatch, UNO_QUERY ); if ( xDisp.is() ) xDisp->dispatchWithNotification( aDispatches[n].aURL, aArgs, this ); else { ::osl::ClearableMutexGuard aGuard( GetMutex() ); m_nRequestCount--; aGuard.clear(); xDispatch->dispatch( aDispatches[n].aURL, aArgs ); } } } ::osl::ClearableMutexGuard aGuard( GetMutex() ); bool bEmpty = (m_nRequestCount == 0); aGuard.clear(); // No more asynchronous requests? // The requests are removed from the request container after they called back to this // implementation via statusChanged!! if ( bEmpty && !bNoTerminate /*m_aRequestContainer.empty()*/ ) { // Delay give a chance for threads to complete work impl_sleep(2); // We have to check if we have an open task otherwise we have to shutdown the office. Reference< XFramesSupplier > xTasksSupplier( xDesktop, UNO_QUERY ); aGuard.clear(); // Delay give a chance for threads to complete work impl_sleep(1); Reference< XElementAccess > xList( xTasksSupplier->getFrames(), UNO_QUERY ); if ( !xList->hasElements() ) { // We don't have any task open so we have to shutdown ourself!! Reference< XDesktop > xDesktop2( xTasksSupplier, UNO_QUERY ); if ( xDesktop2.is() ) return xDesktop2->terminate(); } } return sal_False;}void SAL_CALL DispatchWatcher::disposing( const ::com::sun::star::lang::EventObject& )throw(::com::sun::star::uno::RuntimeException){}void SAL_CALL DispatchWatcher::dispatchFinished( const DispatchResultEvent& ) throw( RuntimeException ){ osl::ClearableMutexGuard aGuard( GetMutex() ); sal_Int16 nCount = m_nRequestCount; aGuard.clear(); OfficeIPCThread::RequestsCompleted( 1 );/* // Find request in our hash map and remove it as a pending request DispatchWatcherHashMap::iterator pDispatchEntry = m_aRequestContainer.find( rEvent.FeatureURL.Complete ) ; if ( pDispatchEntry != m_aRequestContainer.end() ) { m_aRequestContainer.erase( pDispatchEntry ); aGuard.clear(); OfficeIPCThread::RequestsCompleted( 1 ); } else aGuard.clear();*/ if ( !nCount && !OfficeIPCThread::AreRequestsPending() ) { // We have to check if we have an open task otherwise we have to shutdown the office. Reference< XFramesSupplier > xTasksSupplier( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), UNO_QUERY ); Reference< XElementAccess > xList( xTasksSupplier->getFrames(), UNO_QUERY ); if ( !xList->hasElements() ) { // We don't have any task open so we have to shutdown ourself!! Reference< XDesktop > xDesktop( xTasksSupplier, UNO_QUERY ); if ( xDesktop.is() ) xDesktop->terminate(); } }}}