diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /desktop/source/app/dispatchwatcher.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'desktop/source/app/dispatchwatcher.cxx')
-rw-r--r-- | desktop/source/app/dispatchwatcher.cxx | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/desktop/source/app/dispatchwatcher.cxx b/desktop/source/app/dispatchwatcher.cxx new file mode 100644 index 000000000..381507149 --- /dev/null +++ b/desktop/source/app/dispatchwatcher.cxx @@ -0,0 +1,832 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <svl/fstathelper.hxx> + +#include <app.hxx> +#include "dispatchwatcher.hxx" +#include "officeipcthread.hxx" +#include <rtl/ustring.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/synchronousdispatch.hxx> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XNotifyingDispatch.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/view/XPrintable.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/document/MacroExecMode.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/document/UpdateDocMode.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <com/sun/star/document/XEmbeddedScripts.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <tools/diagnose_ex.h> +#include <tools/urlobj.hxx> +#include <unotools/mediadescriptor.hxx> +#include <unotools/tempfile.hxx> + +#include <osl/thread.hxx> +#include <osl/file.hxx> +#include <iostream> +#include <string_view> +#include <utility> + +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; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::document; + +namespace document = ::com::sun::star::document; + +namespace desktop +{ + +namespace { + +struct DispatchHolder +{ + DispatchHolder( URL _aURL, Reference< XDispatch > const & rDispatch ) : + aURL(std::move( _aURL )), xDispatch( rDispatch ) {} + + URL aURL; + Reference< XDispatch > xDispatch; +}; + +std::shared_ptr<const SfxFilter> impl_lookupExportFilterForUrl( std::u16string_view rUrl, std::u16string_view rFactory ) +{ + // create the list of filters + OUString sQuery = "getSortedFilterList()" + ":module=" + + OUString::Concat(rFactory) + // use long name here ! + ":iflags=" + + OUString::number(static_cast<sal_Int32>(SfxFilterFlags::EXPORT)) + + ":eflags=" + + OUString::number(static_cast<int>(SFX_FILTER_NOTINSTALLED)); + + const Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); + const Reference< XContainerQuery > xFilterFactory( + xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", xContext ), + UNO_QUERY_THROW ); + + std::shared_ptr<const SfxFilter> pBestMatch; + + const Reference< XEnumeration > xFilterEnum( + xFilterFactory->createSubSetEnumerationByQuery( sQuery ), UNO_SET_THROW ); + while ( xFilterEnum->hasMoreElements() ) + { + comphelper::SequenceAsHashMap aFilterProps( xFilterEnum->nextElement() ); + const OUString aName( aFilterProps.getUnpackedValueOrDefault( "Name", OUString() ) ); + if ( !aName.isEmpty() ) + { + std::shared_ptr<const SfxFilter> pFilter( SfxFilter::GetFilterByName( aName ) ); + if ( pFilter && pFilter->CanExport() && pFilter->GetWildcard().Matches( rUrl ) ) + { + if ( !pBestMatch || ( SfxFilterFlags::PREFERED & pFilter->GetFilterFlags() ) ) + pBestMatch = pFilter; + } + } + } + + return pBestMatch; +} + +std::shared_ptr<const SfxFilter> impl_getExportFilterFromUrl( + const OUString& rUrl, const OUString& rFactory) +{ + try + { + const Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); + const Reference< document::XTypeDetection > xTypeDetector( + xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", xContext ), + UNO_QUERY_THROW ); + const OUString aTypeName( xTypeDetector->queryTypeByURL( rUrl ) ); + + std::shared_ptr<const SfxFilter> pFilter( SfxFilterMatcher( rFactory ).GetFilter4EA( aTypeName, SfxFilterFlags::EXPORT ) ); + if ( !pFilter ) + pFilter = impl_lookupExportFilterForUrl( rUrl, rFactory ); + if ( !pFilter ) + { + OUString aTempName; + FileBase::getSystemPathFromFileURL( rUrl, aTempName ); + OString aSource = OUStringToOString ( aTempName, osl_getThreadTextEncoding() ); + std::cerr << "Error: no export filter for " << aSource << " found, aborting." << std::endl; + } + + return pFilter; + } + catch ( const Exception& ) + { + return nullptr; + } +} + +OUString impl_GuessFilter( const OUString& rUrlOut, const OUString& rDocService ) +{ + OUString aOutFilter; + std::shared_ptr<const SfxFilter> pOutFilter = impl_getExportFilterFromUrl( rUrlOut, rDocService ); + if (pOutFilter) + aOutFilter = pOutFilter->GetFilterName(); + + return aOutFilter; +} + +/// dump scripts in a document to the console. +void scriptCat(const Reference< XModel >& xDoc ) +{ + Reference< XEmbeddedScripts > xScriptAccess( xDoc, UNO_QUERY ); + if (!xScriptAccess) + { + std::cout << "No script access\n"; + return; + } + + // ignore xScriptAccess->getDialogLibraries() for now + Reference< css::script::XLibraryContainer2 > xLibraries( + xScriptAccess->getBasicLibraries() ); + + if ( !xLibraries.is() ) + { + std::cout << "No script libraries\n"; + return; + } + + const Sequence< OUString > aLibNames = xLibraries->getElementNames(); + std::cout << "Libraries: " << aLibNames.getLength() << "\n"; + for (OUString const & libName : aLibNames) + { + std::cout << "Library: '" << libName << "' children: "; + Reference< XNameContainer > xContainer; + try { + if (!xLibraries->isLibraryLoaded( libName )) + xLibraries->loadLibrary( libName ); + xContainer = Reference< XNameContainer >( + xLibraries->getByName( libName ), UNO_QUERY ); + } + catch (const css::uno::Exception &e) + { + std::cout << "[" << libName << "] - failed to load library: " << e.Message << "\n"; + continue; + } + if( !xContainer.is() ) + std::cout << "0\n"; + else + { + Sequence< OUString > aObjectNames = xContainer->getElementNames(); + + std::cout << aObjectNames.getLength() << "\n\n"; + for ( sal_Int32 j = 0 ; j < aObjectNames.getLength() ; ++j ) + { + const OUString &rObjectName = aObjectNames[j]; + + try + { + Any aCode = xContainer->getByName( rObjectName ); + OUString aCodeString; + + if (! (aCode >>= aCodeString ) ) + std::cout << "[" << rObjectName << "] - error fetching code\n"; + else + std::cout << "[" << rObjectName << "]\n" + << aCodeString.trim() + << "\n[/" << rObjectName << "]\n"; + } + catch (const css::uno::Exception &e) + { + std::cout << "[" << rObjectName << "] - exception " << e.Message << " fetching code\n"; + } + + if (j < aObjectNames.getLength() - 1) + std::cout << "\n----------------------------------------------------------\n"; + std::cout << "\n"; + } + } + } +} + +// Perform batch print +void batchPrint( std::u16string_view rPrinterName, const Reference< XPrintable > &xDoc, + const INetURLObject &aObj, const OUString &aName ) +{ + OUString aFilterOut; + OUString aPrinterName; + size_t nPathIndex = rPrinterName.rfind( ';' ); + if( nPathIndex != std::u16string_view::npos ) + aFilterOut=rPrinterName.substr( nPathIndex+1 ); + if( nPathIndex != 0 ) + aPrinterName=rPrinterName.substr( 0, nPathIndex ); + + INetURLObject aOutFilename( aObj ); + aOutFilename.SetExtension( u"pdf" ); + FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut ); + OUString aOutFile = aFilterOut + "/" + aOutFilename.getName(); + + OUString aTempName; + FileBase::getSystemPathFromFileURL( aName, aTempName ); + OString aSource8 = OUStringToOString ( aTempName, osl_getThreadTextEncoding() ); + FileBase::getSystemPathFromFileURL( aOutFile, aTempName ); + OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding() ); + + std::cout << "print " << aSource8 << " -> " << aTargetURL8; + std::cout << " using " << (aPrinterName.isEmpty() ? "<default_printer>" : OUStringToOString( aPrinterName, osl_getThreadTextEncoding() )); + std::cout << std::endl; + + // create the custom printer, if given + Sequence < PropertyValue > aPrinterArgs; + if( !aPrinterName.isEmpty() ) + { + aPrinterArgs = { comphelper::makePropertyValue("Name", aPrinterName) }; + xDoc->setPrinter( aPrinterArgs ); + } + + // print ( also without user interaction ) + aPrinterArgs = { comphelper::makePropertyValue("FileName", aOutFile), + comphelper::makePropertyValue("Wait", true) }; + xDoc->print( aPrinterArgs ); +} + +} // anonymous namespace + +DispatchWatcher::DispatchWatcher() + : m_nRequestCount(0) +{ +} + + +DispatchWatcher::~DispatchWatcher() +{ +} + + +bool DispatchWatcher::executeDispatchRequests( const std::vector<DispatchRequest>& aDispatchRequestsList, bool bNoTerminate ) +{ + Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); + + std::vector< DispatchHolder > aDispatches; + bool bSetInputFilter = false; + OUString aForcedInputFilter; + + for (auto const & aDispatchRequest: aDispatchRequestsList) + { + // Set Input Filter + if ( aDispatchRequest.aRequestType == REQUEST_INFILTER ) + { + bSetInputFilter = true; + aForcedInputFilter = aDispatchRequest.aURL; + RequestHandler::RequestsCompleted(); + continue; + } + + // create parameter array + std::vector<PropertyValue> aArgs; + + // mark request as user interaction from outside + aArgs.emplace_back("Referer", 0, Any(OUString("private:OpenEvent")), + PropertyState_DIRECT_VALUE); + + OUString aTarget("_default"); + + if ( aDispatchRequest.aRequestType == REQUEST_PRINT || + aDispatchRequest.aRequestType == REQUEST_PRINTTO || + aDispatchRequest.aRequestType == REQUEST_BATCHPRINT || + aDispatchRequest.aRequestType == REQUEST_CONVERSION || + aDispatchRequest.aRequestType == REQUEST_CAT || + aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT) + { + // documents opened for printing are opened readonly because they must be opened as a + // new document and this document could be open already + aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE); + // always open a new document for printing, because it must be disposed afterwards + aArgs.emplace_back("OpenNewView", 0, Any(true), PropertyState_DIRECT_VALUE); + // printing is done in a hidden view + aArgs.emplace_back("Hidden", 0, Any(true), PropertyState_DIRECT_VALUE); + // load document for printing without user interaction + aArgs.emplace_back("Silent", 0, Any(true), PropertyState_DIRECT_VALUE); + + // hidden documents should never be put into open tasks + aTarget = "_blank"; + } + else + { + Reference < XInteractionHandler2 > xInteraction( + InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) ); + + aArgs.emplace_back("InteractionHandler", 0, Any(xInteraction), + PropertyState_DIRECT_VALUE); + + aArgs.emplace_back("MacroExecutionMode", 0, + Any(css::document::MacroExecMode::USE_CONFIG), + PropertyState_DIRECT_VALUE); + + aArgs.emplace_back("UpdateDocMode", 0, + Any(css::document::UpdateDocMode::ACCORDING_TO_CONFIG), + PropertyState_DIRECT_VALUE); + } + + if ( !aDispatchRequest.aPreselectedFactory.isEmpty() ) + { + aArgs.emplace_back(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, 0, + Any(aDispatchRequest.aPreselectedFactory), + PropertyState_DIRECT_VALUE); + } + + OUString aName( GetURL_Impl( aDispatchRequest.aURL, aDispatchRequest.aCwdUrl ) ); + + // load the document ... if they are loadable! + // Otherwise try to dispatch it ... + Reference < XPrintable > xDoc; + if( + ( aName.startsWith( ".uno" ) ) || + ( aName.startsWith( "slot:" ) ) || + ( aName.startsWith( "macro:" ) ) || + ( aName.startsWith("vnd.sun.star.script") ) + ) + { + // Attention: URL must be parsed full. Otherwise some detections on it will fail! + // It doesn't matter, if parser isn't available. Because; We try loading of URL then ... + URL aURL ; + aURL.Complete = aName; + + Reference < XDispatch > xDispatcher ; + Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) ); + + if( xParser.is() ) + xParser->parseStrict( aURL ); + + xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 ); + SAL_WARN_IF( + !xDispatcher.is(), "desktop.app", + "unsupported dispatch request <" << aName << ">"); + if( xDispatcher.is() ) + { + { + osl::MutexGuard aGuard(m_mutex); + // Remember request so we can find it in statusChanged! + 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.emplace_back( aURL, xDispatcher ); + } + } + else if ( aName.startsWith( "service:" ) ) + { + // TODO: the dispatch has to be done for loadComponentFromURL as well. + URL aURL ; + aURL.Complete = aName; + + Reference < XDispatch > xDispatcher ; + Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) ); + + if( xParser.is() ) + xParser->parseStrict( aURL ); + + xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 ); + + if( xDispatcher.is() ) + { + 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{ comphelper::makePropertyValue("SynchronMode", + true) }; + Reference < XNotifyingDispatch > xDisp( xDispatcher, UNO_QUERY ); + if ( xDisp.is() ) + xDisp->dispatchWithNotification( aURL, aArgs2, this ); + else + xDispatcher->dispatch( aURL, aArgs2 ); + } + catch (const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION( + "desktop.app", + "Desktop::OpenDefault() ignoring Exception while calling XNotifyingDispatch"); + } + } + } + else + { + INetURLObject aObj( aName ); + if ( aObj.GetProtocol() == INetProtocol::PrivSoffice ) + aTarget = "_default"; + + // Set "AsTemplate" argument according to request type + if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW || + aDispatchRequest.aRequestType == REQUEST_FORCEOPEN ) + { + aArgs.emplace_back("AsTemplate", 0, + Any(aDispatchRequest.aRequestType == REQUEST_FORCENEW), + PropertyState_DIRECT_VALUE); + } + + // if we are called in viewmode, open document read-only + if(aDispatchRequest.aRequestType == REQUEST_VIEW) { + aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE); + } + + // if we are called with --show set Start in mediadescriptor + if(aDispatchRequest.aRequestType == REQUEST_START) { + aArgs.emplace_back("StartPresentation", 0, Any(true), PropertyState_DIRECT_VALUE); + } + + // Force input filter, if possible + if( bSetInputFilter ) + { + sal_Int32 nFilterOptionsIndex = 0; + aArgs.emplace_back("FilterName", 0, + Any(aForcedInputFilter.getToken(0, ':', nFilterOptionsIndex)), + PropertyState_DIRECT_VALUE); + + if (0 < nFilterOptionsIndex) + { + aArgs.emplace_back("FilterOptions", 0, + Any(aForcedInputFilter.copy(nFilterOptionsIndex)), + PropertyState_DIRECT_VALUE); + } + } + + // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism. + try + { + xDoc.set(comphelper::SynchronousDispatch::dispatch( + xDesktop, aName, aTarget, comphelper::containerToSequence(aArgs)), + UNO_QUERY); + } + catch (const css::lang::IllegalArgumentException&) + { + TOOLS_WARN_EXCEPTION( + "desktop.app", + "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL"); + } + catch (const css::io::IOException&) + { + TOOLS_WARN_EXCEPTION( + "desktop.app", + "Dispatchwatcher IOException while calling loadComponentFromURL"); + } + if ( aDispatchRequest.aRequestType == REQUEST_OPEN || + aDispatchRequest.aRequestType == REQUEST_VIEW || + aDispatchRequest.aRequestType == REQUEST_START || + aDispatchRequest.aRequestType == REQUEST_FORCEOPEN || + aDispatchRequest.aRequestType == REQUEST_FORCENEW ) + { + // request is completed + RequestHandler::RequestsCompleted(); + } + else if ( aDispatchRequest.aRequestType == REQUEST_PRINT || + aDispatchRequest.aRequestType == REQUEST_PRINTTO || + aDispatchRequest.aRequestType == REQUEST_BATCHPRINT || + aDispatchRequest.aRequestType == REQUEST_CONVERSION || + aDispatchRequest.aRequestType == REQUEST_CAT || + aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT ) + { + if ( xDoc.is() ) + { + // Do we need to save the document in a different format? + if ( aDispatchRequest.aRequestType == REQUEST_CONVERSION || + aDispatchRequest.aRequestType == REQUEST_CAT ) + { +// FIXME: factor out into a method ... + Reference< XStorable > xStorable( xDoc, UNO_QUERY ); + if ( xStorable.is() ) { + OUString aParam = aDispatchRequest.aPrinterName; + sal_Int32 nPathIndex = aParam.lastIndexOf( ';' ); + sal_Int32 nFilterIndex = aParam.indexOf( ':' ); + sal_Int32 nImgFilterIndex = aParam.lastIndexOf( '|' ); + if( nPathIndex < nFilterIndex ) + nFilterIndex = -1; + + OUString aFilterOut; + OUString aImgOut; + OUString aFilter; + OUString aFilterExt; + bool bGuess = false; + + if( nFilterIndex >= 0 ) + { + aFilter = aParam.copy( nFilterIndex+1, nPathIndex-nFilterIndex-1 ); + aFilterExt = aParam.copy( 0, nFilterIndex ); + } + else + { + // Guess + bGuess = true; + aFilterExt = aParam.copy( 0, nPathIndex ); + } + + if( nImgFilterIndex >= 0 ) + { + aImgOut = aParam.copy( nImgFilterIndex+1 ); + aFilterOut = aParam.copy( nPathIndex+1, nImgFilterIndex-nPathIndex-1 ); + } + else + aFilterOut = aParam.copy( nPathIndex+1 ); + + FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut ); + INetURLObject aOutFilename(aFilterOut); + aOutFilename.Append(aObj.getName(INetURLObject::LAST_SEGMENT, true, + INetURLObject::DecodeMechanism::NONE)); + aOutFilename.SetExtension(aFilterExt); + OUString aOutFile + = aOutFilename.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + std::unique_ptr<utl::TempFile> fileForCat; + if( aDispatchRequest.aRequestType == REQUEST_CAT ) + { + fileForCat = std::make_unique<utl::TempFile>(); + if (fileForCat->IsValid()) + fileForCat->EnableKillingFile(); + else + std::cerr << "Error: Cannot create temporary file..." << std::endl ; + aOutFile = fileForCat->GetURL(); + } + + if ( bGuess ) + { + OUString aDocService; + Reference< XModel > xModel( xDoc, UNO_QUERY ); + if ( xModel.is() ) + { + utl::MediaDescriptor aMediaDesc( xModel->getArgs() ); + aDocService = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString() ); + } + aFilter = impl_GuessFilter( aOutFile, aDocService ); + } + + bool bMultiFileTarget = false; + + if (aFilter.isEmpty()) + { + std::cerr << "Error: no export filter" << std::endl; + } + else + { + sal_Int32 nFilterOptionsIndex = aFilter.indexOf(':'); + sal_Int32 nProps = ( 0 < nFilterOptionsIndex ) ? 4 : 3; + + if ( !aImgOut.isEmpty() ) + nProps +=1; + Sequence<PropertyValue> conversionProperties( nProps ); + auto pconversionProperties = conversionProperties.getArray(); + pconversionProperties[0].Name = "ConversionRequestOrigin"; + pconversionProperties[0].Value <<= OUString("CommandLine"); + pconversionProperties[1].Name = "Overwrite"; + pconversionProperties[1].Value <<= true; + + pconversionProperties[2].Name = "FilterName"; + if( 0 < nFilterOptionsIndex ) + { + OUString sFilterName = aFilter.copy(0, nFilterOptionsIndex); + OUString sFilterOptions = aFilter.copy(nFilterOptionsIndex + 1); + + if (sFilterName == "Text - txt - csv (StarCalc)") + { + sal_Int32 nIdx(0); + // If the 11th token is '-1' then we export a file + // per sheet where the file name is based on the suggested + // output filename concatenated with the sheet name, so adjust + // the output and overwrite messages + // If the 11th token is not present or numeric 0 then the + // default sheet is exported with the output filename. If it + // is numeric >0 then that sheet (1-based) with the output + // filename concatenated with the sheet name. So even if + // that is a single file, the multi file target mechanism is + // used. + const OUString aTok(sFilterOptions.getToken(11, ',', nIdx)); + // Actual validity is checked in Calc, here just check for + // presence of numeric value at start. + bMultiFileTarget = (!aTok.isEmpty() && aTok.toInt32() != 0); + } + + pconversionProperties[2].Value <<= sFilterName; + + pconversionProperties[3].Name = "FilterOptions"; + pconversionProperties[3].Value <<= sFilterOptions; + } + else + { + pconversionProperties[2].Value <<= aFilter; + } + + if ( !aImgOut.isEmpty() ) + { + assert(conversionProperties[nProps-1].Name.isEmpty()); + pconversionProperties[nProps-1].Name = "ImageFilter"; + pconversionProperties[nProps-1].Value <<= aImgOut; + } + + OUString aTempName; + FileBase::getSystemPathFromFileURL(aName, aTempName); + OString aSource8 = OUStringToOString(aTempName, osl_getThreadTextEncoding()); + FileBase::getSystemPathFromFileURL(aOutFile, aTempName); + OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding()); + if (aDispatchRequest.aRequestType != REQUEST_CAT) + { + std::cout << "convert " << aSource8; + if (!bMultiFileTarget) + std::cout << " -> " << aTargetURL8; + std::cout << " using filter : " << OUStringToOString(aFilter, osl_getThreadTextEncoding()) << std::endl; + if (!bMultiFileTarget && FStatHelper::IsDocument(aOutFile)) + std::cout << "Overwriting: " << OUStringToOString(aTempName, osl_getThreadTextEncoding()) << std::endl ; + } + try + { + xStorable->storeToURL(aOutFile, conversionProperties); + } + catch (const Exception& rException) + { + std::cerr << "Error: Please verify input parameters..."; + if (!rException.Message.isEmpty()) + std::cerr << " (" << rException.Message << ")"; + std::cerr << std::endl; + } + + if (fileForCat && fileForCat->IsValid()) + { + SvStream* aStream = fileForCat->GetStream(StreamMode::STD_READ); + while (aStream->good()) + { + OString aStr; + aStream->ReadLine(aStr, SAL_MAX_INT32); + for (sal_Int32 i = 0; i < aStr.getLength(); ++i) + { + std::cout << aStr[i]; + } + std::cout << std::endl; + } + } + } + } + } + else if ( aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT ) + { + Reference< XModel > xModel( xDoc, UNO_QUERY ); + if( xModel.is() ) + scriptCat( xModel ); + } + else if ( aDispatchRequest.aRequestType == REQUEST_BATCHPRINT ) + { + batchPrint( aDispatchRequest.aPrinterName, xDoc, aObj, aName ); + } + else + { + if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO ) + { + // create the printer + Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue( + "Name", aDispatchRequest.aPrinterName) }; + xDoc->setPrinter( aPrinterArgs ); + } + + // print ( also without user interaction ) + Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue("Wait", + true) }; + xDoc->print( aPrinterArgs ); + } + } + else + { + std::cerr << "Error: source file could not be loaded" << std::endl; + } + + // remove the document + try + { + Reference < XCloseable > xClose( xDoc, UNO_QUERY ); + if ( xClose.is() ) + xClose->close( true ); + else + { + Reference < XComponent > xComp( xDoc, UNO_QUERY ); + if ( xComp.is() ) + xComp->dispose(); + } + } + catch (const css::util::CloseVetoException&) + { + } + + // request is completed + RequestHandler::RequestsCompleted(); + } + } + } + + if ( !aDispatches.empty() ) + { + // Execute all asynchronous dispatches now after we placed them into our request container! + Sequence < PropertyValue > aArgs{ + comphelper::makePropertyValue("Referer", OUString("private:OpenEvent")), + comphelper::makePropertyValue("SynchronMode", true) + }; + + for (const DispatchHolder & aDispatche : aDispatches) + { + Reference< XDispatch > xDispatch = aDispatche.xDispatch; + Reference < XNotifyingDispatch > xDisp( xDispatch, UNO_QUERY ); + if ( xDisp.is() ) + xDisp->dispatchWithNotification( aDispatche.aURL, aArgs, this ); + else + { + { + osl::MutexGuard aGuard(m_mutex); + m_nRequestCount--; + } + xDispatch->dispatch( aDispatche.aURL, aArgs ); + } + } + } + + ::osl::ClearableMutexGuard aGuard(m_mutex); + 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()*/ ) + { + // We have to check if we have an open task otherwise we have to shutdown the office. + Reference< XElementAccess > xList = xDesktop->getFrames(); + + if ( !xList->hasElements() ) + { + // We don't have any task open so we have to shutdown ourself!! + return xDesktop->terminate(); + } + } + + return false; +} + + +void SAL_CALL DispatchWatcher::disposing( const css::lang::EventObject& ) +{ +} + + +void SAL_CALL DispatchWatcher::dispatchFinished( const DispatchResultEvent& ) +{ + osl::ClearableMutexGuard aGuard(m_mutex); + sal_Int16 nCount = --m_nRequestCount; + aGuard.clear(); + RequestHandler::RequestsCompleted(); + if ( !nCount && !RequestHandler::AreRequestsPending() ) + { + // We have to check if we have an open task otherwise we have to shutdown the office. + Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); + Reference< XElementAccess > xList = xDesktop->getFrames(); + + if ( !xList->hasElements() ) + { + // We don't have any task open so we have to shutdown ourself!! + xDesktop->terminate(); + } + } +} + +} // namespace desktop + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |