office-gobmx/desktop/source/app/dispatchwatcher.cxx
Noel Grandin ed0b12f4ea no need to take a copy of the getProcessComponentContext return value
we can just take a "const &".

(found by running clang-tidy with the
performance-unnecessary-copy-initialization warning)

Change-Id: I20fd208c65303da78170b1ac06c638fdf3aa094b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176267
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Jenkins
2024-11-08 15:23:52 +01:00

864 lines
37 KiB
C++

/* -*- 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/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 <comphelper/diagnose_ex.hxx>
#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( u"com.sun.star.document.FilterFactory"_ustr, 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( u"Name"_ustr, 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 = std::move(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( u"com.sun.star.document.TypeDetection"_ustr, 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>"_ostr : OUStringToOString( aPrinterName, osl_getThreadTextEncoding() ));
std::cout << std::endl;
// create the custom printer, if given
Sequence < PropertyValue > aPrinterArgs;
if( !aPrinterName.isEmpty() )
{
aPrinterArgs = { comphelper::makePropertyValue(u"Name"_ustr, aPrinterName) };
xDoc->setPrinter( aPrinterArgs );
}
// print ( also without user interaction )
aPrinterArgs = { comphelper::makePropertyValue(u"FileName"_ustr, aOutFile),
comphelper::makePropertyValue(u"Wait"_ustr, true) };
xDoc->print( aPrinterArgs );
}
// Get xDoc module name
OUString getName(const Reference< XInterface > & xDoc)
{
Reference< XModel > xModel( xDoc, UNO_QUERY );
if (!xModel)
return OUString();
utl::MediaDescriptor aMediaDesc( xModel->getArgs() );
OUString aDocService = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString() );
if (aDocService == "com.sun.star.text.TextDocument")
return u"Writer"_ustr;
else if (aDocService == "com.sun.star.text.GlobalDocument")
return u"Writer master"_ustr;
else if (aDocService == "com.sun.star.text.WebDocument")
return u"Writer/Web"_ustr;
else if (aDocService == "com.sun.star.drawing.DrawingDocument")
return u"Draw"_ustr;
else if (aDocService == "com.sun.star.presentation.PresentationDocument")
return u"Impress"_ustr;
else if (aDocService == "com.sun.star.sheet.SpreadsheetDocument")
return u"Calc"_ustr;
else if (aDocService == "com.sun.star.script.BasicIDE")
return u"Basic"_ustr;
else if (aDocService == "com.sun.star.formula.FormulaProperties")
return u"Math"_ustr;
else if (aDocService == "com.sun.star.sdb.RelationDesign")
return u"Relation Design"_ustr;
else if (aDocService == "com.sun.star.sdb.QueryDesign")
return u"Query Design"_ustr;
else if (aDocService == "com.sun.star.sdb.TableDesign")
return u"Table Design"_ustr;
else if (aDocService == "com.sun.star.sdb.DataSourceBrowser")
return u"Data Source Browser"_ustr;
else if (aDocService == "com.sun.star.sdb.DatabaseDocument")
return u"Database"_ustr;
return OUString();
}
} // 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(u"private:OpenEvent"_ustr),
PropertyState_DIRECT_VALUE);
OUString aTarget(u"_default"_ustr);
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() )
{
// 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(u"SynchronMode"_ustr,
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) {
const sal_Int32 nStartingSlide = aDispatchRequest.aParam.toInt32();
const sal_uInt16 nSlide = nStartingSlide > 0 ? nStartingSlide : 1;
aArgs.emplace_back("StartPresentation", 0, Any(nSlide), 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() ) {
const OUString& aParam = aDispatchRequest.aParam;
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::TempFileNamed> fileForCat;
if( aDispatchRequest.aRequestType == REQUEST_CAT )
{
fileForCat = std::make_unique<utl::TempFileNamed>();
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 <<= u"CommandLine"_ustr;
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)
{
OUString name=getName(xDoc);
std::cout << "convert " << aSource8;
if (!name.isEmpty())
std::cout << " as a " << name <<" document";
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.aParam, xDoc, aObj, aName);
}
else
{
if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO )
{
// create the printer
Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue(
u"Name"_ustr, aDispatchRequest.aParam) };
xDoc->setPrinter( aPrinterArgs );
}
// print ( also without user interaction )
Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue(u"Wait"_ustr,
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(u"Referer"_ustr, u"private:OpenEvent"_ustr),
comphelper::makePropertyValue(u"SynchronMode"_ustr, 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
{
m_nRequestCount--;
xDispatch->dispatch( aDispatche.aURL, aArgs );
}
}
}
bool bEmpty = (m_nRequestCount == 0);
// 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& )
{
int nCount = --m_nRequestCount;
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: */