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