LibreOffice Module desktop (master)  1
dispatchwatcher.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
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>
27 
28 #include <app.hxx>
29 #include "dispatchwatcher.hxx"
30 #include "officeipcthread.hxx"
31 #include <rtl/ustring.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>
54 
56 #include <comphelper/sequence.hxx>
57 #include <tools/diagnose_ex.h>
58 #include <tools/urlobj.hxx>
60 #include <unotools/tempfile.hxx>
61 
62 #include <osl/thread.hxx>
63 #include <osl/file.hxx>
64 #include <iostream>
65 #include <string_view>
66 
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;
77 
78 namespace document = ::com::sun::star::document;
79 
80 namespace desktop
81 {
82 
83 namespace {
84 
85 struct DispatchHolder
86 {
87  DispatchHolder( const URL& rURL, Reference< XDispatch > const & rDispatch ) :
88  aURL( rURL ), xDispatch( rDispatch ) {}
89 
91  Reference< XDispatch > xDispatch;
92 };
93 
94 std::shared_ptr<const SfxFilter> impl_lookupExportFilterForUrl( std::u16string_view rUrl, std::u16string_view rFactory )
95 {
96  // create the list of filters
97  OUString sQuery = "getSortedFilterList()"
98  ":module=" +
99  OUString::Concat(rFactory) + // use long name here !
100  ":iflags=" +
101  OUString::number(static_cast<sal_Int32>(SfxFilterFlags::EXPORT)) +
102  ":eflags=" +
103  OUString::number(static_cast<int>(SFX_FILTER_NOTINSTALLED));
104 
106  const Reference< XContainerQuery > xFilterFactory(
107  xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.FilterFactory", xContext ),
108  UNO_QUERY_THROW );
109 
110  std::shared_ptr<const SfxFilter> pBestMatch;
111 
112  const Reference< XEnumeration > xFilterEnum(
113  xFilterFactory->createSubSetEnumerationByQuery( sQuery ), UNO_SET_THROW );
114  while ( xFilterEnum->hasMoreElements() )
115  {
116  comphelper::SequenceAsHashMap aFilterProps( xFilterEnum->nextElement() );
117  const OUString aName( aFilterProps.getUnpackedValueOrDefault( "Name", OUString() ) );
118  if ( !aName.isEmpty() )
119  {
120  std::shared_ptr<const SfxFilter> pFilter( SfxFilter::GetFilterByName( aName ) );
121  if ( pFilter && pFilter->CanExport() && pFilter->GetWildcard().Matches( rUrl ) )
122  {
123  if ( !pBestMatch || ( SfxFilterFlags::PREFERED & pFilter->GetFilterFlags() ) )
124  pBestMatch = pFilter;
125  }
126  }
127  }
128 
129  return pBestMatch;
130 }
131 
132 std::shared_ptr<const SfxFilter> impl_getExportFilterFromUrl(
133  const OUString& rUrl, const OUString& rFactory)
134 {
135  try
136  {
138  const Reference< document::XTypeDetection > xTypeDetector(
139  xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.TypeDetection", xContext ),
140  UNO_QUERY_THROW );
141  const OUString aTypeName( xTypeDetector->queryTypeByURL( rUrl ) );
142 
143  std::shared_ptr<const SfxFilter> pFilter( SfxFilterMatcher( rFactory ).GetFilter4EA( aTypeName, SfxFilterFlags::EXPORT ) );
144  if ( !pFilter )
145  pFilter = impl_lookupExportFilterForUrl( rUrl, rFactory );
146  if ( !pFilter )
147  {
148  OUString aTempName;
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;
152  }
153 
154  return pFilter;
155  }
156  catch ( const Exception& )
157  {
158  return nullptr;
159  }
160 }
161 
162 OUString impl_GuessFilter( const OUString& rUrlOut, const OUString& rDocService )
163 {
164  OUString aOutFilter;
165  std::shared_ptr<const SfxFilter> pOutFilter = impl_getExportFilterFromUrl( rUrlOut, rDocService );
166  if (pOutFilter)
167  aOutFilter = pOutFilter->GetFilterName();
168 
169  return aOutFilter;
170 }
171 
173 void scriptCat(const Reference< XModel >& xDoc )
174 {
175  Reference< XEmbeddedScripts > xScriptAccess( xDoc, UNO_QUERY );
176  if (!xScriptAccess)
177  {
178  std::cout << "No script access\n";
179  return;
180  }
181 
182  // ignore xScriptAccess->getDialogLibraries() for now
183  Reference< css::script::XLibraryContainer2 > xLibraries(
184  xScriptAccess->getBasicLibraries() );
185 
186  if ( !xLibraries.is() )
187  {
188  std::cout << "No script libraries\n";
189  return;
190  }
191 
192  const Sequence< OUString > aLibNames = xLibraries->getElementNames();
193  std::cout << "Libraries: " << aLibNames.getLength() << "\n";
194  for (OUString const & libName : aLibNames)
195  {
196  std::cout << "Library: '" << libName << "' children: ";
197  Reference< XNameContainer > xContainer;
198  try {
199  if (!xLibraries->isLibraryLoaded( libName ))
200  xLibraries->loadLibrary( libName );
201  xContainer = Reference< XNameContainer >(
202  xLibraries->getByName( libName ), UNO_QUERY );
203  }
204  catch (const css::uno::Exception &e)
205  {
206  std::cout << "[" << libName << "] - failed to load library: " << e.Message << "\n";
207  continue;
208  }
209  if( !xContainer.is() )
210  std::cout << "0\n";
211  else
212  {
213  Sequence< OUString > aObjectNames = xContainer->getElementNames();
214 
215  std::cout << aObjectNames.getLength() << "\n\n";
216  for ( sal_Int32 j = 0 ; j < aObjectNames.getLength() ; ++j )
217  {
218  const OUString &rObjectName = aObjectNames[j];
219 
220  try
221  {
222  Any aCode = xContainer->getByName( rObjectName );
223  OUString aCodeString;
224 
225  if (! (aCode >>= aCodeString ) )
226  std::cout << "[" << rObjectName << "] - error fetching code\n";
227  else
228  std::cout << "[" << rObjectName << "]\n"
229  << aCodeString.trim()
230  << "\n[/" << rObjectName << "]\n";
231  }
232  catch (const css::uno::Exception &e)
233  {
234  std::cout << "[" << rObjectName << "] - exception " << e.Message << " fetching code\n";
235  }
236 
237  if (j < aObjectNames.getLength() - 1)
238  std::cout << "\n----------------------------------------------------------\n";
239  std::cout << "\n";
240  }
241  }
242  }
243 }
244 
245 // Perform batch print
246 void batchPrint( std::u16string_view rPrinterName, const Reference< XPrintable > &xDoc,
247  const INetURLObject &aObj, const OUString &aName )
248 {
249  OUString aFilterOut;
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 );
256 
257  INetURLObject aOutFilename( aObj );
258  aOutFilename.SetExtension( u"pdf" );
259  FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut );
260  OUString aOutFile = aFilterOut + "/" + aOutFilename.getName();
261 
262  OUString aTempName;
263  FileBase::getSystemPathFromFileURL( aName, aTempName );
264  OString aSource8 = OUStringToOString ( aTempName, osl_getThreadTextEncoding() );
265  FileBase::getSystemPathFromFileURL( aOutFile, aTempName );
266  OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding() );
267 
268  std::cout << "print " << aSource8 << " -> " << aTargetURL8;
269  std::cout << " using " << (aPrinterName.isEmpty() ? "<default_printer>" : OUStringToOString( aPrinterName, osl_getThreadTextEncoding() ));
270  std::cout << std::endl;
271 
272  // create the custom printer, if given
273  Sequence < PropertyValue > aPrinterArgs;
274  if( !aPrinterName.isEmpty() )
275  {
276  aPrinterArgs = { comphelper::makePropertyValue("Name", aPrinterName) };
277  xDoc->setPrinter( aPrinterArgs );
278  }
279 
280  // print ( also without user interaction )
281  aPrinterArgs = { comphelper::makePropertyValue("FileName", aOutFile),
282  comphelper::makePropertyValue("Wait", true) };
283  xDoc->print( aPrinterArgs );
284 }
285 
286 } // anonymous namespace
287 
289  : m_nRequestCount(0)
290 {
291 }
292 
293 
295 {
296 }
297 
298 
299 bool DispatchWatcher::executeDispatchRequests( const std::vector<DispatchRequest>& aDispatchRequestsList, bool bNoTerminate )
300 {
301  Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
302 
303  std::vector< DispatchHolder > aDispatches;
304  bool bSetInputFilter = false;
305  OUString aForcedInputFilter;
306 
307  for (auto const & aDispatchRequest: aDispatchRequestsList)
308  {
309  // Set Input Filter
310  if ( aDispatchRequest.aRequestType == REQUEST_INFILTER )
311  {
312  bSetInputFilter = true;
313  aForcedInputFilter = aDispatchRequest.aURL;
315  continue;
316  }
317 
318  // create parameter array
319  std::vector<PropertyValue> aArgs;
320 
321  // mark request as user interaction from outside
322  aArgs.emplace_back("Referer", 0, Any(OUString("private:OpenEvent")),
323  PropertyState_DIRECT_VALUE);
324 
325  OUString aTarget("_default");
326 
327  if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
328  aDispatchRequest.aRequestType == REQUEST_PRINTTO ||
329  aDispatchRequest.aRequestType == REQUEST_BATCHPRINT ||
330  aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
331  aDispatchRequest.aRequestType == REQUEST_CAT ||
332  aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT)
333  {
334  // documents opened for printing are opened readonly because they must be opened as a
335  // new document and this document could be open already
336  aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE);
337  // always open a new document for printing, because it must be disposed afterwards
338  aArgs.emplace_back("OpenNewView", 0, Any(true), PropertyState_DIRECT_VALUE);
339  // printing is done in a hidden view
340  aArgs.emplace_back("Hidden", 0, Any(true), PropertyState_DIRECT_VALUE);
341  // load document for printing without user interaction
342  aArgs.emplace_back("Silent", 0, Any(true), PropertyState_DIRECT_VALUE);
343 
344  // hidden documents should never be put into open tasks
345  aTarget = "_blank";
346  }
347  else
348  {
349  Reference < XInteractionHandler2 > xInteraction(
350  InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
351 
352  aArgs.emplace_back("InteractionHandler", 0, Any(xInteraction),
353  PropertyState_DIRECT_VALUE);
354 
355  aArgs.emplace_back("MacroExecutionMode", 0,
356  Any(css::document::MacroExecMode::USE_CONFIG),
357  PropertyState_DIRECT_VALUE);
358 
359  aArgs.emplace_back("UpdateDocMode", 0,
360  Any(css::document::UpdateDocMode::ACCORDING_TO_CONFIG),
361  PropertyState_DIRECT_VALUE);
362  }
363 
364  if ( !aDispatchRequest.aPreselectedFactory.isEmpty() )
365  {
366  aArgs.emplace_back(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, 0,
367  Any(aDispatchRequest.aPreselectedFactory),
368  PropertyState_DIRECT_VALUE);
369  }
370 
371  OUString aName( GetURL_Impl( aDispatchRequest.aURL, aDispatchRequest.aCwdUrl ) );
372 
373  // load the document ... if they are loadable!
374  // Otherwise try to dispatch it ...
375  Reference < XPrintable > xDoc;
376  if(
377  ( aName.startsWith( ".uno" ) ) ||
378  ( aName.startsWith( "slot:" ) ) ||
379  ( aName.startsWith( "macro:" ) ) ||
380  ( aName.startsWith("vnd.sun.star.script") )
381  )
382  {
383  // Attention: URL must be parsed full. Otherwise some detections on it will fail!
384  // It doesn't matter, if parser isn't available. Because; We try loading of URL then ...
385  URL aURL ;
386  aURL.Complete = aName;
387 
388  Reference < XDispatch > xDispatcher ;
389  Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
390 
391  if( xParser.is() )
392  xParser->parseStrict( aURL );
393 
394  xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 );
395  SAL_WARN_IF(
396  !xDispatcher.is(), "desktop.app",
397  "unsupported dispatch request <" << aName << ">");
398  if( xDispatcher.is() )
399  {
400  {
401  osl::MutexGuard aGuard(m_mutex);
402  // Remember request so we can find it in statusChanged!
403  m_nRequestCount++;
404  }
405 
406  // Use local vector to store dispatcher because we have to fill our request container before
407  // we can dispatch. Otherwise it would be possible that statusChanged is called before we dispatched all requests!!
408  aDispatches.emplace_back( aURL, xDispatcher );
409  }
410  }
411  else if ( aName.startsWith( "service:" ) )
412  {
413  // TODO: the dispatch has to be done for loadComponentFromURL as well.
414  URL aURL ;
415  aURL.Complete = aName;
416 
417  Reference < XDispatch > xDispatcher ;
418  Reference < XURLTransformer > xParser ( URLTransformer::create(::comphelper::getProcessComponentContext()) );
419 
420  if( xParser.is() )
421  xParser->parseStrict( aURL );
422 
423  xDispatcher = xDesktop->queryDispatch( aURL, OUString(), 0 );
424 
425  if( xDispatcher.is() )
426  {
427  try
428  {
429  // We have to be listener to catch errors during dispatching URLs.
430  // Otherwise it would be possible to have an office running without an open
431  // window!!
432  Sequence < PropertyValue > aArgs2{ comphelper::makePropertyValue("SynchronMode",
433  true) };
434  Reference < XNotifyingDispatch > xDisp( xDispatcher, UNO_QUERY );
435  if ( xDisp.is() )
436  xDisp->dispatchWithNotification( aURL, aArgs2, this );
437  else
438  xDispatcher->dispatch( aURL, aArgs2 );
439  }
440  catch (const css::uno::Exception&)
441  {
443  "desktop.app",
444  "Desktop::OpenDefault() ignoring Exception while calling XNotifyingDispatch");
445  }
446  }
447  }
448  else
449  {
450  INetURLObject aObj( aName );
451  if ( aObj.GetProtocol() == INetProtocol::PrivSoffice )
452  aTarget = "_default";
453 
454  // Set "AsTemplate" argument according to request type
455  if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW ||
456  aDispatchRequest.aRequestType == REQUEST_FORCEOPEN )
457  {
458  aArgs.emplace_back("AsTemplate", 0,
459  Any(aDispatchRequest.aRequestType == REQUEST_FORCENEW),
460  PropertyState_DIRECT_VALUE);
461  }
462 
463  // if we are called in viewmode, open document read-only
464  if(aDispatchRequest.aRequestType == REQUEST_VIEW) {
465  aArgs.emplace_back("ReadOnly", 0, Any(true), PropertyState_DIRECT_VALUE);
466  }
467 
468  // if we are called with --show set Start in mediadescriptor
469  if(aDispatchRequest.aRequestType == REQUEST_START) {
470  aArgs.emplace_back("StartPresentation", 0, Any(true), PropertyState_DIRECT_VALUE);
471  }
472 
473  // Force input filter, if possible
474  if( bSetInputFilter )
475  {
476  sal_Int32 nFilterOptionsIndex = 0;
477  aArgs.emplace_back("FilterName", 0,
478  Any(aForcedInputFilter.getToken(0, ':', nFilterOptionsIndex)),
479  PropertyState_DIRECT_VALUE);
480 
481  if (0 < nFilterOptionsIndex)
482  {
483  aArgs.emplace_back("FilterOptions", 0,
484  Any(aForcedInputFilter.copy(nFilterOptionsIndex)),
485  PropertyState_DIRECT_VALUE);
486  }
487  }
488 
489  // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism.
490  try
491  {
493  xDesktop, aName, aTarget, comphelper::containerToSequence(aArgs)),
494  UNO_QUERY);
495  }
496  catch (const css::lang::IllegalArgumentException&)
497  {
499  "desktop.app",
500  "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL");
501  }
502  catch (const css::io::IOException&)
503  {
505  "desktop.app",
506  "Dispatchwatcher IOException while calling loadComponentFromURL");
507  }
508  if ( aDispatchRequest.aRequestType == REQUEST_OPEN ||
509  aDispatchRequest.aRequestType == REQUEST_VIEW ||
510  aDispatchRequest.aRequestType == REQUEST_START ||
511  aDispatchRequest.aRequestType == REQUEST_FORCEOPEN ||
512  aDispatchRequest.aRequestType == REQUEST_FORCENEW )
513  {
514  // request is completed
516  }
517  else if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
518  aDispatchRequest.aRequestType == REQUEST_PRINTTO ||
519  aDispatchRequest.aRequestType == REQUEST_BATCHPRINT ||
520  aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
521  aDispatchRequest.aRequestType == REQUEST_CAT ||
522  aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT )
523  {
524  if ( xDoc.is() )
525  {
526  // Do we need to save the document in a different format?
527  if ( aDispatchRequest.aRequestType == REQUEST_CONVERSION ||
528  aDispatchRequest.aRequestType == REQUEST_CAT )
529  {
530 // FIXME: factor out into a method ...
531  Reference< XStorable > xStorable( xDoc, UNO_QUERY );
532  if ( xStorable.is() ) {
533  OUString aParam = aDispatchRequest.aPrinterName;
534  sal_Int32 nPathIndex = aParam.lastIndexOf( ';' );
535  sal_Int32 nFilterIndex = aParam.indexOf( ':' );
536  sal_Int32 nImgFilterIndex = aParam.lastIndexOf( '|' );
537  if( nPathIndex < nFilterIndex )
538  nFilterIndex = -1;
539 
540  OUString aFilterOut;
541  OUString aImgOut;
542  OUString aFilter;
543  OUString aFilterExt;
544  bool bGuess = false;
545 
546  if( nFilterIndex >= 0 )
547  {
548  aFilter = aParam.copy( nFilterIndex+1, nPathIndex-nFilterIndex-1 );
549  aFilterExt = aParam.copy( 0, nFilterIndex );
550  }
551  else
552  {
553  // Guess
554  bGuess = true;
555  aFilterExt = aParam.copy( 0, nPathIndex );
556  }
557 
558  if( nImgFilterIndex >= 0 )
559  {
560  aImgOut = aParam.copy( nImgFilterIndex+1 );
561  aFilterOut = aParam.copy( nPathIndex+1, nImgFilterIndex-nPathIndex-1 );
562  }
563  else
564  aFilterOut = aParam.copy( nPathIndex+1 );
565 
566  FileBase::getFileURLFromSystemPath( aFilterOut, aFilterOut );
567  INetURLObject aOutFilename(aFilterOut);
568  aOutFilename.Append(aObj.getName(INetURLObject::LAST_SEGMENT, true,
570  aOutFilename.SetExtension(aFilterExt);
571  OUString aOutFile
573 
574  std::unique_ptr<utl::TempFile> fileForCat;
575  if( aDispatchRequest.aRequestType == REQUEST_CAT )
576  {
577  fileForCat = std::make_unique<utl::TempFile>();
578  if (fileForCat->IsValid())
579  fileForCat->EnableKillingFile();
580  else
581  std::cerr << "Error: Cannot create temporary file..." << std::endl ;
582  aOutFile = fileForCat->GetURL();
583  }
584 
585  if ( bGuess )
586  {
587  OUString aDocService;
588  Reference< XModel > xModel( xDoc, UNO_QUERY );
589  if ( xModel.is() )
590  {
591  utl::MediaDescriptor aMediaDesc( xModel->getArgs() );
592  aDocService = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_DOCUMENTSERVICE, OUString() );
593  }
594  aFilter = impl_GuessFilter( aOutFile, aDocService );
595  }
596 
597  bool bMultiFileTarget = false;
598 
599  if (aFilter.isEmpty())
600  {
601  std::cerr << "Error: no export filter" << std::endl;
602  }
603  else
604  {
605  sal_Int32 nFilterOptionsIndex = aFilter.indexOf(':');
606  sal_Int32 nProps = ( 0 < nFilterOptionsIndex ) ? 4 : 3;
607 
608  if ( !aImgOut.isEmpty() )
609  nProps +=1;
610  Sequence<PropertyValue> conversionProperties( nProps );
611  auto pconversionProperties = conversionProperties.getArray();
612  pconversionProperties[0].Name = "ConversionRequestOrigin";
613  pconversionProperties[0].Value <<= OUString("CommandLine");
614  pconversionProperties[1].Name = "Overwrite";
615  pconversionProperties[1].Value <<= true;
616 
617  pconversionProperties[2].Name = "FilterName";
618  if( 0 < nFilterOptionsIndex )
619  {
620  OUString sFilterName = aFilter.copy(0, nFilterOptionsIndex);
621  OUString sFilterOptions = aFilter.copy(nFilterOptionsIndex + 1);
622 
623  if (sFilterName == "Text - txt - csv (StarCalc)")
624  {
625  sal_Int32 nIdx(0);
626  // If the 11th token is '-1' then we export a file
627  // per sheet where the file name is based on the suggested
628  // output filename concatenated with the sheet name, so adjust
629  // the output and overwrite messages
630  // If the 11th token is not present or numeric 0 then the
631  // default sheet is exported with the output filename. If it
632  // is numeric >0 then that sheet (1-based) with the output
633  // filename concatenated with the sheet name. So even if
634  // that is a single file, the multi file target mechanism is
635  // used.
636  const OUString aTok(sFilterOptions.getToken(11, ',', nIdx));
637  // Actual validity is checked in Calc, here just check for
638  // presence of numeric value at start.
639  bMultiFileTarget = (!aTok.isEmpty() && aTok.toInt32() != 0);
640  }
641 
642  pconversionProperties[2].Value <<= sFilterName;
643 
644  pconversionProperties[3].Name = "FilterOptions";
645  pconversionProperties[3].Value <<= sFilterOptions;
646  }
647  else
648  {
649  pconversionProperties[2].Value <<= aFilter;
650  }
651 
652  if ( !aImgOut.isEmpty() )
653  {
654  assert(conversionProperties[nProps-1].Name.isEmpty());
655  pconversionProperties[nProps-1].Name = "ImageFilter";
656  pconversionProperties[nProps-1].Value <<= aImgOut;
657  }
658 
659  OUString aTempName;
660  FileBase::getSystemPathFromFileURL(aName, aTempName);
661  OString aSource8 = OUStringToOString(aTempName, osl_getThreadTextEncoding());
662  FileBase::getSystemPathFromFileURL(aOutFile, aTempName);
663  OString aTargetURL8 = OUStringToOString(aTempName, osl_getThreadTextEncoding());
664  if (aDispatchRequest.aRequestType != REQUEST_CAT)
665  {
666  std::cout << "convert " << aSource8;
667  if (!bMultiFileTarget)
668  std::cout << " -> " << aTargetURL8;
669  std::cout << " using filter : " << OUStringToOString(aFilter, osl_getThreadTextEncoding()) << std::endl;
670  if (!bMultiFileTarget && FStatHelper::IsDocument(aOutFile))
671  std::cout << "Overwriting: " << OUStringToOString(aTempName, osl_getThreadTextEncoding()) << std::endl ;
672  }
673  try
674  {
675  xStorable->storeToURL(aOutFile, conversionProperties);
676  }
677  catch (const Exception& rException)
678  {
679  std::cerr << "Error: Please verify input parameters...";
680  if (!rException.Message.isEmpty())
681  std::cerr << " (" << rException.Message << ")";
682  std::cerr << std::endl;
683  }
684 
685  if (fileForCat && fileForCat->IsValid())
686  {
687  SvStream* aStream = fileForCat->GetStream(StreamMode::STD_READ);
688  while (aStream->good())
689  {
690  OString aStr;
691  aStream->ReadLine(aStr, SAL_MAX_INT32);
692  for (sal_Int32 i = 0; i < aStr.getLength(); ++i)
693  {
694  std::cout << aStr[i];
695  }
696  std::cout << std::endl;
697  }
698  }
699  }
700  }
701  }
702  else if ( aDispatchRequest.aRequestType == REQUEST_SCRIPT_CAT )
703  {
704  Reference< XModel > xModel( xDoc, UNO_QUERY );
705  if( xModel.is() )
706  scriptCat( xModel );
707  }
708  else if ( aDispatchRequest.aRequestType == REQUEST_BATCHPRINT )
709  {
710  batchPrint( aDispatchRequest.aPrinterName, xDoc, aObj, aName );
711  }
712  else
713  {
714  if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO )
715  {
716  // create the printer
717  Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue(
718  "Name", aDispatchRequest.aPrinterName) };
719  xDoc->setPrinter( aPrinterArgs );
720  }
721 
722  // print ( also without user interaction )
723  Sequence < PropertyValue > aPrinterArgs{ comphelper::makePropertyValue("Wait",
724  true) };
725  xDoc->print( aPrinterArgs );
726  }
727  }
728  else
729  {
730  std::cerr << "Error: source file could not be loaded" << std::endl;
731  }
732 
733  // remove the document
734  try
735  {
736  Reference < XCloseable > xClose( xDoc, UNO_QUERY );
737  if ( xClose.is() )
738  xClose->close( true );
739  else
740  {
741  Reference < XComponent > xComp( xDoc, UNO_QUERY );
742  if ( xComp.is() )
743  xComp->dispose();
744  }
745  }
746  catch (const css::util::CloseVetoException&)
747  {
748  }
749 
750  // request is completed
752  }
753  }
754  }
755 
756  if ( !aDispatches.empty() )
757  {
758  // Execute all asynchronous dispatches now after we placed them into our request container!
759  Sequence < PropertyValue > aArgs{
760  comphelper::makePropertyValue("Referer", OUString("private:OpenEvent")),
761  comphelper::makePropertyValue("SynchronMode", true)
762  };
763 
764  for (const DispatchHolder & aDispatche : aDispatches)
765  {
766  Reference< XDispatch > xDispatch = aDispatche.xDispatch;
767  Reference < XNotifyingDispatch > xDisp( xDispatch, UNO_QUERY );
768  if ( xDisp.is() )
769  xDisp->dispatchWithNotification( aDispatche.aURL, aArgs, this );
770  else
771  {
772  {
773  osl::MutexGuard aGuard(m_mutex);
774  m_nRequestCount--;
775  }
776  xDispatch->dispatch( aDispatche.aURL, aArgs );
777  }
778  }
779  }
780 
781  ::osl::ClearableMutexGuard aGuard(m_mutex);
782  bool bEmpty = (m_nRequestCount == 0);
783  aGuard.clear();
784 
785  // No more asynchronous requests?
786  // The requests are removed from the request container after they called back to this
787  // implementation via statusChanged!!
788  if ( bEmpty && !bNoTerminate /*m_aRequestContainer.empty()*/ )
789  {
790  // We have to check if we have an open task otherwise we have to shutdown the office.
791  Reference< XElementAccess > xList = xDesktop->getFrames();
792 
793  if ( !xList->hasElements() )
794  {
795  // We don't have any task open so we have to shutdown ourself!!
796  return xDesktop->terminate();
797  }
798  }
799 
800  return false;
801 }
802 
803 
804 void SAL_CALL DispatchWatcher::disposing( const css::lang::EventObject& )
805 {
806 }
807 
808 
809 void SAL_CALL DispatchWatcher::dispatchFinished( const DispatchResultEvent& )
810 {
811  osl::ClearableMutexGuard aGuard(m_mutex);
812  sal_Int16 nCount = --m_nRequestCount;
813  aGuard.clear();
815  if ( !nCount && !RequestHandler::AreRequestsPending() )
816  {
817  // We have to check if we have an open task otherwise we have to shutdown the office.
818  Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
819  Reference< XElementAccess > xList = xDesktop->getFrames();
820 
821  if ( !xList->hasElements() )
822  {
823  // We don't have any task open so we have to shutdown ourself!!
824  xDesktop->terminate();
825  }
826  }
827 }
828 
829 } // namespace desktop
830 
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SVL_DLLPUBLIC bool IsDocument(const OUString &rURL)
URL aURL
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
OUString GetURL_Impl(const OUString &rName, std::optional< OUString > const &cwdUrl)
Definition: app.cxx:2206
bool ReadLine(OStringBuffer &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
#define SFX_FILTER_NOTINSTALLED
OUString Name
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
Definition: app.cxx:164
int nCount
static COMPHELPER_DLLPUBLIC css::uno::Reference< css::lang::XComponent > dispatch(const css::uno::Reference< css::uno::XInterface > &xStartPoint, const OUString &sURL, const OUString &sTarget, const css::uno::Sequence< css::beans::PropertyValue > &lArguments)
static constexpr OUStringLiteral PROP_DOCUMENTSERVICE
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define SAL_MAX_INT32
static bool AreRequestsPending()
int i
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static std::shared_ptr< const SfxFilter > GetFilterByName(const OUString &rName)
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2429
Reference< XDispatch > xDispatch
#define SAL_WARN_IF(condition, area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
OUString aName
INetProtocol GetProtocol() const
Reference< XComponentContext > getProcessComponentContext()
bool Append(std::u16string_view rTheSegment, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
bool good() const
void SetExtension(std::u16string_view rTheExtension)
Reference< XModel > xModel
virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent &aEvent) override
aStr
virtual ~DispatchWatcher() override
bool executeDispatchRequests(const std::vector< DispatchRequest > &aDispatches, bool bNoTerminate)