xref: /AOO41X/main/fpicker/source/office/commonpicker.cxx (revision b557fc96600fce3029f73c89748b6c08fd00b34d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_fpicker.hxx"
26 
27 #include "commonpicker.hxx"
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <com/sun/star/beans/NamedValue.hpp>
30 #include <vcl/svapp.hxx>
31 #include <vos/mutex.hxx>
32 #include <toolkit/helper/vclunohelper.hxx>
33 #include <comphelper/weakeventlistener.hxx>
34 #include <comphelper/types.hxx>
35 #include <vcl/msgbox.hxx>
36 #include "iodlg.hxx"
37 
38 //.........................................................................
39 namespace svt
40 {
41 //.........................................................................
42 
43 #define PROPERTY_ID_HELPURL     1
44 #define PROPERTY_ID_WINDOW      2
45 
46     // using --------------------------------------------------------------
47 
48     using namespace     ::com::sun::star::lang;
49     using namespace     ::com::sun::star::ui::dialogs;
50     using namespace     ::com::sun::star::uno;
51     using namespace     ::com::sun::star::beans;
52     using namespace     ::comphelper;
53 
54     //---------------------------------------------------------------------
OCommonPicker(const::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & _rxFactory)55     OCommonPicker::OCommonPicker( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory )
56         :OCommonPicker_Base( m_aMutex )
57         ,OPropertyContainer( GetBroadcastHelper() )
58         ,m_xORB( _rxFactory )
59         ,m_pDlg( NULL )
60         ,m_nCancelEvent( 0 )
61         ,m_bExecuting( sal_False )
62     {
63         // the two properties we have
64         registerProperty(
65             ::rtl::OUString::createFromAscii( "HelpURL" ), PROPERTY_ID_HELPURL,
66             PropertyAttribute::TRANSIENT,
67             &m_sHelpURL, ::getCppuType( &m_sHelpURL )
68         );
69 
70         registerProperty(
71             ::rtl::OUString::createFromAscii( "Window" ), PROPERTY_ID_WINDOW,
72             PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY,
73             &m_xWindow, ::getCppuType( &m_xWindow )
74         );
75     }
76 
77     //---------------------------------------------------------------------
~OCommonPicker()78     OCommonPicker::~OCommonPicker()
79     {
80         if ( !GetBroadcastHelper().bDisposed )
81         {
82             acquire();
83             dispose();
84         }
85     }
86 
87     //---------------------------------------------------------------------
88     // disambiguate XInterface
89     //---------------------------------------------------------------------
IMPLEMENT_FORWARD_XINTERFACE2(OCommonPicker,OCommonPicker_Base,OPropertyContainer)90     IMPLEMENT_FORWARD_XINTERFACE2( OCommonPicker, OCommonPicker_Base, OPropertyContainer )
91 
92     //---------------------------------------------------------------------
93     // disambiguate XTypeProvider
94     //---------------------------------------------------------------------
95     IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCommonPicker, OCommonPicker_Base, OPropertyContainer )
96 
97     //---------------------------------------------------------------------
98     // XComponent related methods
99     //---------------------------------------------------------------------
100     void OCommonPicker::checkAlive() const SAL_THROW( (DisposedException) )
101     {
102         if ( GetBroadcastHelper().bInDispose || GetBroadcastHelper().bDisposed )
103             throw DisposedException();
104     }
105 
prepareDialog()106     void OCommonPicker::prepareDialog()
107     {
108         if ( !getDialog() )
109             createPicker();
110 
111         // set the title
112         if ( m_aTitle.getLength() > 0 )
113             getDialog()->SetText( m_aTitle );
114     }
115 
116     //---------------------------------------------------------------------
disposing()117     void SAL_CALL OCommonPicker::disposing()
118     {
119         ::vos::OGuard aGuard( Application::GetSolarMutex() );
120 
121         stopWindowListening();
122 
123         if ( m_nCancelEvent )
124             Application::RemoveUserEvent( m_nCancelEvent );
125 
126         {
127             ::osl::MutexGuard aOwnGuard( m_aMutex );
128             if ( m_bExecuting && m_pDlg )
129                 m_pDlg->EndDialog( RET_CANCEL );
130         }
131 
132         delete m_pDlg;
133         m_pDlg = NULL;
134         m_xWindow = NULL;
135         m_xDialogParent = NULL;
136     }
137 
138     //---------------------------------------------------------------------
stopWindowListening()139     void OCommonPicker::stopWindowListening()
140     {
141         disposeComponent( m_xWindowListenerAdapter );
142         disposeComponent( m_xParentListenerAdapter );
143     }
144 
145     //---------------------------------------------------------------------
146     // XEventListener
147     //---------------------------------------------------------------------
disposing(const EventObject & _rSource)148     void SAL_CALL OCommonPicker::disposing( const EventObject& _rSource ) throw (RuntimeException)
149     {
150         ::vos::OGuard aGuard( Application::GetSolarMutex() );
151         sal_Bool bDialogDying = _rSource.Source == m_xWindow;
152         sal_Bool bParentDying = _rSource.Source == m_xDialogParent;
153 
154         if ( bDialogDying || bParentDying )
155         {
156             stopWindowListening();
157 
158             if ( !bDialogDying )    // it's the parent which is dying -> delete the dialog
159                 delete m_pDlg;
160 
161             m_pDlg = NULL;
162             m_xWindow = NULL;
163             m_xDialogParent = NULL;
164         }
165         else
166         {
167             DBG_ERROR( "OCommonPicker::disposing: where did this come from?" );
168         }
169     }
170 
171     //---------------------------------------------------------------------
172     // property set related methods
173     //---------------------------------------------------------------------
createArrayHelper() const174     ::cppu::IPropertyArrayHelper* OCommonPicker::createArrayHelper( ) const
175     {
176         Sequence< Property > aProps;
177         describeProperties( aProps );
178         return new cppu::OPropertyArrayHelper( aProps );
179     }
180 
181     //---------------------------------------------------------------------
getInfoHelper()182     ::cppu::IPropertyArrayHelper& SAL_CALL OCommonPicker::getInfoHelper()
183     {
184         return *const_cast< OCommonPicker* >( this )->getArrayHelper();
185     }
186 
187     //---------------------------------------------------------------------
getPropertySetInfo()188     Reference< XPropertySetInfo > SAL_CALL OCommonPicker::getPropertySetInfo(  ) throw(RuntimeException)
189     {
190         return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
191     }
192 
193     //---------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)194     void SAL_CALL OCommonPicker::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception)
195     {
196         OPropertyContainer::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
197 
198         // if the HelpURL changed, forward this to the dialog
199         if ( PROPERTY_ID_HELPURL == _nHandle )
200             if ( m_pDlg )
201                 OControlAccess::setHelpURL( m_pDlg, m_sHelpURL, sal_False );
202     }
203 
204 
205     //---------------------------------------------------------------------
createPicker()206     sal_Bool OCommonPicker::createPicker()
207     {
208         ::vos::OGuard aGuard( Application::GetSolarMutex() );
209 
210         if ( !m_pDlg )
211         {
212             m_pDlg = implCreateDialog( VCLUnoHelper::GetWindow( m_xDialogParent ) );
213             DBG_ASSERT( m_pDlg, "OCommonPicker::createPicker: invalid dialog returned!" );
214 
215             if ( m_pDlg )
216             {
217                 // synchronize the help id of the dialog with out help URL property
218                 if ( m_sHelpURL.getLength() )
219                 {   // somebody already set the help URL while we had no dialog yet
220                     OControlAccess::setHelpURL( m_pDlg, m_sHelpURL, sal_False );
221                 }
222                 else
223                 {
224                     m_sHelpURL = OControlAccess::getHelpURL( m_pDlg, sal_False );
225                 }
226 
227                 m_xWindow = VCLUnoHelper::GetInterface( m_pDlg );
228 
229                 // add as event listener to the window
230                 Reference< XComponent > xWindowComp( m_xWindow, UNO_QUERY );
231                 OSL_ENSURE( xWindowComp.is(), "OCommonPicker::createFileDialog: invalid window component!" );
232                 if ( xWindowComp.is() )
233                 {
234                     m_xWindowListenerAdapter = new OWeakEventListenerAdapter( this, xWindowComp );
235                         // the adapter will add itself as listener, and forward notifications
236                 }
237 
238                 // _and_ add as event listener to the parent - in case the parent is destroyed
239                 // before we are disposed, our disposal would access dead VCL windows then ....
240                 m_xDialogParent = VCLUnoHelper::GetInterface( m_pDlg->GetParent() );
241                 xWindowComp = xWindowComp.query( m_xDialogParent );
242                 OSL_ENSURE( xWindowComp.is() || !m_pDlg->GetParent(), "OCommonPicker::createFileDialog: invalid window component (the parent this time)!" );
243                 if ( xWindowComp.is() )
244                 {
245                     m_xParentListenerAdapter = new OWeakEventListenerAdapter( this, xWindowComp );
246                         // the adapter will add itself as listener, and forward notifications
247                 }
248             }
249         }
250 
251         return NULL != m_pDlg;
252     }
253 
254     //---------------------------------------------------------------------
255     // XControlAccess functions
256     //---------------------------------------------------------------------
setControlProperty(const::rtl::OUString & aControlName,const::rtl::OUString & aControlProperty,const Any & aValue)257     void SAL_CALL OCommonPicker::setControlProperty( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty, const Any& aValue ) throw (IllegalArgumentException, RuntimeException)
258     {
259         checkAlive();
260 
261         ::vos::OGuard aGuard( Application::GetSolarMutex() );
262         if ( createPicker() )
263         {
264             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
265             aAccess.setControlProperty( aControlName, aControlProperty, aValue );
266         }
267     }
268 
269     //---------------------------------------------------------------------
getControlProperty(const::rtl::OUString & aControlName,const::rtl::OUString & aControlProperty)270     Any SAL_CALL OCommonPicker::getControlProperty( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty ) throw (IllegalArgumentException, RuntimeException)
271     {
272         checkAlive();
273 
274         ::vos::OGuard aGuard( Application::GetSolarMutex() );
275         if ( createPicker() )
276         {
277             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
278             return aAccess.getControlProperty( aControlName, aControlProperty );
279         }
280 
281         return Any();
282     }
283 
284     //---------------------------------------------------------------------
285     // XControlInformation functions
286     //---------------------------------------------------------------------
getSupportedControls()287     Sequence< ::rtl::OUString > SAL_CALL OCommonPicker::getSupportedControls(  ) throw (RuntimeException)
288     {
289         checkAlive();
290 
291         ::vos::OGuard aGuard( Application::GetSolarMutex() );
292         if ( createPicker() )
293         {
294             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
295             return aAccess.getSupportedControls( );
296         }
297 
298         return Sequence< ::rtl::OUString >();
299     }
300 
301     //---------------------------------------------------------------------
isControlSupported(const::rtl::OUString & aControlName)302     sal_Bool SAL_CALL OCommonPicker::isControlSupported( const ::rtl::OUString& aControlName ) throw (RuntimeException)
303     {
304         checkAlive();
305 
306         ::vos::OGuard aGuard( Application::GetSolarMutex() );
307         if ( createPicker() )
308         {
309             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
310             return aAccess.isControlSupported( aControlName );
311         }
312 
313         return sal_False;
314     }
315 
316     //---------------------------------------------------------------------
getSupportedControlProperties(const::rtl::OUString & aControlName)317     Sequence< ::rtl::OUString > SAL_CALL OCommonPicker::getSupportedControlProperties( const ::rtl::OUString& aControlName ) throw (IllegalArgumentException, RuntimeException)
318     {
319         checkAlive();
320 
321         ::vos::OGuard aGuard( Application::GetSolarMutex() );
322         if ( createPicker() )
323         {
324             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
325             return aAccess.getSupportedControlProperties( aControlName );
326         }
327 
328         return Sequence< ::rtl::OUString >();
329     }
330 
331     //---------------------------------------------------------------------
isControlPropertySupported(const::rtl::OUString & aControlName,const::rtl::OUString & aControlProperty)332     sal_Bool SAL_CALL OCommonPicker::isControlPropertySupported( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty ) throw (IllegalArgumentException, RuntimeException)
333     {
334         checkAlive();
335 
336         ::vos::OGuard aGuard( Application::GetSolarMutex() );
337         if ( createPicker() )
338         {
339             ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() );
340             return aAccess.isControlPropertySupported( aControlName, aControlProperty );
341         }
342 
343         return sal_False;
344     }
345 
346     //---------------------------------------------------------------------
347     // XExecutableDialog functions
348     //---------------------------------------------------------------------
setTitle(const rtl::OUString & _rTitle)349     void SAL_CALL OCommonPicker::setTitle( const rtl::OUString& _rTitle ) throw( RuntimeException )
350     {
351         ::vos::OGuard aGuard( Application::GetSolarMutex() );
352         m_aTitle = _rTitle;
353     }
354 
355     //---------------------------------------------------------------------
execute()356     sal_Int16 OCommonPicker::execute() throw (RuntimeException)
357     {
358         ::vos::OGuard aGuard( Application::GetSolarMutex() );
359 
360         prepareDialog();
361 
362         {
363             ::osl::MutexGuard aOwnGuard( m_aMutex );
364             m_bExecuting = sal_True;
365         }
366         sal_Int16 nResult = implExecutePicker();
367         {
368             ::osl::MutexGuard aOwnGuard( m_aMutex );
369             m_bExecuting = sal_False;
370         }
371 
372         return nResult;
373     }
374 
375     //---------------------------------------------------------------------
376     // XCancellable functions
377     //---------------------------------------------------------------------
cancel()378     void SAL_CALL OCommonPicker::cancel(  ) throw (RuntimeException)
379     {
380         {
381             ::osl::MutexGuard aGuard( m_aMutex );
382             if ( m_nCancelEvent )
383                 // nothing to do - the event for cancelling the dialog is already on the way
384                 return;
385         }
386 
387         // The thread which executes our dialog has locked the solar mutex for
388         // sure. Cancelling the dialog should be done with a locked solar mutex, too.
389         // Thus we post ourself a message for cancelling the dialog. This way, the message
390         // is either handled in the thread which opened the dialog (which may even be
391         // this thread here), or, if no dialog is open, in the thread doing scheduling
392         // currently. Both is okay for us ....
393         //
394         // Note that we could do check if we are really executing the dialog currently.
395         // but the information would be potentially obsolete at the moment our event
396         // arrives, so we need to check it there, anyway ...
397         m_nCancelEvent = Application::PostUserEvent( LINK( this, OCommonPicker, OnCancelPicker ) );
398     }
399 
400     //---------------------------------------------------------------------
IMPL_LINK(OCommonPicker,OnCancelPicker,void *,EMPTYARG)401     IMPL_LINK( OCommonPicker, OnCancelPicker, void*, EMPTYARG )
402     {
403         // By definition, the solar mutex is locked when we arrive here. Note that this
404         // is important, as for instance the consistency of m_pDlg depends on this mutex.
405         ::osl::MutexGuard aGuard( m_aMutex );
406         m_nCancelEvent = 0;
407 
408         if ( !m_bExecuting )
409             // nothing to do. This may be because the dialog was cancelled after our cancel method
410             // posted this async event, or because somebody called cancel without the dialog
411             // being executed at this time.
412             return 0;
413 
414         OSL_ENSURE( getDialog(), "OCommonPicker::OnCancelPicker: executing, but no dialog!" );
415         if ( getDialog() )
416             getDialog()->EndDialog( RET_CANCEL );
417 
418         return 0L;
419     }
420 
421     //------------------------------------------------------------------------------------
422     // XInitialization functions
423     //------------------------------------------------------------------------------------
initialize(const Sequence<Any> & _rArguments)424     void SAL_CALL OCommonPicker::initialize( const Sequence< Any >& _rArguments )
425         throw ( Exception, RuntimeException )
426     {
427         checkAlive();
428 
429         ::rtl::OUString sSettingName;
430         Any             aSettingValue;
431 
432         PropertyValue   aPropArg;
433         NamedValue      aPairArg;
434 
435 
436         const Any* pArguments       = _rArguments.getConstArray();
437         const Any* pArgumentsEnd    = _rArguments.getConstArray() + _rArguments.getLength();
438         for (   const Any* pArgument = pArguments;
439                 pArgument != pArgumentsEnd;
440                 ++pArgument
441             )
442         {
443             if ( *pArgument >>= aPropArg )
444             {
445                 if ( aPropArg.Name.getLength() <= 0)
446                     continue;
447 
448                 sSettingName = aPropArg.Name;
449                 aSettingValue = aPropArg.Value;
450             }
451             else if ( *pArgument >>= aPairArg )
452             {
453                 if ( aPairArg.Name.getLength() <= 0)
454                     continue;
455 
456                 sSettingName = aPairArg.Name;
457                 aSettingValue = aPairArg.Value;
458 
459 
460             }
461             else
462             {
463                 DBG_ERROR(
464                     (   ::rtl::OString( "OCommonPicker::initialize: unknown argument type at position " )
465                     +=  ::rtl::OString::valueOf( (sal_Int32)( pArguments - _rArguments.getConstArray() ) )
466                     ).getStr()
467                 );
468                 continue;
469             }
470 
471 #ifdef DBG_UTIL
472             sal_Bool bKnownSetting =
473 #endif
474             implHandleInitializationArgument( sSettingName, aSettingValue );
475             DBG_ASSERT( bKnownSetting,
476                 (   ::rtl::OString( "OCommonPicker::initialize: unknown argument \"" )
477                 +=  ::rtl::OString( sSettingName.getStr(), sSettingName.getLength(), osl_getThreadTextEncoding() )
478                 +=  ::rtl::OString( "\"!" )
479                 ).getStr()
480             );
481         }
482     }
483 
484     //---------------------------------------------------------------------
implHandleInitializationArgument(const::rtl::OUString & _rName,const Any & _rValue)485     sal_Bool OCommonPicker::implHandleInitializationArgument( const ::rtl::OUString& _rName, const Any& _rValue ) SAL_THROW( ( Exception, RuntimeException ) )
486     {
487         sal_Bool bKnown = sal_True;
488         if ( _rName.equalsAscii( "ParentWindow" ) )
489         {
490             m_xDialogParent.clear();
491             OSL_VERIFY( _rValue >>= m_xDialogParent );
492             OSL_ENSURE( VCLUnoHelper::GetWindow( m_xDialogParent ), "OCommonPicker::implHandleInitializationArgument: invalid parent window given!" );
493         }
494         else
495             bKnown = sal_False;
496         return bKnown;
497     }
498 
499 //.........................................................................
500 }   // namespace svt
501 //.........................................................................
502 
503