Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / desktop / source / app / dispatchwatcher.cxx
blobb00cff042b7ea0a95343db2ea53b14709ebdfd15
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/docfile.hxx>
24 #include <sfx2/docfilt.hxx>
25 #include <sfx2/fcontnr.hxx>
26 #include <svl/fstathelper.hxx>
28 #include <app.hxx>
29 #include "dispatchwatcher.hxx"
30 #include "officeipcthread.hxx"
31 #include <rtl/ustring.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/synchronousdispatch.hxx>
34 #include <com/sun/star/io/IOException.hpp>
35 #include <com/sun/star/util/XCloseable.hpp>
36 #include <com/sun/star/util/CloseVetoException.hpp>
37 #include <com/sun/star/task/InteractionHandler.hpp>
38 #include <com/sun/star/util/URL.hpp>
39 #include <com/sun/star/frame/Desktop.hpp>
40 #include <com/sun/star/container/XContainerQuery.hpp>
41 #include <com/sun/star/container/XEnumeration.hpp>
42 #include <com/sun/star/frame/XDispatch.hpp>
43 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/view/XPrintable.hpp>
46 #include <com/sun/star/util/URLTransformer.hpp>
47 #include <com/sun/star/util/XURLTransformer.hpp>
48 #include <com/sun/star/document/MacroExecMode.hpp>
49 #include <com/sun/star/document/XTypeDetection.hpp>
50 #include <com/sun/star/document/UpdateDocMode.hpp>
51 #include <com/sun/star/frame/XStorable.hpp>
52 #include <com/sun/star/script/XLibraryContainer2.hpp>
53 #include <com/sun/star/document/XEmbeddedScripts.hpp>
55 #include <comphelper/propertyvalue.hxx>
56 #include <comphelper/sequence.hxx>
57 #include <comphelper/diagnose_ex.hxx>
58 #include <tools/urlobj.hxx>
59 #include <unotools/mediadescriptor.hxx>
60 #include <unotools/tempfile.hxx>
62 #include <osl/thread.hxx>
63 #include <osl/file.hxx>
64 #include <iostream>
65 #include <string_view>
66 #include <utility>
68 using namespace ::osl;
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::util;
71 using namespace ::com::sun::star::lang;
72 using namespace ::com::sun::star::frame;
73 using namespace ::com::sun::star::container;
74 using namespace ::com::sun::star::beans;
75 using namespace ::com::sun::star::view;
76 using namespace ::com::sun::star::task;
77 using namespace ::com::sun::star::document;
79 namespace document = ::com::sun::star::document;
81 namespace desktop
84 namespace {
86 struct DispatchHolder
88 DispatchHolder( URL _aURL, Reference< XDispatch > const & rDispatch ) :
89 aURL(std::move( _aURL )), xDispatch( rDispatch ) {}
91 URL aURL;
92 Reference< XDispatch > xDispatch;
95 std::shared_ptr<const SfxFilter> impl_lookupExportFilterForUrl( std::u16string_view rUrl, std::u16string_view rFactory )
97 // create the list of filters
98 OUString sQuery = "getSortedFilterList()"
99 ":module=" +
100 OUString::Concat(rFactory) + // use long name here !
101 ":iflags=" +
102 OUString::number(static_cast<sal_Int32>(SfxFilterFlags::EXPORT)) +
103 ":eflags=" +
104 OUString::number(static_cast<int>(SFX_FILTER_NOTINSTALLED));
106 const Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
107 const Reference< XContainerQuery > xFilterFactory(
108 xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", xContext ),
109 UNO_QUERY_THROW );
111 std::shared_ptr<const SfxFilter> pBestMatch;
113 const Reference< XEnumeration > xFilterEnum(
114 xFilterFactory->createSubSetEnumerationByQuery( sQuery ), UNO_SET_THROW );
115 while ( xFilterEnum->hasMoreElements() )
117 comphelper::SequenceAsHashMap aFilterProps( xFilterEnum->nextElement() );
118 const OUString aName( aFilterProps.getUnpackedValueOrDefault( "Name", OUString() ) );
119 if ( !aName.isEmpty() )
121 std::shared_ptr<const SfxFilter> pFilter( SfxFilter::GetFilterByName( aName ) );
122 if ( pFilter && pFilter->CanExport() && pFilter->GetWildcard().Matches( rUrl ) )
124 if ( !pBestMatch || ( SfxFilterFlags::PREFERED & pFilter->GetFilterFlags() ) )
125 pBestMatch = pFilter;
130 return pBestMatch;
133 std::shared_ptr<const SfxFilter> impl_getExportFilterFromUrl(
134 const OUString& rUrl, const OUString& rFactory)
138 const Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
139 const Reference< document::XTypeDetection > xTypeDetector(
140 xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", xContext ),
141 UNO_QUERY_THROW );
142 const OUString aTypeName( xTypeDetector->queryTypeByURL( rUrl ) );
144 std::shared_ptr<const SfxFilter> pFilter( SfxFilterMatcher( rFactory ).GetFilter4EA( aTypeName, SfxFilterFlags::EXPORT ) );
145 if ( !pFilter )
146 pFilter = impl_lookupExportFilterForUrl( rUrl, rFactory );
147 if ( !pFilter )
149 OUString aTempName;
150 FileBase::getSystemPathFromFileURL( rUrl, aTempName );
151 OString aSource = OUStringToOString ( aTempName, osl_getThreadTextEncoding() );
152 std::cerr << "Error: no export filter for " << aSource << " found, aborting." << std::endl;
155 return pFilter;
157 catch ( const Exception& )
159 return nullptr;
163 OUString impl_GuessFilter( const OUString& rUrlOut, const OUString& rDocService )
165 OUString aOutFilter;
166 std::shared_ptr<const SfxFilter> pOutFilter = impl_getExportFilterFromUrl( rUrlOut, rDocService );
167 if (pOutFilter)
168 aOutFilter = pOutFilter->GetFilterName();
170 return aOutFilter;
173 /// dump scripts in a document to the console.
174 void scriptCat(const Reference< XModel >& xDoc )
176 Reference< XEmbeddedScripts > xScriptAccess( xDoc, UNO_QUERY );
177 if (!xScriptAccess)
179 std::cout << "No script access\n";
180 return;
183 // ignore xScriptAccess->getDialogLibraries() for now
184 Reference< css::script::XLibraryContainer2 > xLibraries(
185 xScriptAccess->getBasicLibraries() );
187 if ( !xLibraries.is() )
189 std::cout << "No script libraries\n";
190 return;
193 const Sequence< OUString > aLibNames = xLibraries->getElementNames();
194 std::cout << "Libraries: " << aLibNames.getLength() << "\n";
195 for (OUString const & libName : aLibNames)
197 std::cout << "Library: '" << libName << "' children: ";
198 Reference< XNameContainer > xContainer;
199 try {
200 if (!xLibraries->isLibraryLoaded( libName ))
201 xLibraries->loadLibrary( libName );
202 xContainer = Reference< XNameContainer >(
203 xLibraries->getByName( libName ), UNO_QUERY );
205 catch (const css::uno::Exception &e)
207 std::cout << "[" << libName << "] - failed to load library: " << e.Message << "\n";
208 continue;
210 if( !xContainer.is() )
211 std::cout << "0\n";
212 else
214 Sequence< OUString > aObjectNames = xContainer->getElementNames();
216 std::cout << aObjectNames.getLength() << "\n\n";
217 for ( sal_Int32 j = 0 ; j < aObjectNames.getLength() ; ++j )
219 const OUString &rObjectName = aObjectNames[j];
223 Any aCode = xContainer->getByName( rObjectName );
224 OUString aCodeString;
226 if (! (aCode >>= aCodeString ) )
227 std::cout << "[" << rObjectName << "] - error fetching code\n";
228 else
229 std::cout << "[" << rObjectName << "]\n"
230 << aCodeString.trim()
231 << "\n[/" << rObjectName << "]\n";
233 catch (const css::uno::Exception &e)
235 std::cout << "[" << rObjectName << "] - exception " << e.Message << " fetching code\n";
238 if (j < aObjectNames.getLength() - 1)
239 std::cout << "\n----------------------------------------------------------\n";
240 std::cout << "\n";
246 // Perform batch print
247 void batchPrint( std::u16string_view rPrinterName, const Reference< XPrintable > &xDoc,
248 const INetURLObject &aObj, const OUString &aName )
250 OUString aFilterOut;
251 OUString aPrinterName;
252 size_t nPathIndex = rPrinterName.rfind( ';' );
253 if( nPathIndex != std::u16string_view::npos )
254 aFilterOut=rPrinterName.substr( nPathIndex+1 );
255 if( nPathIndex != 0 )
256 aPrinterName=rPrinterName.substr( 0, nPathIndex );
258 INetURLObject aOutFilename( aObj );
259 aOutFilename.SetExtension( u"pdf" );
260 FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut );
261 OUString aOutFile = aFilterOut + "/" + aOutFilename.getName();
263 OUString aTempName;
264 FileBase::getSystemPathFromFileURL( aName, aTempName );
265 OString aSource8 = OUStringToOString ( aTempName, osl_getThreadTextEncoding() );
266 FileBase::getSystemPathFromFileURL( aOutFile, aTempName );
267 OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding() );
269 std::cout << "print " << aSource8 << " -> " << aTargetURL8;
270 std::cout << " using " << (aPrinterName.isEmpty() ? "<default_printer>" : OUStringToOString( aPrinterName, osl_getThreadTextEncoding() ));
271 std::cout << std::endl;
273 // create the custom printer, if given
274 Sequence < PropertyValue > aPrinterArgs;
275 if( !aPrinterName.isEmpty() )
277 aPrinterArgs = { comphelper::makePropertyValue("Name", aPrinterName) };
278 xDoc->setPrinter( aPrinterArgs );
281 // print ( also without user interaction )
282 aPrinterArgs = { comphelper::makePropertyValue("FileName", aOutFile),
283 comphelper::makePropertyValue("Wait", true) };
284 xDoc->print( aPrinterArgs );
287 // Get xDoc module name
288 OUString getName(const Reference< XInterface > & xDoc)
290 Reference< XModel > xModel( xDoc, UNO_QUERY );
291 if (!xModel)
292 return OUString();
293 utl::MediaDescriptor aMediaDesc( xModel->getArgs() );
294 OUString aDocService = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString() );
295 if (aDocService == "com.sun.star.text.TextDocument")
296 return "Writer";
297 else if (aDocService == "com.sun.star.text.GlobalDocument")
298 return "Writer master";
299 else if (aDocService == "com.sun.star.text.WebDocument")
300 return "Writer/Web";
301 else if (aDocService == "com.sun.star.drawing.DrawingDocument")
302 return "Draw";
303 else if (aDocService == "com.sun.star.presentation.PresentationDocument")
304 return "Impress";
305 else if (aDocService == "com.sun.star.sheet.SpreadsheetDocument")
306 return "Calc";
307 else if (aDocService == "com.sun.star.script.BasicIDE")
308 return "Basic";
309 else if (aDocService == "com.sun.star.formula.FormulaProperties")
310 return "Math";
311 else if (aDocService == "com.sun.star.sdb.RelationDesign")
312 return "Relation Design";
313 else if (aDocService == "com.sun.star.sdb.QueryDesign")
314 return "Query Design";
315 else if (aDocService == "com.sun.star.sdb.TableDesign")
316 return "Table Design";
317 else if (aDocService == "com.sun.star.sdb.DataSourceBrowser")
318 return "Data Source Browser";
319 else if (aDocService == "com.sun.star.sdb.DatabaseDocument")
320 return "Database";
322 return OUString();
325 } // anonymous namespace
327 DispatchWatcher::DispatchWatcher()
328 : m_nRequestCount(0)
333 DispatchWatcher::~DispatchWatcher()
338 bool DispatchWatcher::executeDispatchRequests( const std::vector<DispatchRequest>& aDispatchRequestsList, bool bNoTerminate )
340 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
342 std::vector< DispatchHolder > aDispatches;
343 bool bSetInputFilter = false;
344 OUString aForcedInputFilter;
346 for (auto const & aDispatchRequest: aDispatchRequestsList)
348 // Set Input Filter
349 if ( aDispatchRequest.aRequestType == REQUEST_INFILTER )
351 bSetInputFilter = true;
352 aForcedInputFilter = aDispatchRequest.aURL;
353 RequestHandler::RequestsCompleted();
354 continue;
357 // create parameter array
358 std::vector<PropertyValue> aArgs;
360 // mark request as user interaction from outside
361 aArgs.emplace_back("Referer", 0, Any(OUString("private:OpenEvent")),
362 PropertyState_DIRECT_VALUE);
364 OUString aTarget("_default");
366 if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
367 aDispatchRequest.aRequestType == REQUEST_PRINTTO ||
368 aDispatchRequest.aRequestType == REQUEST_BATCHPRINT ||
369 aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
370 aDispatchRequest.aRequestType == REQUEST_CAT ||
371 aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT)
373 // documents opened for printing are opened readonly because they must be opened as a
374 // new document and this document could be open already
375 aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE);
376 // always open a new document for printing, because it must be disposed afterwards
377 aArgs.emplace_back("OpenNewView", 0, Any(true), PropertyState_DIRECT_VALUE);
378 // printing is done in a hidden view
379 aArgs.emplace_back("Hidden", 0, Any(true), PropertyState_DIRECT_VALUE);
380 // load document for printing without user interaction
381 aArgs.emplace_back("Silent", 0, Any(true), PropertyState_DIRECT_VALUE);
383 // hidden documents should never be put into open tasks
384 aTarget = "_blank";
386 else
388 Reference < XInteractionHandler2 > xInteraction(
389 InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
391 aArgs.emplace_back("InteractionHandler", 0, Any(xInteraction),
392 PropertyState_DIRECT_VALUE);
394 aArgs.emplace_back("MacroExecutionMode", 0,
395 Any(css::document::MacroExecMode::USE_CONFIG),
396 PropertyState_DIRECT_VALUE);
398 aArgs.emplace_back("UpdateDocMode", 0,
399 Any(css::document::UpdateDocMode::ACCORDING_TO_CONFIG),
400 PropertyState_DIRECT_VALUE);
403 if ( !aDispatchRequest.aPreselectedFactory.isEmpty() )
405 aArgs.emplace_back(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, 0,
406 Any(aDispatchRequest.aPreselectedFactory),
407 PropertyState_DIRECT_VALUE);
410 OUString aName( GetURL_Impl( aDispatchRequest.aURL, aDispatchRequest.aCwdUrl ) );
412 // load the document ... if they are loadable!
413 // Otherwise try to dispatch it ...
414 Reference < XPrintable > xDoc;
416 ( aName.startsWith( ".uno" ) ) ||
417 ( aName.startsWith( "slot:" ) ) ||
418 ( aName.startsWith( "macro:" ) ) ||
419 ( aName.startsWith("vnd.sun.star.script") )
422 // Attention: URL must be parsed full. Otherwise some detections on it will fail!
423 // It doesn't matter, if parser isn't available. Because; We try loading of URL then ...
424 URL aURL ;
425 aURL.Complete = aName;
427 Reference < XDispatch > xDispatcher ;
428 Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
430 if( xParser.is() )
431 xParser->parseStrict( aURL );
433 xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 );
434 SAL_WARN_IF(
435 !xDispatcher.is(), "desktop.app",
436 "unsupported dispatch request <" << aName << ">");
437 if( xDispatcher.is() )
439 // Remember request so we can find it in statusChanged!
440 m_nRequestCount++;
442 // Use local vector to store dispatcher because we have to fill our request container before
443 // we can dispatch. Otherwise it would be possible that statusChanged is called before we dispatched all requests!!
444 aDispatches.emplace_back( aURL, xDispatcher );
447 else if ( aName.startsWith( "service:" ) )
449 // TODO: the dispatch has to be done for loadComponentFromURL as well.
450 URL aURL ;
451 aURL.Complete = aName;
453 Reference < XDispatch > xDispatcher ;
454 Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
456 if( xParser.is() )
457 xParser->parseStrict( aURL );
459 xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 );
461 if( xDispatcher.is() )
465 // We have to be listener to catch errors during dispatching URLs.
466 // Otherwise it would be possible to have an office running without an open
467 // window!!
468 Sequence < PropertyValue > aArgs2{ comphelper::makePropertyValue("SynchronMode",
469 true) };
470 Reference < XNotifyingDispatch > xDisp( xDispatcher, UNO_QUERY );
471 if ( xDisp.is() )
472 xDisp->dispatchWithNotification( aURL, aArgs2, this );
473 else
474 xDispatcher->dispatch( aURL, aArgs2 );
476 catch (const css::uno::Exception&)
478 TOOLS_WARN_EXCEPTION(
479 "desktop.app",
480 "Desktop::OpenDefault() ignoring Exception while calling XNotifyingDispatch");
484 else
486 INetURLObject aObj( aName );
487 if ( aObj.GetProtocol() == INetProtocol::PrivSoffice )
488 aTarget = "_default";
490 // Set "AsTemplate" argument according to request type
491 if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW ||
492 aDispatchRequest.aRequestType == REQUEST_FORCEOPEN )
494 aArgs.emplace_back("AsTemplate", 0,
495 Any(aDispatchRequest.aRequestType == REQUEST_FORCENEW),
496 PropertyState_DIRECT_VALUE);
499 // if we are called in viewmode, open document read-only
500 if(aDispatchRequest.aRequestType == REQUEST_VIEW) {
501 aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE);
504 // if we are called with --show set Start in mediadescriptor
505 if(aDispatchRequest.aRequestType == REQUEST_START) {
506 aArgs.emplace_back("StartPresentation", 0, Any(true), PropertyState_DIRECT_VALUE);
509 // Force input filter, if possible
510 if( bSetInputFilter )
512 sal_Int32 nFilterOptionsIndex = 0;
513 aArgs.emplace_back("FilterName", 0,
514 Any(aForcedInputFilter.getToken(0, ':', nFilterOptionsIndex)),
515 PropertyState_DIRECT_VALUE);
517 if (0 < nFilterOptionsIndex)
519 aArgs.emplace_back("FilterOptions", 0,
520 Any(aForcedInputFilter.copy(nFilterOptionsIndex)),
521 PropertyState_DIRECT_VALUE);
525 // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism.
528 xDoc.set(comphelper::SynchronousDispatch::dispatch(
529 xDesktop, aName, aTarget, comphelper::containerToSequence(aArgs)),
530 UNO_QUERY);
532 catch (const css::lang::IllegalArgumentException&)
534 TOOLS_WARN_EXCEPTION(
535 "desktop.app",
536 "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL");
538 catch (const css::io::IOException&)
540 TOOLS_WARN_EXCEPTION(
541 "desktop.app",
542 "Dispatchwatcher IOException while calling loadComponentFromURL");
544 if ( aDispatchRequest.aRequestType == REQUEST_OPEN ||
545 aDispatchRequest.aRequestType == REQUEST_VIEW ||
546 aDispatchRequest.aRequestType == REQUEST_START ||
547 aDispatchRequest.aRequestType == REQUEST_FORCEOPEN ||
548 aDispatchRequest.aRequestType == REQUEST_FORCENEW )
550 // request is completed
551 RequestHandler::RequestsCompleted();
553 else if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
554 aDispatchRequest.aRequestType == REQUEST_PRINTTO ||
555 aDispatchRequest.aRequestType == REQUEST_BATCHPRINT ||
556 aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
557 aDispatchRequest.aRequestType == REQUEST_CAT ||
558 aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT )
560 if ( xDoc.is() )
562 // Do we need to save the document in a different format?
563 if ( aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
564 aDispatchRequest.aRequestType == REQUEST_CAT )
566 // FIXME: factor out into a method ...
567 Reference< XStorable > xStorable( xDoc, UNO_QUERY );
568 if ( xStorable.is() ) {
569 OUString aParam = aDispatchRequest.aPrinterName;
570 sal_Int32 nPathIndex = aParam.lastIndexOf( ';' );
571 sal_Int32 nFilterIndex = aParam.indexOf( ':' );
572 sal_Int32 nImgFilterIndex = aParam.lastIndexOf( '|' );
573 if( nPathIndex < nFilterIndex )
574 nFilterIndex = -1;
576 OUString aFilterOut;
577 OUString aImgOut;
578 OUString aFilter;
579 OUString aFilterExt;
580 bool bGuess = false;
582 if( nFilterIndex >= 0 )
584 aFilter = aParam.copy( nFilterIndex+1, nPathIndex-nFilterIndex-1 );
585 aFilterExt = aParam.copy( 0, nFilterIndex );
587 else
589 // Guess
590 bGuess = true;
591 aFilterExt = aParam.copy( 0, nPathIndex );
594 if( nImgFilterIndex >= 0 )
596 aImgOut = aParam.copy( nImgFilterIndex+1 );
597 aFilterOut = aParam.copy( nPathIndex+1, nImgFilterIndex-nPathIndex-1 );
599 else
600 aFilterOut = aParam.copy( nPathIndex+1 );
602 FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut );
603 INetURLObject aOutFilename(aFilterOut);
604 aOutFilename.Append(aObj.getName(INetURLObject::LAST_SEGMENT, true,
605 INetURLObject::DecodeMechanism::NONE));
606 aOutFilename.SetExtension(aFilterExt);
607 OUString aOutFile
608 = aOutFilename.GetMainURL(INetURLObject::DecodeMechanism::NONE);
610 std::unique_ptr<utl::TempFileNamed> fileForCat;
611 if( aDispatchRequest.aRequestType == REQUEST_CAT )
613 fileForCat = std::make_unique<utl::TempFileNamed>();
614 if (fileForCat->IsValid())
615 fileForCat->EnableKillingFile();
616 else
617 std::cerr << "Error: Cannot create temporary file..." << std::endl ;
618 aOutFile = fileForCat->GetURL();
621 if ( bGuess )
623 OUString aDocService;
624 Reference< XModel > xModel( xDoc, UNO_QUERY );
625 if ( xModel.is() )
627 utl::MediaDescriptor aMediaDesc( xModel->getArgs() );
628 aDocService = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString() );
630 aFilter = impl_GuessFilter( aOutFile, aDocService );
633 bool bMultiFileTarget = false;
635 if (aFilter.isEmpty())
637 std::cerr << "Error: no export filter" << std::endl;
639 else
641 sal_Int32 nFilterOptionsIndex = aFilter.indexOf(':');
642 sal_Int32 nProps = ( 0 < nFilterOptionsIndex ) ? 4 : 3;
644 if ( !aImgOut.isEmpty() )
645 nProps +=1;
646 Sequence<PropertyValue> conversionProperties( nProps );
647 auto pconversionProperties = conversionProperties.getArray();
648 pconversionProperties[0].Name = "ConversionRequestOrigin";
649 pconversionProperties[0].Value <<= OUString("CommandLine");
650 pconversionProperties[1].Name = "Overwrite";
651 pconversionProperties[1].Value <<= true;
653 pconversionProperties[2].Name = "FilterName";
654 if( 0 < nFilterOptionsIndex )
656 OUString sFilterName = aFilter.copy(0, nFilterOptionsIndex);
657 OUString sFilterOptions = aFilter.copy(nFilterOptionsIndex + 1);
659 if (sFilterName == "Text - txt - csv (StarCalc)")
661 sal_Int32 nIdx(0);
662 // If the 11th token is '-1' then we export a file
663 // per sheet where the file name is based on the suggested
664 // output filename concatenated with the sheet name, so adjust
665 // the output and overwrite messages
666 // If the 11th token is not present or numeric 0 then the
667 // default sheet is exported with the output filename. If it
668 // is numeric >0 then that sheet (1-based) with the output
669 // filename concatenated with the sheet name. So even if
670 // that is a single file, the multi file target mechanism is
671 // used.
672 const OUString aTok(sFilterOptions.getToken(11, ',', nIdx));
673 // Actual validity is checked in Calc, here just check for
674 // presence of numeric value at start.
675 bMultiFileTarget = (!aTok.isEmpty() && aTok.toInt32() != 0);
678 pconversionProperties[2].Value <<= sFilterName;
680 pconversionProperties[3].Name = "FilterOptions";
681 pconversionProperties[3].Value <<= sFilterOptions;
683 else
685 pconversionProperties[2].Value <<= aFilter;
688 if ( !aImgOut.isEmpty() )
690 assert(conversionProperties[nProps-1].Name.isEmpty());
691 pconversionProperties[nProps-1].Name = "ImageFilter";
692 pconversionProperties[nProps-1].Value <<= aImgOut;
695 OUString aTempName;
696 FileBase::getSystemPathFromFileURL(aName, aTempName);
697 OString aSource8 = OUStringToOString(aTempName, osl_getThreadTextEncoding());
698 FileBase::getSystemPathFromFileURL(aOutFile, aTempName);
699 OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding());
700 if (aDispatchRequest.aRequestType != REQUEST_CAT)
702 OUString name=getName(xDoc);
703 std::cout << "convert " << aSource8;
704 if (!name.isEmpty())
705 std::cout << " as a " << name <<" document";
706 if (!bMultiFileTarget)
707 std::cout << " -> " << aTargetURL8;
708 std::cout << " using filter : " << OUStringToOString(aFilter, osl_getThreadTextEncoding()) << std::endl;
709 if (!bMultiFileTarget && FStatHelper::IsDocument(aOutFile))
710 std::cout << "Overwriting: " << OUStringToOString(aTempName, osl_getThreadTextEncoding()) << std::endl ;
714 xStorable->storeToURL(aOutFile, conversionProperties);
716 catch (const Exception& rException)
718 std::cerr << "Error: Please verify input parameters...";
719 if (!rException.Message.isEmpty())
720 std::cerr << " (" << rException.Message << ")";
721 std::cerr << std::endl;
724 if (fileForCat && fileForCat->IsValid())
726 SvStream* aStream = fileForCat->GetStream(StreamMode::STD_READ);
727 while (aStream->good())
729 OString aStr;
730 aStream->ReadLine(aStr, SAL_MAX_INT32);
731 for (sal_Int32 i = 0; i < aStr.getLength(); ++i)
733 std::cout << aStr[i];
735 std::cout << std::endl;
741 else if ( aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT )
743 Reference< XModel > xModel( xDoc, UNO_QUERY );
744 if( xModel.is() )
745 scriptCat( xModel );
747 else if ( aDispatchRequest.aRequestType == REQUEST_BATCHPRINT )
749 batchPrint( aDispatchRequest.aPrinterName, xDoc, aObj, aName );
751 else
753 if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO )
755 // create the printer
756 Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue(
757 "Name", aDispatchRequest.aPrinterName) };
758 xDoc->setPrinter( aPrinterArgs );
761 // print ( also without user interaction )
762 Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue("Wait",
763 true) };
764 xDoc->print( aPrinterArgs );
767 else
769 std::cerr << "Error: source file could not be loaded" << std::endl;
772 // remove the document
775 Reference < XCloseable > xClose( xDoc, UNO_QUERY );
776 if ( xClose.is() )
777 xClose->close( true );
778 else
780 Reference < XComponent > xComp( xDoc, UNO_QUERY );
781 if ( xComp.is() )
782 xComp->dispose();
785 catch (const css::util::CloseVetoException&)
789 // request is completed
790 RequestHandler::RequestsCompleted();
795 if ( !aDispatches.empty() )
797 // Execute all asynchronous dispatches now after we placed them into our request container!
798 Sequence < PropertyValue > aArgs{
799 comphelper::makePropertyValue("Referer", OUString("private:OpenEvent")),
800 comphelper::makePropertyValue("SynchronMode", true)
803 for (const DispatchHolder & aDispatche : aDispatches)
805 Reference< XDispatch > xDispatch = aDispatche.xDispatch;
806 Reference < XNotifyingDispatch > xDisp( xDispatch, UNO_QUERY );
807 if ( xDisp.is() )
808 xDisp->dispatchWithNotification( aDispatche.aURL, aArgs, this );
809 else
811 m_nRequestCount--;
812 xDispatch->dispatch( aDispatche.aURL, aArgs );
817 bool bEmpty = (m_nRequestCount == 0);
819 // No more asynchronous requests?
820 // The requests are removed from the request container after they called back to this
821 // implementation via statusChanged!!
822 if ( bEmpty && !bNoTerminate /*m_aRequestContainer.empty()*/ )
824 // We have to check if we have an open task otherwise we have to shutdown the office.
825 Reference< XElementAccess > xList = xDesktop->getFrames();
827 if ( !xList->hasElements() )
829 // We don't have any task open so we have to shutdown ourself!!
830 return xDesktop->terminate();
834 return false;
838 void SAL_CALL DispatchWatcher::disposing( const css::lang::EventObject& )
843 void SAL_CALL DispatchWatcher::dispatchFinished( const DispatchResultEvent& )
845 int nCount = --m_nRequestCount;
846 RequestHandler::RequestsCompleted();
847 if ( !nCount && !RequestHandler::AreRequestsPending() )
849 // We have to check if we have an open task otherwise we have to shutdown the office.
850 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
851 Reference< XElementAccess > xList = xDesktop->getFrames();
853 if ( !xList->hasElements() )
855 // We don't have any task open so we have to shutdown ourself!!
856 xDesktop->terminate();
861 } // namespace desktop
863 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */