Update ooo320-m1
[ooovba.git] / desktop / source / app / dispatchwatcher.cxx
blobc3886299d328566e999f1dde496a8d30dae27d8c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dispatchwatcher.cxx,v $
10 * $Revision: 1.30 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_desktop.hxx"
34 #include "dispatchwatcher.hxx"
35 #include <rtl/ustring.hxx>
36 #include <tools/string.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <comphelper/synchronousdispatch.hxx>
39 #include <com/sun/star/util/XCloseable.hpp>
40 #include <com/sun/star/util/CloseVetoException.hpp>
41 #include <com/sun/star/task/XInteractionHandler.hpp>
42 #include <com/sun/star/util/URL.hpp>
43 #include <com/sun/star/frame/XDesktop.hpp>
44 #include <com/sun/star/container/XEnumeration.hpp>
45 #include <com/sun/star/frame/XFramesSupplier.hpp>
46 #include <com/sun/star/frame/XDispatch.hpp>
47 #include <com/sun/star/frame/XComponentLoader.hpp>
48 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <com/sun/star/view/XPrintable.hpp>
50 #include <com/sun/star/frame/XDispatchProvider.hpp>
51 #include <com/sun/star/util/XURLTransformer.hpp>
52 #include <com/sun/star/document/MacroExecMode.hpp>
53 #include <com/sun/star/document/UpdateDocMode.hpp>
55 #include <tools/urlobj.hxx>
56 #include <comphelper/mediadescriptor.hxx>
58 #include <vector>
60 using namespace ::rtl;
61 using namespace ::osl;
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::util;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::frame;
66 using namespace ::com::sun::star::container;
67 using namespace ::com::sun::star::beans;
68 using namespace ::com::sun::star::view;
70 namespace desktop
73 String GetURL_Impl(
74 const String& rName, boost::optional< rtl::OUString > const & cwdUrl );
76 struct DispatchHolder
78 DispatchHolder( const URL& rURL, Reference< XDispatch >& rDispatch ) :
79 aURL( rURL ), xDispatch( rDispatch ) {}
81 URL aURL;
82 rtl::OUString cwdUrl;
83 Reference< XDispatch > xDispatch;
86 Mutex* DispatchWatcher::pWatcherMutex = NULL;
88 Mutex& DispatchWatcher::GetMutex()
90 if ( !pWatcherMutex )
92 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
93 if ( !pWatcherMutex )
94 pWatcherMutex = new osl::Mutex();
97 return *pWatcherMutex;
100 // Create or get the dispatch watcher implementation. This implementation must be
101 // a singleton to prevent access to the framework after it wants to terminate.
102 DispatchWatcher* DispatchWatcher::GetDispatchWatcher()
104 static Reference< XInterface > xDispatchWatcher;
105 static DispatchWatcher* pDispatchWatcher = NULL;
107 if ( !xDispatchWatcher.is() )
109 ::osl::MutexGuard aGuard( GetMutex() );
111 if ( !xDispatchWatcher.is() )
113 pDispatchWatcher = new DispatchWatcher();
115 // We have to hold a reference to ourself forever to prevent our own destruction.
116 xDispatchWatcher = static_cast< cppu::OWeakObject *>( pDispatchWatcher );
120 return pDispatchWatcher;
124 DispatchWatcher::DispatchWatcher()
125 : m_nRequestCount(0)
130 DispatchWatcher::~DispatchWatcher()
135 sal_Bool DispatchWatcher::executeDispatchRequests( const DispatchList& aDispatchRequestsList, bool bNoTerminate )
137 Reference< XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
138 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ),
139 UNO_QUERY );
141 DispatchList::const_iterator p;
142 std::vector< DispatchHolder > aDispatches;
143 ::rtl::OUString aAsTemplateArg( RTL_CONSTASCII_USTRINGPARAM( "AsTemplate"));
145 for ( p = aDispatchRequestsList.begin(); p != aDispatchRequestsList.end(); p++ )
147 String aPrinterName;
148 const DispatchRequest& aDispatchRequest = *p;
150 // create parameter array
151 sal_Int32 nCount = 4;
152 if ( aDispatchRequest.aPreselectedFactory.getLength() )
153 nCount++;
155 // we need more properties for a print/print to request
156 if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
157 aDispatchRequest.aRequestType == REQUEST_PRINTTO )
158 nCount++;
160 Sequence < PropertyValue > aArgs( nCount );
162 // mark request as user interaction from outside
163 aArgs[0].Name = ::rtl::OUString::createFromAscii("Referer");
164 aArgs[0].Value <<= ::rtl::OUString::createFromAscii("private:OpenEvent");
166 if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
167 aDispatchRequest.aRequestType == REQUEST_PRINTTO )
169 aArgs[1].Name = ::rtl::OUString::createFromAscii("ReadOnly");
170 aArgs[2].Name = ::rtl::OUString::createFromAscii("OpenNewView");
171 aArgs[3].Name = ::rtl::OUString::createFromAscii("Hidden");
172 aArgs[4].Name = ::rtl::OUString::createFromAscii("Silent");
174 else
176 Reference < com::sun::star::task::XInteractionHandler > xInteraction(
177 ::comphelper::getProcessServiceFactory()->createInstance( OUString::createFromAscii("com.sun.star.task.InteractionHandler") ),
178 com::sun::star::uno::UNO_QUERY );
180 aArgs[1].Name = OUString::createFromAscii( "InteractionHandler" );
181 aArgs[1].Value <<= xInteraction;
183 sal_Int16 nMacroExecMode = ::com::sun::star::document::MacroExecMode::USE_CONFIG;
184 aArgs[2].Name = OUString::createFromAscii( "MacroExecutionMode" );
185 aArgs[2].Value <<= nMacroExecMode;
187 sal_Int16 nUpdateDoc = ::com::sun::star::document::UpdateDocMode::ACCORDING_TO_CONFIG;
188 aArgs[3].Name = OUString::createFromAscii( "UpdateDocMode" );
189 aArgs[3].Value <<= nUpdateDoc;
192 if ( aDispatchRequest.aPreselectedFactory.getLength() )
194 aArgs[nCount-1].Name = ::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE();
195 aArgs[nCount-1].Value <<= aDispatchRequest.aPreselectedFactory;
198 String aName( GetURL_Impl( aDispatchRequest.aURL, aDispatchRequest.aCwdUrl ) );
199 ::rtl::OUString aTarget( RTL_CONSTASCII_USTRINGPARAM("_default") );
201 if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
202 aDispatchRequest.aRequestType == REQUEST_PRINTTO )
204 // documents opened for printing are opened readonly because they must be opened as a new document and this
205 // document could be open already
206 aArgs[1].Value <<= sal_True;
208 // always open a new document for printing, because it must be disposed afterwards
209 aArgs[2].Value <<= sal_True;
211 // printing is done in a hidden view
212 aArgs[3].Value <<= sal_True;
214 // load document for printing without user interaction
215 aArgs[4].Value <<= sal_True;
217 // hidden documents should never be put into open tasks
218 aTarget = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_blank") );
221 // load the document ... if they are loadable!
222 // Otherwise try to dispatch it ...
223 Reference < XPrintable > xDoc;
225 ( aName.CompareToAscii( ".uno" , 4 ) == COMPARE_EQUAL ) ||
226 ( aName.CompareToAscii( "slot:" , 5 ) == COMPARE_EQUAL ) ||
227 ( aName.CompareToAscii( "macro:", 6 ) == COMPARE_EQUAL ) ||
228 ( aName.CompareToAscii("vnd.sun.star.script", 19) == COMPARE_EQUAL)
231 // Attention: URL must be parsed full. Otherwise some detections on it will fail!
232 // It doesnt matter, if parser isn't available. Because; We try loading of URL then ...
233 URL aURL ;
234 aURL.Complete = aName;
236 Reference < XDispatch > xDispatcher ;
237 Reference < XDispatchProvider > xProvider ( xDesktop, UNO_QUERY );
238 Reference < XURLTransformer > xParser ( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer")) ), ::com::sun::star::uno::UNO_QUERY );
240 if( xParser.is() == sal_True )
241 xParser->parseStrict( aURL );
243 if( xProvider.is() == sal_True )
244 xDispatcher = xProvider->queryDispatch( aURL, ::rtl::OUString(), 0 );
246 if( xDispatcher.is() == sal_True )
249 ::osl::ClearableMutexGuard aGuard( GetMutex() );
250 // Remember request so we can find it in statusChanged!
251 m_aRequestContainer.insert( DispatchWatcherHashMap::value_type( aURL.Complete, (sal_Int32)1 ) );
252 m_nRequestCount++;
255 // Use local vector to store dispatcher because we have to fill our request container before
256 // we can dispatch. Otherwise it would be possible that statusChanged is called before we dispatched all requests!!
257 aDispatches.push_back( DispatchHolder( aURL, xDispatcher ));
260 else if ( ( aName.CompareToAscii( "service:" , 8 ) == COMPARE_EQUAL ) )
262 // TODO: the dispatch has to be done for loadComponentFromURL as well. Please ask AS for more details.
263 URL aURL ;
264 aURL.Complete = aName;
266 Reference < XDispatch > xDispatcher ;
267 Reference < XDispatchProvider > xProvider ( xDesktop, UNO_QUERY );
268 Reference < XURLTransformer > xParser ( ::comphelper::getProcessServiceFactory()->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.URLTransformer")) ), ::com::sun::star::uno::UNO_QUERY );
270 if( xParser.is() == sal_True )
271 xParser->parseStrict( aURL );
273 if( xProvider.is() == sal_True )
274 xDispatcher = xProvider->queryDispatch( aURL, ::rtl::OUString(), 0 );
276 if( xDispatcher.is() == sal_True )
280 // We have to be listener to catch errors during dispatching URLs.
281 // Otherwise it would be possible to have an office running without an open
282 // window!!
283 Sequence < PropertyValue > aArgs2(1);
284 aArgs2[0].Name = ::rtl::OUString::createFromAscii("SynchronMode");
285 aArgs2[0].Value <<= sal_True;
286 Reference < XNotifyingDispatch > xDisp( xDispatcher, UNO_QUERY );
287 if ( xDisp.is() )
288 xDisp->dispatchWithNotification( aURL, aArgs2, DispatchWatcher::GetDispatchWatcher() );
289 else
290 xDispatcher->dispatch( aURL, aArgs2 );
292 catch ( ::com::sun::star::uno::Exception& )
294 OUString aMsg = OUString::createFromAscii(
295 "Desktop::OpenDefault() IllegalArgumentException while calling XNotifyingDispatch: ");
296 OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr());
300 else
302 INetURLObject aObj( aName );
303 if ( aObj.GetProtocol() == INET_PROT_PRIVATE )
304 aTarget = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("_default") );
306 // Set "AsTemplate" argument according to request type
307 if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW ||
308 aDispatchRequest.aRequestType == REQUEST_FORCEOPEN )
310 sal_Int32 nIndex = aArgs.getLength();
311 aArgs.realloc( nIndex+1 );
312 aArgs[nIndex].Name = aAsTemplateArg;
313 if ( aDispatchRequest.aRequestType == REQUEST_FORCENEW )
314 aArgs[nIndex].Value <<= sal_True;
315 else
316 aArgs[nIndex].Value <<= sal_False;
319 // if we are called in viewmode, open document read-only
320 // #95425#
321 if(aDispatchRequest.aRequestType == REQUEST_VIEW) {
322 sal_Int32 nIndex = aArgs.getLength();
323 aArgs.realloc(nIndex+1);
324 aArgs[nIndex].Name = OUString::createFromAscii("ReadOnly");
325 aArgs[nIndex].Value <<= sal_True;
328 // if we are called with -start set Start in mediadescriptor
329 if(aDispatchRequest.aRequestType == REQUEST_START) {
330 sal_Int32 nIndex = aArgs.getLength();
331 aArgs.realloc(nIndex+1);
332 aArgs[nIndex].Name = OUString::createFromAscii("StartPresentation");
333 aArgs[nIndex].Value <<= sal_True;
336 // This is a synchron loading of a component so we don't have to deal with our statusChanged listener mechanism.
340 xDoc = Reference < XPrintable >( ::comphelper::SynchronousDispatch::dispatch( xDesktop, aName, aTarget, 0, aArgs ), UNO_QUERY );
341 //xDoc = Reference < XPrintable >( xDesktop->loadComponentFromURL( aName, aTarget, 0, aArgs ), UNO_QUERY );
343 catch ( ::com::sun::star::lang::IllegalArgumentException& iae)
345 OUString aMsg = OUString::createFromAscii(
346 "Dispatchwatcher IllegalArgumentException while calling loadComponentFromURL: ")
347 + iae.Message;
348 OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr());
350 catch (com::sun::star::io::IOException& ioe)
352 OUString aMsg = OUString::createFromAscii(
353 "Dispatchwatcher IOException while calling loadComponentFromURL: ")
354 + ioe.Message;
355 OSL_ENSURE( sal_False, OUStringToOString(aMsg, RTL_TEXTENCODING_ASCII_US).getStr());
357 if ( aDispatchRequest.aRequestType == REQUEST_OPEN ||
358 aDispatchRequest.aRequestType == REQUEST_VIEW ||
359 aDispatchRequest.aRequestType == REQUEST_START ||
360 aDispatchRequest.aRequestType == REQUEST_FORCEOPEN ||
361 aDispatchRequest.aRequestType == REQUEST_FORCENEW )
363 // request is completed
364 OfficeIPCThread::RequestsCompleted( 1 );
366 else if ( aDispatchRequest.aRequestType == REQUEST_PRINT ||
367 aDispatchRequest.aRequestType == REQUEST_PRINTTO )
369 if ( xDoc.is() )
371 if ( aDispatchRequest.aRequestType == REQUEST_PRINTTO )
373 // create the printer
374 Sequence < PropertyValue > aPrinterArgs( 1 );
375 aPrinterArgs[0].Name = ::rtl::OUString::createFromAscii("Name");
376 aPrinterArgs[0].Value <<= ::rtl::OUString( aDispatchRequest.aPrinterName );
377 xDoc->setPrinter( aPrinterArgs );
380 // print ( also without user interaction )
381 Sequence < PropertyValue > aPrinterArgs( 1 );
382 aPrinterArgs[0].Name = ::rtl::OUString::createFromAscii("Wait");
383 aPrinterArgs[0].Value <<= ( sal_Bool ) sal_True;
384 xDoc->print( aPrinterArgs );
386 else
388 // place error message here ...
391 // remove the document
394 Reference < XCloseable > xClose( xDoc, UNO_QUERY );
395 if ( xClose.is() )
396 xClose->close( sal_True );
397 else
399 Reference < XComponent > xComp( xDoc, UNO_QUERY );
400 if ( xComp.is() )
401 xComp->dispose();
404 catch ( com::sun::star::util::CloseVetoException& )
408 // request is completed
409 OfficeIPCThread::RequestsCompleted( 1 );
414 if ( aDispatches.size() > 0 )
416 // Execute all asynchronous dispatches now after we placed them into our request container!
417 Sequence < PropertyValue > aArgs( 2 );
418 aArgs[0].Name = ::rtl::OUString::createFromAscii("Referer");
419 aArgs[0].Value <<= ::rtl::OUString::createFromAscii("private:OpenEvent");
420 aArgs[1].Name = ::rtl::OUString::createFromAscii("SynchronMode");
421 aArgs[1].Value <<= sal_True;
423 for ( sal_uInt32 n = 0; n < aDispatches.size(); n++ )
425 Reference< XDispatch > xDispatch = aDispatches[n].xDispatch;
426 Reference < XNotifyingDispatch > xDisp( xDispatch, UNO_QUERY );
427 if ( xDisp.is() )
428 xDisp->dispatchWithNotification( aDispatches[n].aURL, aArgs, this );
429 else
431 ::osl::ClearableMutexGuard aGuard( GetMutex() );
432 m_nRequestCount--;
433 aGuard.clear();
434 xDispatch->dispatch( aDispatches[n].aURL, aArgs );
439 ::osl::ClearableMutexGuard aGuard( GetMutex() );
440 bool bEmpty = (m_nRequestCount == 0);
441 aGuard.clear();
443 // No more asynchronous requests?
444 // The requests are removed from the request container after they called back to this
445 // implementation via statusChanged!!
446 if ( bEmpty && !bNoTerminate /*m_aRequestContainer.empty()*/ )
448 // We have to check if we have an open task otherwise we have to shutdown the office.
449 Reference< XFramesSupplier > xTasksSupplier( xDesktop, UNO_QUERY );
450 aGuard.clear();
452 Reference< XElementAccess > xList( xTasksSupplier->getFrames(), UNO_QUERY );
454 if ( !xList->hasElements() )
456 // We don't have any task open so we have to shutdown ourself!!
457 Reference< XDesktop > xDesktop2( xTasksSupplier, UNO_QUERY );
458 if ( xDesktop2.is() )
459 return xDesktop2->terminate();
463 return sal_False;
467 void SAL_CALL DispatchWatcher::disposing( const ::com::sun::star::lang::EventObject& )
468 throw(::com::sun::star::uno::RuntimeException)
473 void SAL_CALL DispatchWatcher::dispatchFinished( const DispatchResultEvent& ) throw( RuntimeException )
475 osl::ClearableMutexGuard aGuard( GetMutex() );
476 sal_Int16 nCount = --m_nRequestCount;
477 aGuard.clear();
478 OfficeIPCThread::RequestsCompleted( 1 );
480 // Find request in our hash map and remove it as a pending request
481 DispatchWatcherHashMap::iterator pDispatchEntry = m_aRequestContainer.find( rEvent.FeatureURL.Complete ) ;
482 if ( pDispatchEntry != m_aRequestContainer.end() )
484 m_aRequestContainer.erase( pDispatchEntry );
485 aGuard.clear();
486 OfficeIPCThread::RequestsCompleted( 1 );
488 else
489 aGuard.clear();
491 if ( !nCount && !OfficeIPCThread::AreRequestsPending() )
493 // We have to check if we have an open task otherwise we have to shutdown the office.
494 Reference< XFramesSupplier > xTasksSupplier( ::comphelper::getProcessServiceFactory()->createInstance(
495 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ),
496 UNO_QUERY );
497 Reference< XElementAccess > xList( xTasksSupplier->getFrames(), UNO_QUERY );
499 if ( !xList->hasElements() )
501 // We don't have any task open so we have to shutdown ourself!!
502 Reference< XDesktop > xDesktop( xTasksSupplier, UNO_QUERY );
503 if ( xDesktop.is() )
504 xDesktop->terminate();