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 .
21 #include "dlgprov.hxx"
22 #include "dlgevtatt.hxx"
23 #include <com/sun/star/awt/UnoControlDialog.hpp>
24 #include <com/sun/star/awt/Toolkit.hpp>
25 #include <com/sun/star/awt/XControlContainer.hpp>
26 #include <com/sun/star/awt/XWindowPeer.hpp>
27 #include <com/sun/star/beans/theIntrospection.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/document/XEmbeddedScripts.hpp>
30 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 #include <com/sun/star/io/XInputStreamProvider.hpp>
33 #include <com/sun/star/resource/XStringResourceSupplier.hpp>
34 #include <com/sun/star/resource/XStringResourceManager.hpp>
35 #include <com/sun/star/script/XLibraryContainer.hpp>
36 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
37 #include <com/sun/star/uri/XUriReference.hpp>
38 #include <com/sun/star/uri/UriReferenceFactory.hpp>
39 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
40 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
41 #include <com/sun/star/util/theMacroExpander.hpp>
43 #include <cppuhelper/exc_hlp.hxx>
44 #include <cppuhelper/supportsservice.hxx>
45 #include <sfx2/app.hxx>
46 #include <xmlscript/xmldlg_imexp.hxx>
47 #include <tools/urlobj.hxx>
48 #include <comphelper/namedvaluecollection.hxx>
49 #include <util/MiscUtils.hxx>
50 #include <vcl/settings.hxx>
51 #include <vcl/svapp.hxx>
52 #include <i18nlangtag/languagetag.hxx>
54 using namespace ::com::sun::star
;
58 using namespace script
;
59 using namespace beans
;
60 using namespace document
;
61 using namespace ::sf_misc
;
66 Reference
< resource::XStringResourceManager
> lcl_getStringResourceManager(const Reference
< XComponentContext
>& i_xContext
, std::u16string_view i_sURL
)
68 INetURLObject
aInetObj( i_sURL
);
69 OUString aDlgName
= aInetObj
.GetBase();
70 aInetObj
.removeSegment();
71 OUString aDlgLocation
= aInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
72 css::lang::Locale aLocale
= Application::GetSettings().GetUILanguageTag().getLocale();
74 Reference
< task::XInteractionHandler
> xDummyHandler
;
76 Sequence
<Any
> aArgs
{ Any(aDlgLocation
),
77 Any(true), // bReadOnly
83 Reference
< XMultiComponentFactory
> xSMgr_( i_xContext
->getServiceManager(), UNO_SET_THROW
);
85 Reference
< resource::XStringResourceManager
> xStringResourceManager( xSMgr_
->createInstanceWithContext
86 ( "com.sun.star.resource.StringResourceWithLocation",
87 i_xContext
), UNO_QUERY
);
88 if( xStringResourceManager
.is() )
90 Reference
< XInitialization
> xInit( xStringResourceManager
, UNO_QUERY
);
92 xInit
->initialize( aArgs
);
94 return xStringResourceManager
;
96 Reference
< container::XNameContainer
> lcl_createControlModel(const Reference
< XComponentContext
>& i_xContext
)
98 Reference
< XMultiComponentFactory
> xSMgr_( i_xContext
->getServiceManager(), UNO_SET_THROW
);
99 Reference
< container::XNameContainer
> xControlModel( xSMgr_
->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", i_xContext
), UNO_QUERY_THROW
);
100 return xControlModel
;
102 Reference
< container::XNameContainer
> lcl_createDialogModel( const Reference
< XComponentContext
>& i_xContext
,
103 const Reference
< io::XInputStream
>& xInput
,
104 const Reference
< frame::XModel
>& xModel
,
105 const Reference
< resource::XStringResourceManager
>& xStringResourceManager
,
106 const Any
&aDialogSourceURL
)
108 Reference
< container::XNameContainer
> xDialogModel( lcl_createControlModel(i_xContext
) );
110 Reference
< beans::XPropertySet
> xDlgPropSet( xDialogModel
, UNO_QUERY
);
111 xDlgPropSet
->setPropertyValue( "DialogSourceURL", aDialogSourceURL
);
113 // #TODO we really need to detect the source of the Dialog, is it
114 // the dialog. E.g. if the dialog was created from basic ( then we just
115 // can't tell where its from )
116 // If we are happy to always substitute the form model for the awt
117 // one then maybe the presence of a document model is enough to trigger
118 // swapping out the models ( or perhaps we only want to do this
119 // for vba mode ) there are a number of feasible and valid possibilities
120 ::xmlscript::importDialogModel( xInput
, xDialogModel
, i_xContext
, xModel
);
122 // Set resource property
123 if( xStringResourceManager
.is() )
125 Reference
< beans::XPropertySet
> xDlgPSet( xDialogModel
, UNO_QUERY
);
126 Any aStringResourceManagerAny
;
127 aStringResourceManagerAny
<<= xStringResourceManager
;
128 xDlgPSet
->setPropertyValue( "ResourceResolver", aStringResourceManagerAny
);
137 ::osl::Mutex
& getMutex()
139 static ::osl::Mutex s_aMutex
;
145 // DialogProviderImpl
148 DialogProviderImpl::DialogProviderImpl( const Reference
< XComponentContext
>& rxContext
)
149 :m_xContext( rxContext
)
154 DialogProviderImpl::~DialogProviderImpl()
159 static Reference
< resource::XStringResourceManager
> getStringResourceFromDialogLibrary
160 ( const Reference
< container::XNameContainer
>& xDialogLib
)
162 Reference
< resource::XStringResourceManager
> xStringResourceManager
;
163 if( xDialogLib
.is() )
165 Reference
< resource::XStringResourceSupplier
> xStringResourceSupplier( xDialogLib
, UNO_QUERY
);
166 if( xStringResourceSupplier
.is() )
168 Reference
< resource::XStringResourceResolver
>
169 xStringResourceResolver
= xStringResourceSupplier
->getStringResource();
171 xStringResourceManager
=
172 Reference
< resource::XStringResourceManager
>( xStringResourceResolver
, UNO_QUERY
);
175 return xStringResourceManager
;
178 Reference
< container::XNameContainer
> DialogProviderImpl::createDialogModel(
179 const Reference
< io::XInputStream
>& xInput
,
180 const Reference
< resource::XStringResourceManager
>& xStringResourceManager
,
181 const Any
&aDialogSourceURL
)
183 return lcl_createDialogModel(m_xContext
,xInput
,m_xModel
,xStringResourceManager
,aDialogSourceURL
);
186 Reference
< XControlModel
> DialogProviderImpl::createDialogModelForBasic()
189 // shouldn't get here
190 throw RuntimeException("No information to create dialog" );
191 Reference
< resource::XStringResourceManager
> xStringResourceManager
= getStringResourceFromDialogLibrary( m_BasicInfo
->mxDlgLib
);
193 Any
aDialogSourceURL((OUString()));
194 Reference
< XControlModel
> xCtrlModel( createDialogModel( m_BasicInfo
->mxInput
, xStringResourceManager
, aDialogSourceURL
), UNO_QUERY_THROW
);
198 Reference
< XControlModel
> DialogProviderImpl::createDialogModel( const OUString
& sURL
)
201 OUString
aURL( sURL
);
204 // TODO: use URL parsing class
205 // TODO: decoding of location
207 Reference
< uri::XUriReferenceFactory
> xFac ( uri::UriReferenceFactory::create( m_xContext
) );
209 // i75778: Support non-script URLs
210 Reference
< io::XInputStream
> xInput
;
211 Reference
< container::XNameContainer
> xDialogLib
;
213 // Accept file URL to single dialog
214 bool bSingleDialog
= false;
216 Reference
< util::XMacroExpander
> xMacroExpander
=
217 util::theMacroExpander::get(m_xContext
);
219 Reference
< uri::XUriReference
> uriRef
;
222 uriRef
= xFac
->parse( aURL
);
225 OUString errorMsg
= "DialogProviderImpl::getDialogModel: failed to parse URI: " + aURL
;
226 throw IllegalArgumentException( errorMsg
, Reference
< XInterface
>(), 1 );
228 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
232 aURL
= sxUri
->expand( xMacroExpander
);
235 Reference
< uri::XVndSunStarScriptUrl
> sfUri( uriRef
, UNO_QUERY
);
238 bSingleDialog
= true;
240 // Try any other URL with SimpleFileAccess
241 Reference
< ucb::XSimpleFileAccess3
> xSFI
= ucb::SimpleFileAccess::create(m_xContext
);
245 xInput
= xSFI
->openFileRead( aURL
);
252 OUString sDescription
= sfUri
->getName();
254 sal_Int32 nIndex
= 0;
256 OUString sLibName
= sDescription
.getToken( 0, '.', nIndex
);
259 sDlgName
= sDescription
.getToken( 0, '.', nIndex
);
261 OUString sLocation
= sfUri
->getParameter( "location" );
264 // get dialog library container
265 // TODO: dialogs in packages
266 Reference
< XLibraryContainer
> xLibContainer
;
268 if ( sLocation
== "application" )
270 xLibContainer
= SfxGetpApp()->GetDialogContainer();
272 else if ( sLocation
== "document" )
274 Reference
< XEmbeddedScripts
> xDocumentScripts( m_xModel
, UNO_QUERY
);
275 if ( xDocumentScripts
.is() )
277 xLibContainer
= xDocumentScripts
->getDialogLibraries();
278 OSL_ENSURE( xLibContainer
.is(),
279 "DialogProviderImpl::createDialogModel: invalid dialog container!" );
284 const Sequence
< OUString
> aOpenDocsTdocURLs( MiscUtils::allOpenTDocUrls( m_xContext
) );
285 for ( auto const & tdocURL
: aOpenDocsTdocURLs
)
287 Reference
< frame::XModel
> xModel( MiscUtils::tDocUrlToModel( tdocURL
) );
288 OSL_ENSURE( xModel
.is(), "DialogProviderImpl::createDialogModel: invalid document model!" );
292 OUString sDocURL
= xModel
->getURL();
293 if ( sDocURL
.isEmpty() )
295 sDocURL
= ::comphelper::NamedValueCollection::getOrDefault( xModel
->getArgs(), u
"Title", sDocURL
);
298 if ( sLocation
!= sDocURL
)
301 Reference
< XEmbeddedScripts
> xDocumentScripts( m_xModel
, UNO_QUERY
);
302 if ( !xDocumentScripts
.is() )
305 xLibContainer
= xDocumentScripts
->getDialogLibraries();
306 OSL_ENSURE( xLibContainer
.is(),
307 "DialogProviderImpl::createDialogModel: invalid dialog container!" );
311 // get input stream provider
312 Reference
< io::XInputStreamProvider
> xISP
;
313 if ( !xLibContainer
.is() )
315 throw IllegalArgumentException(
316 "DialogProviderImpl::getDialog: library container not found!",
317 Reference
< XInterface
>(), 1 );
320 // load dialog library
321 if ( !xLibContainer
->isLibraryLoaded( sLibName
) )
322 xLibContainer
->loadLibrary( sLibName
);
324 // get dialog library
325 if ( xLibContainer
->hasByName( sLibName
) )
327 Any aElement
= xLibContainer
->getByName( sLibName
);
328 aElement
>>= xDialogLib
;
331 if ( !xDialogLib
.is() )
333 throw IllegalArgumentException(
334 "DialogProviderImpl::getDialogModel: library not found!",
335 Reference
< XInterface
>(), 1 );
338 // get input stream provider
339 if ( xDialogLib
->hasByName( sDlgName
) )
341 Any aElement
= xDialogLib
->getByName( sDlgName
);
347 throw IllegalArgumentException(
348 "DialogProviderImpl::getDialogModel: dialog not found!",
349 Reference
< XInterface
>(), 1 );
355 xInput
= xISP
->createInputStream();
356 msDialogLibName
= sLibName
;
359 // import dialog model
360 Reference
< XControlModel
> xCtrlModel
;
361 if ( xInput
.is() && m_xContext
.is() )
363 Reference
< resource::XStringResourceManager
> xStringResourceManager
;
366 xStringResourceManager
= lcl_getStringResourceManager(m_xContext
,aURL
);
368 else if( xDialogLib
.is() )
370 xStringResourceManager
= getStringResourceFromDialogLibrary( xDialogLib
);
373 Any aDialogSourceURLAny
;
374 aDialogSourceURLAny
<<= aURL
;
376 Reference
< container::XNameContainer
> xDialogModel( createDialogModel( xInput
, xStringResourceManager
, aDialogSourceURLAny
), UNO_SET_THROW
);
378 xCtrlModel
.set( xDialogModel
, UNO_QUERY
);
384 Reference
< XUnoControlDialog
> DialogProviderImpl::createDialogControl
385 ( const Reference
< XControlModel
>& rxDialogModel
, const Reference
< XWindowPeer
>& xParent
)
387 OSL_ENSURE( rxDialogModel
.is(), "DialogProviderImpl::getDialogControl: no dialog model" );
389 Reference
< XUnoControlDialog
> xDialogControl
;
391 if ( m_xContext
.is() )
393 xDialogControl
= UnoControlDialog::create( m_xContext
);
396 if ( rxDialogModel
.is() )
397 xDialogControl
->setModel( rxDialogModel
);
400 xDialogControl
->setVisible( false );
402 // get the parent of the dialog control
403 Reference
< XWindowPeer
> xPeer
;
408 else if ( m_xModel
.is() )
410 Reference
< frame::XController
> xController
= m_xModel
->getCurrentController();
411 if ( xController
.is() )
413 Reference
< frame::XFrame
> xFrame
= xController
->getFrame();
415 xPeer
.set( xFrame
->getContainerWindow(), UNO_QUERY
);
420 Reference
< XToolkit
> xToolkit( Toolkit::create( m_xContext
), UNO_QUERY_THROW
);
421 xDialogControl
->createPeer( xToolkit
, xPeer
);
424 return xDialogControl
;
428 void DialogProviderImpl::attachControlEvents(
429 const Reference
< XControl
>& rxControl
,
430 const Reference
< XInterface
>& rxHandler
,
431 const Reference
< XIntrospectionAccess
>& rxIntrospectionAccess
,
432 bool bDialogProviderMode
)
434 if ( !rxControl
.is() )
437 Reference
< XControlContainer
> xControlContainer( rxControl
, UNO_QUERY
);
439 if ( !xControlContainer
.is() )
442 Sequence
< Reference
< XControl
> > aControls
= xControlContainer
->getControls();
443 const Reference
< XControl
>* pControls
= aControls
.getConstArray();
444 sal_Int32 nControlCount
= aControls
.getLength();
446 Sequence
< Reference
< XInterface
> > aObjects( nControlCount
+ 1 );
447 Reference
< XInterface
>* pObjects
= aObjects
.getArray();
448 for ( sal_Int32 i
= 0; i
< nControlCount
; ++i
)
450 pObjects
[i
].set( pControls
[i
], UNO_QUERY
);
453 // also add the dialog control itself to the sequence
454 pObjects
[nControlCount
].set( rxControl
, UNO_QUERY
);
456 Reference
<XScriptEventsAttacher
> xScriptEventsAttacher
457 = new DialogEventsAttacherImpl(
458 m_xContext
, m_xModel
, rxControl
, rxHandler
, rxIntrospectionAccess
,
460 (m_BasicInfo
? m_BasicInfo
->mxBasicRTLListener
: nullptr), msDialogLibName
);
463 xScriptEventsAttacher
->attachEvents( aObjects
, Reference
< XScriptListener
>(), aHelper
);
466 Reference
< XIntrospectionAccess
> DialogProviderImpl::inspectHandler( const Reference
< XInterface
>& rxHandler
)
468 Reference
< XIntrospectionAccess
> xIntrospectionAccess
;
469 static Reference
< XIntrospection
> xIntrospection
;
471 if( !rxHandler
.is() )
472 return xIntrospectionAccess
;
474 if( !xIntrospection
.is() )
476 // Get introspection service
477 xIntrospection
= theIntrospection::get( m_xContext
);
484 aHandlerAny
<<= rxHandler
;
485 xIntrospectionAccess
= xIntrospection
->inspect( aHandlerAny
);
487 catch( RuntimeException
& )
489 xIntrospectionAccess
.clear();
491 return xIntrospectionAccess
;
498 OUString
DialogProviderImpl::getImplementationName( )
500 return "com.sun.star.comp.scripting.DialogProvider";
503 sal_Bool
DialogProviderImpl::supportsService( const OUString
& rServiceName
)
505 return cppu::supportsService(this, rServiceName
);
508 Sequence
< OUString
> DialogProviderImpl::getSupportedServiceNames( )
510 return { "com.sun.star.awt.DialogProvider",
511 "com.sun.star.awt.DialogProvider2",
512 "com.sun.star.awt.ContainerWindowProvider" };
519 void DialogProviderImpl::initialize( const Sequence
< Any
>& aArguments
)
521 ::osl::MutexGuard
aGuard( getMutex() );
523 if ( aArguments
.getLength() == 1 )
525 aArguments
[0] >>= m_xModel
;
527 if ( !m_xModel
.is() )
529 throw RuntimeException( "DialogProviderImpl::initialize: invalid argument format!" );
532 else if ( aArguments
.getLength() == 4 )
534 // call from RTL_Impl_CreateUnoDialog
535 aArguments
[0] >>= m_xModel
;
536 m_BasicInfo
.reset( new BasicRTLParams
);
537 m_BasicInfo
->mxInput
.set( aArguments
[ 1 ], UNO_QUERY_THROW
);
538 // allow null mxDlgLib, a document dialog instantiated from
539 // from application basic is unable to provide ( or find ) it's
541 aArguments
[ 2 ] >>= m_BasicInfo
->mxDlgLib
;
542 // leave the possibility to optionally allow the old dialog creation
543 // to use the new XScriptListener ( which converts the old style macro
545 m_BasicInfo
->mxBasicRTLListener
.set( aArguments
[ 3 ], UNO_QUERY
);
547 else if ( aArguments
.getLength() > 4 )
549 throw RuntimeException( "DialogProviderImpl::initialize: invalid number of arguments!" );
557 constexpr OUString aDecorationPropName
= u
"Decoration"_ustr
;
559 Reference
< XControl
> DialogProviderImpl::createDialogImpl(
560 const OUString
& URL
, const Reference
< XInterface
>& xHandler
,
561 const Reference
< XWindowPeer
>& xParent
, bool bDialogProviderMode
)
563 // if the dialog is located in a document, the document must already be open!
565 ::osl::MutexGuard
aGuard( getMutex() );
568 // m_xHandler = xHandler;
570 //Reference< XDialog > xDialog;
571 Reference
< XControl
> xCtrl
;
572 Reference
< XControlModel
> xCtrlMod
;
575 // add support for basic RTL_FUNCTION
577 xCtrlMod
= createDialogModelForBasic();
580 OSL_ENSURE( !URL
.isEmpty(), "DialogProviderImpl::getDialog: no URL!" );
581 xCtrlMod
= createDialogModel( URL
);
584 catch ( const RuntimeException
& ) { throw; }
585 catch ( const Exception
& )
587 const Any
aError( ::cppu::getCaughtException() );
588 throw WrappedTargetRuntimeException( OUString(), *this, aError
);
592 // i83963 Force decoration
593 if( bDialogProviderMode
)
595 uno::Reference
< beans::XPropertySet
> xDlgModPropSet( xCtrlMod
, uno::UNO_QUERY
);
596 if( xDlgModPropSet
.is() )
600 bool bDecoration
= true;
601 Any aDecorationAny
= xDlgModPropSet
->getPropertyValue( aDecorationPropName
);
602 aDecorationAny
>>= bDecoration
;
605 xDlgModPropSet
->setPropertyValue( aDecorationPropName
, Any( true ) );
606 xDlgModPropSet
->setPropertyValue( "Title", Any( OUString() ) );
609 catch( UnknownPropertyException
& )
614 xCtrl
.set( createDialogControl( xCtrlMod
, xParent
) );
617 Reference
< XIntrospectionAccess
> xIntrospectionAccess
= inspectHandler( xHandler
);
618 attachControlEvents( xCtrl
, xHandler
, xIntrospectionAccess
, bDialogProviderMode
);
625 Reference
< XDialog
> DialogProviderImpl::createDialog( const OUString
& URL
)
627 Reference
< XInterface
> xDummyHandler
;
628 Reference
< XWindowPeer
> xDummyPeer
;
629 Reference
< XControl
> xControl
= DialogProviderImpl::createDialogImpl( URL
, xDummyHandler
, xDummyPeer
, true );
630 Reference
< XDialog
> xDialog( xControl
, UNO_QUERY
);
634 Reference
< XDialog
> DialogProviderImpl::createDialogWithHandler(
635 const OUString
& URL
, const Reference
< XInterface
>& xHandler
)
639 throw IllegalArgumentException(
640 "DialogProviderImpl::createDialogWithHandler: Invalid xHandler!",
641 Reference
< XInterface
>(), 1 );
643 Reference
< XWindowPeer
> xDummyPeer
;
644 Reference
< XControl
> xControl
= DialogProviderImpl::createDialogImpl( URL
, xHandler
, xDummyPeer
, true );
645 Reference
< XDialog
> xDialog( xControl
, UNO_QUERY
);
649 Reference
< XDialog
> DialogProviderImpl::createDialogWithArguments(
650 const OUString
& URL
, const Sequence
< NamedValue
>& Arguments
)
652 ::comphelper::NamedValueCollection
aArguments( Arguments
);
654 Reference
< XWindowPeer
> xParentPeer
;
655 if ( aArguments
.has( "ParentWindow" ) )
657 const Any
& aParentWindow( aArguments
.get( "ParentWindow" ) );
658 if ( !( aParentWindow
>>= xParentPeer
) )
660 const Reference
< XControl
> xParentControl( aParentWindow
, UNO_QUERY
);
661 if ( xParentControl
.is() )
662 xParentPeer
= xParentControl
->getPeer();
666 const Reference
< XInterface
> xHandler( aArguments
.get( "EventHandler" ), UNO_QUERY
);
668 Reference
< XControl
> xControl
= DialogProviderImpl::createDialogImpl( URL
, xHandler
, xParentPeer
, true );
669 Reference
< XDialog
> xDialog( xControl
, UNO_QUERY
);
673 Reference
< XWindow
> DialogProviderImpl::createContainerWindow(
674 const OUString
& URL
, const OUString
&,
675 const Reference
< XWindowPeer
>& xParent
, const Reference
< XInterface
>& xHandler
)
679 throw IllegalArgumentException(
680 "DialogProviderImpl::createContainerWindow: Invalid xParent!",
681 Reference
< XInterface
>(), 1 );
683 Reference
< XControl
> xControl
= DialogProviderImpl::createDialogImpl( URL
, xHandler
, xParent
, false );
684 Reference
< XWindow
> xWindow( xControl
, UNO_QUERY
);
689 // component operations
692 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
693 scripting_DialogProviderImpl_get_implementation(
694 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
696 return cppu::acquire(new DialogProviderImpl(context
));
699 } // namespace dlgprov
702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */