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 "commonpicker.hxx"
22 #include "fpdialogbase.hxx"
23 #include "OfficeControlAccess.hxx"
24 #include <com/sun/star/beans/PropertyAttribute.hpp>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/beans/NamedValue.hpp>
27 #include <vcl/svapp.hxx>
28 #include <vcl/window.hxx>
29 #include <osl/mutex.hxx>
30 #include <sal/log.hxx>
31 #include <tools/debug.hxx>
32 #include <toolkit/helper/vclunohelper.hxx>
33 #include <comphelper/weakeventlistener.hxx>
34 #include <comphelper/types.hxx>
41 #define PROPERTY_ID_HELPURL 1
42 #define PROPERTY_ID_WINDOW 2
44 // using --------------------------------------------------------------
46 using namespace ::com::sun::star::lang
;
47 using namespace ::com::sun::star::ui::dialogs
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::beans
;
50 using namespace ::comphelper
;
53 OCommonPicker::OCommonPicker()
54 :OCommonPicker_Base( m_aMutex
)
55 ,OPropertyContainer( GetBroadcastHelper() )
56 ,m_nCancelEvent( nullptr )
57 ,m_bExecuting( false )
59 // the two properties we have
61 "HelpURL", PROPERTY_ID_HELPURL
,
62 PropertyAttribute::TRANSIENT
,
63 &m_sHelpURL
, cppu::UnoType
<decltype(m_sHelpURL
)>::get()
67 "Window", PROPERTY_ID_WINDOW
,
68 PropertyAttribute::TRANSIENT
| PropertyAttribute::READONLY
,
69 &m_xWindow
, cppu::UnoType
<decltype(m_xWindow
)>::get()
74 OCommonPicker::~OCommonPicker()
76 if ( !GetBroadcastHelper().bDisposed
)
84 // disambiguate XInterface
86 IMPLEMENT_FORWARD_XINTERFACE2( OCommonPicker
, OCommonPicker_Base
, OPropertyContainer
)
89 // disambiguate XTypeProvider
91 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCommonPicker
, OCommonPicker_Base
, OPropertyContainer
)
94 // XComponent related methods
96 void OCommonPicker::checkAlive() const
98 if ( GetBroadcastHelper().bInDispose
|| GetBroadcastHelper().bDisposed
)
99 throw DisposedException();
102 void OCommonPicker::prepareDialog()
107 if ( !m_aTitle
.isEmpty() )
108 m_xDlg
->set_title(m_aTitle
);
113 void SAL_CALL
OCommonPicker::disposing()
115 SolarMutexGuard aGuard
;
117 stopWindowListening();
119 if ( m_nCancelEvent
)
120 Application::RemoveUserEvent( m_nCancelEvent
);
123 ::osl::MutexGuard
aOwnGuard( m_aMutex
);
124 if ( m_bExecuting
&& m_xDlg
)
125 m_xDlg
->response(RET_CANCEL
);
130 m_xDialogParent
= nullptr;
134 void OCommonPicker::stopWindowListening()
136 disposeComponent( m_xWindowListenerAdapter
);
137 disposeComponent( m_xParentListenerAdapter
);
141 void SAL_CALL
OCommonPicker::disposing( const EventObject
& _rSource
)
143 SolarMutexGuard aGuard
;
144 bool bDialogDying
= _rSource
.Source
== m_xWindow
;
145 bool bParentDying
= _rSource
.Source
== m_xDialogParent
;
147 if ( bDialogDying
|| bParentDying
)
149 stopWindowListening();
151 SAL_WARN_IF(bDialogDying
&& m_bExecuting
, "fpicker.office", "unexpected disposing before response" );
153 // it's the parent which is dying -> delete the dialog
155 ::osl::MutexGuard
aOwnGuard(m_aMutex
);
156 if (m_bExecuting
&& m_xDlg
)
157 m_xDlg
->response(RET_CANCEL
);
162 m_xDialogParent
= nullptr;
166 OSL_FAIL( "OCommonPicker::disposing: where did this come from?" );
170 // property set related methods
171 ::cppu::IPropertyArrayHelper
* OCommonPicker::createArrayHelper( ) const
173 Sequence
< Property
> aProps
;
174 describeProperties( aProps
);
175 return new cppu::OPropertyArrayHelper( aProps
);
178 ::cppu::IPropertyArrayHelper
& SAL_CALL
OCommonPicker::getInfoHelper()
180 return *getArrayHelper();
183 Reference
< XPropertySetInfo
> SAL_CALL
OCommonPicker::getPropertySetInfo( )
185 return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
188 void SAL_CALL
OCommonPicker::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
)
190 OPropertyContainer::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
192 // if the HelpURL changed, forward this to the dialog
193 if (PROPERTY_ID_HELPURL
== nHandle
&& m_xDlg
)
195 ::svt::OControlAccess
aAccess(m_xDlg
.get(), m_xDlg
->GetView());
196 aAccess
.setHelpURL(m_xDlg
->getDialog(), m_sHelpURL
);
200 bool OCommonPicker::createPicker()
204 m_xDlg
= implCreateDialog(Application::GetFrameWeld(m_xDialogParent
));
205 SAL_WARN_IF( !m_xDlg
, "fpicker.office", "OCommonPicker::createPicker: invalid dialog returned!" );
209 weld::Dialog
* pDlg
= m_xDlg
->getDialog();
211 ::svt::OControlAccess
aAccess(m_xDlg
.get(), m_xDlg
->GetView());
212 // synchronize the help id of the dialog without help URL property
213 if ( !m_sHelpURL
.isEmpty() )
214 { // somebody already set the help URL while we had no dialog yet
215 aAccess
.setHelpURL(pDlg
, m_sHelpURL
);
219 m_sHelpURL
= aAccess
.getHelpURL(pDlg
);
222 m_xWindow
= pDlg
->GetXWindow();
224 // add as event listener to the window
225 OSL_ENSURE( m_xWindow
.is(), "OCommonPicker::createFileDialog: invalid window component!" );
226 if ( m_xWindow
.is() )
228 m_xWindowListenerAdapter
= new OWeakEventListenerAdapter( this, m_xWindow
);
229 // the adapter will add itself as listener, and forward notifications
232 VclPtr
<vcl::Window
> xVclDialog(VCLUnoHelper::GetWindow(m_xWindow
));
233 if (xVclDialog
) // this block is quite possibly unnecessary by now
235 // _and_ add as event listener to the parent - in case the parent is destroyed
236 // before we are disposed, our disposal would access dead VCL windows then...
237 m_xDialogParent
= VCLUnoHelper::GetInterface(xVclDialog
->GetParent());
238 OSL_ENSURE(m_xDialogParent
.is() || !xVclDialog
->GetParent(), "OCommonPicker::createFileDialog: invalid window component (the parent this time)!");
240 if ( m_xDialogParent
.is() )
242 m_xParentListenerAdapter
= new OWeakEventListenerAdapter( this, m_xDialogParent
);
243 // the adapter will add itself as listener, and forward notifications
248 return nullptr != m_xDlg
;
251 // XControlAccess functions
252 void SAL_CALL
OCommonPicker::setControlProperty( const OUString
& aControlName
, const OUString
& aControlProperty
, const Any
& aValue
)
256 SolarMutexGuard aGuard
;
257 if ( createPicker() )
259 ::svt::OControlAccess
aAccess( m_xDlg
.get(), m_xDlg
->GetView() );
260 aAccess
.setControlProperty( aControlName
, aControlProperty
, aValue
);
264 Any SAL_CALL
OCommonPicker::getControlProperty( const OUString
& aControlName
, const OUString
& aControlProperty
)
268 SolarMutexGuard aGuard
;
269 if ( createPicker() )
271 ::svt::OControlAccess
aAccess( m_xDlg
.get(), m_xDlg
->GetView() );
272 return aAccess
.getControlProperty( aControlName
, aControlProperty
);
278 // XControlInformation functions
279 Sequence
< OUString
> SAL_CALL
OCommonPicker::getSupportedControls( )
283 SolarMutexGuard aGuard
;
284 if ( createPicker() )
286 ::svt::OControlAccess
aAccess( m_xDlg
.get(), m_xDlg
->GetView() );
287 return aAccess
.getSupportedControls( );
290 return Sequence
< OUString
>();
293 sal_Bool SAL_CALL
OCommonPicker::isControlSupported( const OUString
& aControlName
)
297 SolarMutexGuard aGuard
;
298 if ( createPicker() )
300 return svt::OControlAccess::isControlSupported( aControlName
);
306 Sequence
< OUString
> SAL_CALL
OCommonPicker::getSupportedControlProperties( const OUString
& aControlName
)
310 SolarMutexGuard aGuard
;
311 if ( createPicker() )
313 ::svt::OControlAccess
aAccess( m_xDlg
.get(), m_xDlg
->GetView() );
314 return aAccess
.getSupportedControlProperties( aControlName
);
317 return Sequence
< OUString
>();
320 sal_Bool SAL_CALL
OCommonPicker::isControlPropertySupported( const OUString
& aControlName
, const OUString
& aControlProperty
)
324 SolarMutexGuard aGuard
;
325 if ( createPicker() )
327 ::svt::OControlAccess
aAccess( m_xDlg
.get(), m_xDlg
->GetView() );
328 return aAccess
.isControlPropertySupported( aControlName
, aControlProperty
);
335 // XExecutableDialog functions
337 void OCommonPicker::setTitle( const OUString
& _rTitle
)
339 SolarMutexGuard aGuard
;
344 sal_Int16
OCommonPicker::execute()
346 SolarMutexGuard aGuard
;
351 ::osl::MutexGuard
aOwnGuard( m_aMutex
);
354 sal_Int16 nResult
= implExecutePicker();
356 ::osl::MutexGuard
aOwnGuard( m_aMutex
);
357 m_bExecuting
= false;
364 // XCancellable functions
366 void SAL_CALL
OCommonPicker::cancel( )
369 ::osl::MutexGuard
aGuard( m_aMutex
);
370 if ( m_nCancelEvent
)
371 // nothing to do - the event for cancelling the dialog is already on the way
375 // The thread which executes our dialog has locked the solar mutex for
376 // sure. Cancelling the dialog should be done with a locked solar mutex, too.
377 // Thus we post ourself a message for cancelling the dialog. This way, the message
378 // is either handled in the thread which opened the dialog (which may even be
379 // this thread here), or, if no dialog is open, in the thread doing scheduling
380 // currently. Both is okay for us...
382 // Note that we could do check if we are really executing the dialog currently.
383 // but the information would be potentially obsolete at the moment our event
384 // arrives, so we need to check it there, anyway...
385 m_nCancelEvent
= Application::PostUserEvent( LINK( this, OCommonPicker
, OnCancelPicker
) );
388 IMPL_LINK_NOARG(OCommonPicker
, OnCancelPicker
, void*, void)
390 // By definition, the solar mutex is locked when we arrive here. Note that this
391 // is important, as for instance the consistency of m_xDlg depends on this mutex.
392 ::osl::MutexGuard
aGuard( m_aMutex
);
393 m_nCancelEvent
= nullptr;
396 // nothing to do. This may be because the dialog was canceled after our cancel method
397 // posted this async event, or because somebody called cancel without the dialog
398 // being executed at this time.
401 OSL_ENSURE( m_xDlg
, "OCommonPicker::OnCancelPicker: executing, but no dialog!" );
403 m_xDlg
->response(RET_CANCEL
);
406 // XInitialization functions
407 void SAL_CALL
OCommonPicker::initialize( const Sequence
< Any
>& _rArguments
)
411 OUString sSettingName
;
414 PropertyValue aPropArg
;
418 const Any
* pArguments
= _rArguments
.getConstArray();
419 const Any
* pArgumentsEnd
= _rArguments
.getConstArray() + _rArguments
.getLength();
420 for ( const Any
* pArgument
= pArguments
;
421 pArgument
!= pArgumentsEnd
;
425 if ( *pArgument
>>= aPropArg
)
427 if ( aPropArg
.Name
.isEmpty())
430 sSettingName
= aPropArg
.Name
;
431 aSettingValue
= aPropArg
.Value
;
433 else if ( *pArgument
>>= aPairArg
)
435 if ( aPairArg
.Name
.isEmpty())
438 sSettingName
= aPairArg
.Name
;
439 aSettingValue
= aPairArg
.Value
;
445 SAL_WARN( "fpicker", "OCommonPicker::initialize: unknown argument type at position "
446 << (pArguments
- _rArguments
.getConstArray()));
451 implHandleInitializationArgument( sSettingName
, aSettingValue
);
452 DBG_ASSERT( bKnownSetting
,
454 "OCommonPicker::initialize: unknown argument \""
455 + OUStringToOString(sSettingName
, osl_getThreadTextEncoding())
460 bool OCommonPicker::implHandleInitializationArgument( const OUString
& _rName
, const Any
& _rValue
)
463 if ( _rName
== "ParentWindow" )
465 m_xDialogParent
.clear();
466 OSL_VERIFY( _rValue
>>= m_xDialogParent
);
467 OSL_ENSURE( m_xDialogParent
.is(), "OCommonPicker::implHandleInitializationArgument: invalid parent window given!" );
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */