1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <sfx2/docfilt.hxx>
24 #include <sfx2/fcontnr.hxx>
25 #include <svl/fstathelper.hxx>
28 #include "dispatchwatcher.hxx"
29 #include "officeipcthread.hxx"
30 #include <rtl/ustring.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/synchronousdispatch.hxx>
33 #include <com/sun/star/io/IOException.hpp>
34 #include <com/sun/star/util/XCloseable.hpp>
35 #include <com/sun/star/util/CloseVetoException.hpp>
36 #include <com/sun/star/task/InteractionHandler.hpp>
37 #include <com/sun/star/util/URL.hpp>
38 #include <com/sun/star/frame/Desktop.hpp>
39 #include <com/sun/star/container/XContainerQuery.hpp>
40 #include <com/sun/star/container/XEnumeration.hpp>
41 #include <com/sun/star/frame/XDispatch.hpp>
42 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/view/XPrintable.hpp>
45 #include <com/sun/star/util/URLTransformer.hpp>
46 #include <com/sun/star/util/XURLTransformer.hpp>
47 #include <com/sun/star/document/MacroExecMode.hpp>
48 #include <com/sun/star/document/XTypeDetection.hpp>
49 #include <com/sun/star/document/UpdateDocMode.hpp>
50 #include <com/sun/star/frame/XStorable.hpp>
51 #include <com/sun/star/script/XLibraryContainer2.hpp>
52 #include <com/sun/star/document/XEmbeddedScripts.hpp>
54 #include <comphelper/propertyvalue.hxx>
55 #include <comphelper/sequence.hxx>
56 #include <comphelper/diagnose_ex.hxx>
57 #include <tools/urlobj.hxx>
58 #include <unotools/mediadescriptor.hxx>
59 #include <unotools/tempfile.hxx>
61 #include <osl/thread.hxx>
62 #include <osl/file.hxx>
64 #include <string_view>
67 using namespace ::osl
;
68 using namespace ::com::sun::star::uno
;
69 using namespace ::com::sun::star::util
;
70 using namespace ::com::sun::star::lang
;
71 using namespace ::com::sun::star::frame
;
72 using namespace ::com::sun::star::container
;
73 using namespace ::com::sun::star::beans
;
74 using namespace ::com::sun::star::view
;
75 using namespace ::com::sun::star::task
;
76 using namespace ::com::sun::star::document
;
78 namespace document
= ::com::sun::star::document
;
87 DispatchHolder( URL _aURL
, Reference
< XDispatch
> const & rDispatch
) :
88 aURL(std::move( _aURL
)), xDispatch( rDispatch
) {}
91 Reference
< XDispatch
> xDispatch
;
94 std::shared_ptr
<const SfxFilter
> impl_lookupExportFilterForUrl( std::u16string_view rUrl
, std::u16string_view rFactory
)
96 // create the list of filters
97 OUString sQuery
= "getSortedFilterList()"
99 OUString::Concat(rFactory
) + // use long name here !
101 OUString::number(static_cast<sal_Int32
>(SfxFilterFlags::EXPORT
)) +
103 OUString::number(static_cast<int>(SFX_FILTER_NOTINSTALLED
));
105 const Reference
< XComponentContext
>& xContext( comphelper::getProcessComponentContext() );
106 const Reference
< XContainerQuery
> xFilterFactory(
107 xContext
->getServiceManager()->createInstanceWithContext( u
"com.sun.star.document.FilterFactory"_ustr
, xContext
),
110 std::shared_ptr
<const SfxFilter
> pBestMatch
;
112 const Reference
< XEnumeration
> xFilterEnum(
113 xFilterFactory
->createSubSetEnumerationByQuery( sQuery
), UNO_SET_THROW
);
114 while ( xFilterEnum
->hasMoreElements() )
116 comphelper::SequenceAsHashMap
aFilterProps( xFilterEnum
->nextElement() );
117 const OUString
aName( aFilterProps
.getUnpackedValueOrDefault( u
"Name"_ustr
, OUString() ) );
118 if ( !aName
.isEmpty() )
120 std::shared_ptr
<const SfxFilter
> pFilter( SfxFilter::GetFilterByName( aName
) );
121 if ( pFilter
&& pFilter
->CanExport() && pFilter
->GetWildcard().Matches( rUrl
) )
123 if ( !pBestMatch
|| ( SfxFilterFlags::PREFERED
& pFilter
->GetFilterFlags() ) )
124 pBestMatch
= std::move(pFilter
);
132 std::shared_ptr
<const SfxFilter
> impl_getExportFilterFromUrl(
133 const OUString
& rUrl
, const OUString
& rFactory
)
137 const Reference
< XComponentContext
>& xContext( comphelper::getProcessComponentContext() );
138 const Reference
< document::XTypeDetection
> xTypeDetector(
139 xContext
->getServiceManager()->createInstanceWithContext( u
"com.sun.star.document.TypeDetection"_ustr
, xContext
),
141 const OUString
aTypeName( xTypeDetector
->queryTypeByURL( rUrl
) );
143 std::shared_ptr
<const SfxFilter
> pFilter( SfxFilterMatcher( rFactory
).GetFilter4EA( aTypeName
, SfxFilterFlags::EXPORT
) );
145 pFilter
= impl_lookupExportFilterForUrl( rUrl
, rFactory
);
149 FileBase::getSystemPathFromFileURL( rUrl
, aTempName
);
150 OString aSource
= OUStringToOString ( aTempName
, osl_getThreadTextEncoding() );
151 std::cerr
<< "Error: no export filter for " << aSource
<< " found, aborting." << std::endl
;
156 catch ( const Exception
& )
162 OUString
impl_GuessFilter( const OUString
& rUrlOut
, const OUString
& rDocService
)
165 std::shared_ptr
<const SfxFilter
> pOutFilter
= impl_getExportFilterFromUrl( rUrlOut
, rDocService
);
167 aOutFilter
= pOutFilter
->GetFilterName();
172 /// dump scripts in a document to the console.
173 void scriptCat(const Reference
< XModel
>& xDoc
)
175 Reference
< XEmbeddedScripts
> xScriptAccess( xDoc
, UNO_QUERY
);
178 std::cout
<< "No script access\n";
182 // ignore xScriptAccess->getDialogLibraries() for now
183 Reference
< css::script::XLibraryContainer2
> xLibraries(
184 xScriptAccess
->getBasicLibraries() );
186 if ( !xLibraries
.is() )
188 std::cout
<< "No script libraries\n";
192 const Sequence
< OUString
> aLibNames
= xLibraries
->getElementNames();
193 std::cout
<< "Libraries: " << aLibNames
.getLength() << "\n";
194 for (OUString
const & libName
: aLibNames
)
196 std::cout
<< "Library: '" << libName
<< "' children: ";
197 Reference
< XNameContainer
> xContainer
;
199 if (!xLibraries
->isLibraryLoaded( libName
))
200 xLibraries
->loadLibrary( libName
);
201 xContainer
= Reference
< XNameContainer
>(
202 xLibraries
->getByName( libName
), UNO_QUERY
);
204 catch (const css::uno::Exception
&e
)
206 std::cout
<< "[" << libName
<< "] - failed to load library: " << e
.Message
<< "\n";
209 if( !xContainer
.is() )
213 Sequence
< OUString
> aObjectNames
= xContainer
->getElementNames();
215 std::cout
<< aObjectNames
.getLength() << "\n\n";
216 for ( sal_Int32 j
= 0 ; j
< aObjectNames
.getLength() ; ++j
)
218 const OUString
&rObjectName
= aObjectNames
[j
];
222 Any aCode
= xContainer
->getByName( rObjectName
);
223 OUString aCodeString
;
225 if (! (aCode
>>= aCodeString
) )
226 std::cout
<< "[" << rObjectName
<< "] - error fetching code\n";
228 std::cout
<< "[" << rObjectName
<< "]\n"
229 << aCodeString
.trim()
230 << "\n[/" << rObjectName
<< "]\n";
232 catch (const css::uno::Exception
&e
)
234 std::cout
<< "[" << rObjectName
<< "] - exception " << e
.Message
<< " fetching code\n";
237 if (j
< aObjectNames
.getLength() - 1)
238 std::cout
<< "\n----------------------------------------------------------\n";
245 // Perform batch print
246 void batchPrint( std::u16string_view rPrinterName
, const Reference
< XPrintable
> &xDoc
,
247 const INetURLObject
&aObj
, const OUString
&aName
)
250 OUString aPrinterName
;
251 size_t nPathIndex
= rPrinterName
.rfind( ';' );
252 if( nPathIndex
!= std::u16string_view::npos
)
253 aFilterOut
=rPrinterName
.substr( nPathIndex
+1 );
254 if( nPathIndex
!= 0 )
255 aPrinterName
=rPrinterName
.substr( 0, nPathIndex
);
257 INetURLObject
aOutFilename( aObj
);
258 aOutFilename
.SetExtension( u
"pdf" );
259 FileBase::getFileURLFromSystemPath( aFilterOut
, aFilterOut
);
260 OUString aOutFile
= aFilterOut
+ "/" + aOutFilename
.getName();
263 FileBase::getSystemPathFromFileURL( aName
, aTempName
);
264 OString aSource8
= OUStringToOString ( aTempName
, osl_getThreadTextEncoding() );
265 FileBase::getSystemPathFromFileURL( aOutFile
, aTempName
);
266 OString aTargetURL8
= OUStringToOString(aTempName
, osl_getThreadTextEncoding() );
268 std::cout
<< "print " << aSource8
<< " -> " << aTargetURL8
;
269 std::cout
<< " using " << (aPrinterName
.isEmpty() ? "<default_printer>"_ostr
: OUStringToOString( aPrinterName
, osl_getThreadTextEncoding() ));
270 std::cout
<< std::endl
;
272 // create the custom printer, if given
273 Sequence
< PropertyValue
> aPrinterArgs
;
274 if( !aPrinterName
.isEmpty() )
276 aPrinterArgs
= { comphelper::makePropertyValue(u
"Name"_ustr
, aPrinterName
) };
277 xDoc
->setPrinter( aPrinterArgs
);
280 // print ( also without user interaction )
281 aPrinterArgs
= { comphelper::makePropertyValue(u
"FileName"_ustr
, aOutFile
),
282 comphelper::makePropertyValue(u
"Wait"_ustr
, true) };
283 xDoc
->print( aPrinterArgs
);
286 // Get xDoc module name
287 OUString
getName(const Reference
< XInterface
> & xDoc
)
289 Reference
< XModel
> xModel( xDoc
, UNO_QUERY
);
292 utl::MediaDescriptor
aMediaDesc( xModel
->getArgs() );
293 OUString aDocService
= aMediaDesc
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE
, OUString() );
294 if (aDocService
== "com.sun.star.text.TextDocument")
295 return u
"Writer"_ustr
;
296 else if (aDocService
== "com.sun.star.text.GlobalDocument")
297 return u
"Writer master"_ustr
;
298 else if (aDocService
== "com.sun.star.text.WebDocument")
299 return u
"Writer/Web"_ustr
;
300 else if (aDocService
== "com.sun.star.drawing.DrawingDocument")
302 else if (aDocService
== "com.sun.star.presentation.PresentationDocument")
303 return u
"Impress"_ustr
;
304 else if (aDocService
== "com.sun.star.sheet.SpreadsheetDocument")
306 else if (aDocService
== "com.sun.star.script.BasicIDE")
307 return u
"Basic"_ustr
;
308 else if (aDocService
== "com.sun.star.formula.FormulaProperties")
310 else if (aDocService
== "com.sun.star.sdb.RelationDesign")
311 return u
"Relation Design"_ustr
;
312 else if (aDocService
== "com.sun.star.sdb.QueryDesign")
313 return u
"Query Design"_ustr
;
314 else if (aDocService
== "com.sun.star.sdb.TableDesign")
315 return u
"Table Design"_ustr
;
316 else if (aDocService
== "com.sun.star.sdb.DataSourceBrowser")
317 return u
"Data Source Browser"_ustr
;
318 else if (aDocService
== "com.sun.star.sdb.DatabaseDocument")
319 return u
"Database"_ustr
;
324 } // anonymous namespace
326 DispatchWatcher::DispatchWatcher()
332 DispatchWatcher::~DispatchWatcher()
337 bool DispatchWatcher::executeDispatchRequests( const std::vector
<DispatchRequest
>& aDispatchRequestsList
, bool bNoTerminate
)
339 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
341 std::vector
< DispatchHolder
> aDispatches
;
342 bool bSetInputFilter
= false;
343 OUString aForcedInputFilter
;
345 for (auto const & aDispatchRequest
: aDispatchRequestsList
)
348 if ( aDispatchRequest
.aRequestType
== REQUEST_INFILTER
)
350 bSetInputFilter
= true;
351 aForcedInputFilter
= aDispatchRequest
.aURL
;
352 RequestHandler::RequestsCompleted();
356 // create parameter array
357 std::vector
<PropertyValue
> aArgs
;
359 // mark request as user interaction from outside
360 aArgs
.emplace_back("Referer", 0, Any(u
"private:OpenEvent"_ustr
),
361 PropertyState_DIRECT_VALUE
);
363 OUString
aTarget(u
"_default"_ustr
);
365 if ( aDispatchRequest
.aRequestType
== REQUEST_PRINT
||
366 aDispatchRequest
.aRequestType
== REQUEST_PRINTTO
||
367 aDispatchRequest
.aRequestType
== REQUEST_BATCHPRINT
||
368 aDispatchRequest
.aRequestType
== REQUEST_CONVERSION
||
369 aDispatchRequest
.aRequestType
== REQUEST_CAT
||
370 aDispatchRequest
.aRequestType
== REQUEST_SCRIPT_CAT
)
372 // documents opened for printing are opened readonly because they must be opened as a
373 // new document and this document could be open already
374 aArgs
.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE
);
375 // always open a new document for printing, because it must be disposed afterwards
376 aArgs
.emplace_back("OpenNewView", 0, Any(true), PropertyState_DIRECT_VALUE
);
377 // printing is done in a hidden view
378 aArgs
.emplace_back("Hidden", 0, Any(true), PropertyState_DIRECT_VALUE
);
379 // load document for printing without user interaction
380 aArgs
.emplace_back("Silent", 0, Any(true), PropertyState_DIRECT_VALUE
);
382 // hidden documents should never be put into open tasks
387 Reference
< XInteractionHandler2
> xInteraction(
388 InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
390 aArgs
.emplace_back("InteractionHandler", 0, Any(xInteraction
),
391 PropertyState_DIRECT_VALUE
);
393 aArgs
.emplace_back("MacroExecutionMode", 0,
394 Any(css::document::MacroExecMode::USE_CONFIG
),
395 PropertyState_DIRECT_VALUE
);
397 aArgs
.emplace_back("UpdateDocMode", 0,
398 Any(css::document::UpdateDocMode::ACCORDING_TO_CONFIG
),
399 PropertyState_DIRECT_VALUE
);
402 if ( !aDispatchRequest
.aPreselectedFactory
.isEmpty() )
404 aArgs
.emplace_back(utl::MediaDescriptor::PROP_DOCUMENTSERVICE
, 0,
405 Any(aDispatchRequest
.aPreselectedFactory
),
406 PropertyState_DIRECT_VALUE
);
409 OUString
aName( GetURL_Impl( aDispatchRequest
.aURL
, aDispatchRequest
.aCwdUrl
) );
411 // load the document ... if they are loadable!
412 // Otherwise try to dispatch it ...
413 Reference
< XPrintable
> xDoc
;
415 ( aName
.startsWith( ".uno" ) ) ||
416 ( aName
.startsWith( "slot:" ) ) ||
417 ( aName
.startsWith( "macro:" ) ) ||
418 ( aName
.startsWith("vnd.sun.star.script") )
421 // Attention: URL must be parsed full. Otherwise some detections on it will fail!
422 // It doesn't matter, if parser isn't available. Because; We try loading of URL then ...
424 aURL
.Complete
= aName
;
426 Reference
< XDispatch
> xDispatcher
;
427 Reference
< XURLTransformer
> xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
430 xParser
->parseStrict( aURL
);
432 xDispatcher
= xDesktop
->queryDispatch( aURL
, OUString(), 0 );
434 !xDispatcher
.is(), "desktop.app",
435 "unsupported dispatch request <" << aName
<< ">");
436 if( xDispatcher
.is() )
438 // Remember request so we can find it in statusChanged!
441 // Use local vector to store dispatcher because we have to fill our request container before
442 // we can dispatch. Otherwise it would be possible that statusChanged is called before we dispatched all requests!!
443 aDispatches
.emplace_back( aURL
, xDispatcher
);
446 else if ( aName
.startsWith( "service:" ) )
448 // TODO: the dispatch has to be done for loadComponentFromURL as well.
450 aURL
.Complete
= aName
;
452 Reference
< XDispatch
> xDispatcher
;
453 Reference
< XURLTransformer
> xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
456 xParser
->parseStrict( aURL
);
458 xDispatcher
= xDesktop
->queryDispatch( aURL
, OUString(), 0 );
460 if( xDispatcher
.is() )
464 // We have to be listener to catch errors during dispatching URLs.
465 // Otherwise it would be possible to have an office running without an open
467 Sequence
< PropertyValue
> aArgs2
{ comphelper::makePropertyValue(u
"SynchronMode"_ustr
,
469 Reference
< XNotifyingDispatch
> xDisp( xDispatcher
, UNO_QUERY
);
471 xDisp
->dispatchWithNotification( aURL
, aArgs2
, this );
473 xDispatcher
->dispatch( aURL
, aArgs2
);
475 catch (const css::uno::Exception
&)
477 TOOLS_WARN_EXCEPTION(
479 "Desktop::OpenDefault() ignoring Exception while calling XNotifyingDispatch");
485 INetURLObject
aObj( aName
);
486 if ( aObj
.GetProtocol() == INetProtocol::PrivSoffice
)
487 aTarget
= "_default";
489 // Set "AsTemplate" argument according to request type
490 if ( aDispatchRequest
.aRequestType
== REQUEST_FORCENEW
||
491 aDispatchRequest
.aRequestType
== REQUEST_FORCEOPEN
)
493 aArgs
.emplace_back("AsTemplate", 0,
494 Any(aDispatchRequest
.aRequestType
== REQUEST_FORCENEW
),
495 PropertyState_DIRECT_VALUE
);
498 // if we are called in viewmode, open document read-only
499 if(aDispatchRequest
.aRequestType
== REQUEST_VIEW
) {
500 aArgs
.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE
);
503 // if we are called with --show set Start in mediadescriptor
504 if(aDispatchRequest
.aRequestType
== REQUEST_START
) {
505 const sal_Int32 nStartingSlide
= aDispatchRequest
.aParam
.toInt32();
506 const sal_uInt16 nSlide
= nStartingSlide
> 0 ? nStartingSlide
: 1;
507 aArgs
.emplace_back("StartPresentation", 0, Any(nSlide
), PropertyState_DIRECT_VALUE
);
510 // Force input filter, if possible
511 if( bSetInputFilter
)
513 sal_Int32 nFilterOptionsIndex
= 0;
514 aArgs
.emplace_back("FilterName", 0,
515 Any(aForcedInputFilter
.getToken(0, ':', nFilterOptionsIndex
)),
516 PropertyState_DIRECT_VALUE
);
518 if (0 < nFilterOptionsIndex
)
520 aArgs
.emplace_back("FilterOptions", 0,
521 Any(aForcedInputFilter
.copy(nFilterOptionsIndex
)),
522 PropertyState_DIRECT_VALUE
);
526 // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism.
529 xDoc
.set(comphelper::SynchronousDispatch::dispatch(
530 xDesktop
, aName
, aTarget
, comphelper::containerToSequence(aArgs
)),
533 catch (const css::lang::IllegalArgumentException
&)
535 TOOLS_WARN_EXCEPTION(
537 "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL");
539 catch (const css::io::IOException
&)
541 TOOLS_WARN_EXCEPTION(
543 "Dispatchwatcher IOException while calling loadComponentFromURL");
545 if ( aDispatchRequest
.aRequestType
== REQUEST_OPEN
||
546 aDispatchRequest
.aRequestType
== REQUEST_VIEW
||
547 aDispatchRequest
.aRequestType
== REQUEST_START
||
548 aDispatchRequest
.aRequestType
== REQUEST_FORCEOPEN
||
549 aDispatchRequest
.aRequestType
== REQUEST_FORCENEW
)
551 // request is completed
552 RequestHandler::RequestsCompleted();
554 else if ( aDispatchRequest
.aRequestType
== REQUEST_PRINT
||
555 aDispatchRequest
.aRequestType
== REQUEST_PRINTTO
||
556 aDispatchRequest
.aRequestType
== REQUEST_BATCHPRINT
||
557 aDispatchRequest
.aRequestType
== REQUEST_CONVERSION
||
558 aDispatchRequest
.aRequestType
== REQUEST_CAT
||
559 aDispatchRequest
.aRequestType
== REQUEST_SCRIPT_CAT
)
563 // Do we need to save the document in a different format?
564 if ( aDispatchRequest
.aRequestType
== REQUEST_CONVERSION
||
565 aDispatchRequest
.aRequestType
== REQUEST_CAT
)
567 // FIXME: factor out into a method ...
568 Reference
< XStorable
> xStorable( xDoc
, UNO_QUERY
);
569 if ( xStorable
.is() ) {
570 const OUString
& aParam
= aDispatchRequest
.aParam
;
571 sal_Int32 nPathIndex
= aParam
.lastIndexOf( ';' );
572 sal_Int32 nFilterIndex
= aParam
.indexOf( ':' );
573 sal_Int32 nImgFilterIndex
= aParam
.lastIndexOf( '|' );
574 if( nPathIndex
< nFilterIndex
)
583 if( nFilterIndex
>= 0 )
585 aFilter
= aParam
.copy( nFilterIndex
+1, nPathIndex
-nFilterIndex
-1 );
586 aFilterExt
= aParam
.copy( 0, nFilterIndex
);
592 aFilterExt
= aParam
.copy( 0, nPathIndex
);
595 if( nImgFilterIndex
>= 0 )
597 aImgOut
= aParam
.copy( nImgFilterIndex
+1 );
598 aFilterOut
= aParam
.copy( nPathIndex
+1, nImgFilterIndex
-nPathIndex
-1 );
601 aFilterOut
= aParam
.copy( nPathIndex
+1 );
603 FileBase::getFileURLFromSystemPath( aFilterOut
, aFilterOut
);
604 INetURLObject
aOutFilename(aFilterOut
);
605 aOutFilename
.Append(aObj
.getName(INetURLObject::LAST_SEGMENT
, true,
606 INetURLObject::DecodeMechanism::NONE
));
607 aOutFilename
.SetExtension(aFilterExt
);
609 = aOutFilename
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
611 std::unique_ptr
<utl::TempFileNamed
> fileForCat
;
612 if( aDispatchRequest
.aRequestType
== REQUEST_CAT
)
614 fileForCat
= std::make_unique
<utl::TempFileNamed
>();
615 if (fileForCat
->IsValid())
616 fileForCat
->EnableKillingFile();
618 std::cerr
<< "Error: Cannot create temporary file..." << std::endl
;
619 aOutFile
= fileForCat
->GetURL();
624 OUString aDocService
;
625 Reference
< XModel
> xModel( xDoc
, UNO_QUERY
);
628 utl::MediaDescriptor
aMediaDesc( xModel
->getArgs() );
629 aDocService
= aMediaDesc
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE
, OUString() );
631 aFilter
= impl_GuessFilter( aOutFile
, aDocService
);
634 bool bMultiFileTarget
= false;
636 if (aFilter
.isEmpty())
638 std::cerr
<< "Error: no export filter" << std::endl
;
642 sal_Int32 nFilterOptionsIndex
= aFilter
.indexOf(':');
643 sal_Int32 nProps
= ( 0 < nFilterOptionsIndex
) ? 4 : 3;
645 if ( !aImgOut
.isEmpty() )
647 Sequence
<PropertyValue
> conversionProperties( nProps
);
648 auto pconversionProperties
= conversionProperties
.getArray();
649 pconversionProperties
[0].Name
= "ConversionRequestOrigin";
650 pconversionProperties
[0].Value
<<= u
"CommandLine"_ustr
;
651 pconversionProperties
[1].Name
= "Overwrite";
652 pconversionProperties
[1].Value
<<= true;
654 pconversionProperties
[2].Name
= "FilterName";
655 if( 0 < nFilterOptionsIndex
)
657 OUString sFilterName
= aFilter
.copy(0, nFilterOptionsIndex
);
658 OUString sFilterOptions
= aFilter
.copy(nFilterOptionsIndex
+ 1);
660 if (sFilterName
== "Text - txt - csv (StarCalc)")
663 // If the 11th token is '-1' then we export a file
664 // per sheet where the file name is based on the suggested
665 // output filename concatenated with the sheet name, so adjust
666 // the output and overwrite messages
667 // If the 11th token is not present or numeric 0 then the
668 // default sheet is exported with the output filename. If it
669 // is numeric >0 then that sheet (1-based) with the output
670 // filename concatenated with the sheet name. So even if
671 // that is a single file, the multi file target mechanism is
673 const OUString
aTok(sFilterOptions
.getToken(11, ',', nIdx
));
674 // Actual validity is checked in Calc, here just check for
675 // presence of numeric value at start.
676 bMultiFileTarget
= (!aTok
.isEmpty() && aTok
.toInt32() != 0);
679 pconversionProperties
[2].Value
<<= sFilterName
;
681 pconversionProperties
[3].Name
= "FilterOptions";
682 pconversionProperties
[3].Value
<<= sFilterOptions
;
686 pconversionProperties
[2].Value
<<= aFilter
;
689 if ( !aImgOut
.isEmpty() )
691 assert(conversionProperties
[nProps
-1].Name
.isEmpty());
692 pconversionProperties
[nProps
-1].Name
= "ImageFilter";
693 pconversionProperties
[nProps
-1].Value
<<= aImgOut
;
697 FileBase::getSystemPathFromFileURL(aName
, aTempName
);
698 OString aSource8
= OUStringToOString(aTempName
, osl_getThreadTextEncoding());
699 FileBase::getSystemPathFromFileURL(aOutFile
, aTempName
);
700 OString aTargetURL8
= OUStringToOString(aTempName
, osl_getThreadTextEncoding());
701 if (aDispatchRequest
.aRequestType
!= REQUEST_CAT
)
703 OUString name
=getName(xDoc
);
704 std::cout
<< "convert " << aSource8
;
706 std::cout
<< " as a " << name
<<" document";
707 if (!bMultiFileTarget
)
708 std::cout
<< " -> " << aTargetURL8
;
709 std::cout
<< " using filter : " << OUStringToOString(aFilter
, osl_getThreadTextEncoding()) << std::endl
;
710 if (!bMultiFileTarget
&& FStatHelper::IsDocument(aOutFile
))
711 std::cout
<< "Overwriting: " << OUStringToOString(aTempName
, osl_getThreadTextEncoding()) << std::endl
;
715 xStorable
->storeToURL(aOutFile
, conversionProperties
);
717 catch (const Exception
& rException
)
719 std::cerr
<< "Error: Please verify input parameters...";
720 if (!rException
.Message
.isEmpty())
721 std::cerr
<< " (" << rException
.Message
<< ")";
722 std::cerr
<< std::endl
;
725 if (fileForCat
&& fileForCat
->IsValid())
727 SvStream
* aStream
= fileForCat
->GetStream(StreamMode::STD_READ
);
728 while (aStream
->good())
731 aStream
->ReadLine(aStr
, SAL_MAX_INT32
);
732 for (sal_Int32 i
= 0; i
< aStr
.getLength(); ++i
)
734 std::cout
<< aStr
[i
];
736 std::cout
<< std::endl
;
742 else if ( aDispatchRequest
.aRequestType
== REQUEST_SCRIPT_CAT
)
744 Reference
< XModel
> xModel( xDoc
, UNO_QUERY
);
748 else if ( aDispatchRequest
.aRequestType
== REQUEST_BATCHPRINT
)
750 batchPrint(aDispatchRequest
.aParam
, xDoc
, aObj
, aName
);
754 if ( aDispatchRequest
.aRequestType
== REQUEST_PRINTTO
)
756 // create the printer
757 Sequence
< PropertyValue
> aPrinterArgs
{ comphelper::makePropertyValue(
758 u
"Name"_ustr
, aDispatchRequest
.aParam
) };
759 xDoc
->setPrinter( aPrinterArgs
);
762 // print ( also without user interaction )
763 Sequence
< PropertyValue
> aPrinterArgs
{ comphelper::makePropertyValue(u
"Wait"_ustr
,
765 xDoc
->print( aPrinterArgs
);
770 std::cerr
<< "Error: source file could not be loaded" << std::endl
;
773 // remove the document
776 Reference
< XCloseable
> xClose( xDoc
, UNO_QUERY
);
778 xClose
->close( true );
781 Reference
< XComponent
> xComp( xDoc
, UNO_QUERY
);
786 catch (const css::util::CloseVetoException
&)
790 // request is completed
791 RequestHandler::RequestsCompleted();
796 if ( !aDispatches
.empty() )
798 // Execute all asynchronous dispatches now after we placed them into our request container!
799 Sequence
< PropertyValue
> aArgs
{
800 comphelper::makePropertyValue(u
"Referer"_ustr
, u
"private:OpenEvent"_ustr
),
801 comphelper::makePropertyValue(u
"SynchronMode"_ustr
, true)
804 for (const DispatchHolder
& aDispatche
: aDispatches
)
806 Reference
< XDispatch
> xDispatch
= aDispatche
.xDispatch
;
807 Reference
< XNotifyingDispatch
> xDisp( xDispatch
, UNO_QUERY
);
809 xDisp
->dispatchWithNotification( aDispatche
.aURL
, aArgs
, this );
813 xDispatch
->dispatch( aDispatche
.aURL
, aArgs
);
818 bool bEmpty
= (m_nRequestCount
== 0);
820 // No more asynchronous requests?
821 // The requests are removed from the request container after they called back to this
822 // implementation via statusChanged!!
823 if ( bEmpty
&& !bNoTerminate
/*m_aRequestContainer.empty()*/ )
825 // We have to check if we have an open task otherwise we have to shutdown the office.
826 Reference
< XElementAccess
> xList
= xDesktop
->getFrames();
828 if ( !xList
->hasElements() )
830 // We don't have any task open so we have to shutdown ourself!!
831 return xDesktop
->terminate();
839 void SAL_CALL
DispatchWatcher::disposing( const css::lang::EventObject
& )
844 void SAL_CALL
DispatchWatcher::dispatchFinished( const DispatchResultEvent
& )
846 int nCount
= --m_nRequestCount
;
847 RequestHandler::RequestsCompleted();
848 if ( !nCount
&& !RequestHandler::AreRequestsPending() )
850 // We have to check if we have an open task otherwise we have to shutdown the office.
851 Reference
< XDesktop2
> xDesktop
= css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
852 Reference
< XElementAccess
> xList
= xDesktop
->getFrames();
854 if ( !xList
->hasElements() )
856 // We don't have any task open so we have to shutdown ourself!!
857 xDesktop
->terminate();
862 } // namespace desktop
864 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */