1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25  ************************************************************************/
26 
27 #include "precompiled_svtools.hxx"
28 
29 #include "../unowizard.hxx"
30 #include "wizardshell.hxx"
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/lang/XInitialization.hpp>
34 #include <com/sun/star/beans/XPropertySetInfo.hpp>
35 #include <com/sun/star/uno/XComponentContext.hpp>
36 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
37 #include <com/sun/star/ui/dialogs/XWizardController.hpp>
38 #include <com/sun/star/ui/dialogs/WizardButton.hpp>
39 /** === end UNO includes === **/
40 
41 #include <tools/diagnose_ex.h>
42 #include <rtl/strbuf.hxx>
43 #include <vos/mutex.hxx>
44 #include <vcl/svapp.hxx>
45 #include <tools/urlobj.hxx>
46 
47 //......................................................................................................................
48 namespace svt { namespace uno
49 {
50 //......................................................................................................................
51 
52 	/** === begin UNO using === **/
53 	using ::com::sun::star::uno::Reference;
54 	using ::com::sun::star::uno::XInterface;
55 	using ::com::sun::star::uno::UNO_QUERY;
56 	using ::com::sun::star::uno::UNO_QUERY_THROW;
57 	using ::com::sun::star::uno::UNO_SET_THROW;
58 	using ::com::sun::star::uno::Exception;
59 	using ::com::sun::star::uno::RuntimeException;
60 	using ::com::sun::star::uno::Any;
61 	using ::com::sun::star::uno::makeAny;
62 	using ::com::sun::star::uno::Sequence;
63 	using ::com::sun::star::uno::Type;
64     using ::com::sun::star::lang::XServiceInfo;
65     using ::com::sun::star::ui::dialogs::XWizard;
66     using ::com::sun::star::lang::XInitialization;
67     using ::com::sun::star::beans::XPropertySetInfo;
68     using ::com::sun::star::uno::XComponentContext;
69     using ::com::sun::star::beans::Property;
70     using ::com::sun::star::lang::IllegalArgumentException;
71     using ::com::sun::star::ucb::AlreadyInitializedException;
72     using ::com::sun::star::ui::dialogs::XWizardController;
73     using ::com::sun::star::ui::dialogs::XWizardPage;
74     using ::com::sun::star::container::NoSuchElementException;
75     using ::com::sun::star::util::InvalidStateException;
76     using ::com::sun::star::awt::XWindow;
77 	/** === end UNO using === **/
78     namespace WizardButton = ::com::sun::star::ui::dialogs::WizardButton;
79 
80 	//------------------------------------------------------------------------------------------------------------------
81     namespace
82     {
83         sal_uInt32 lcl_convertWizardButtonToWZB( const sal_Int16 i_nWizardButton )
84         {
85             switch ( i_nWizardButton )
86             {
87             case WizardButton::NONE:        return WZB_NONE;
88             case WizardButton::NEXT:        return WZB_NEXT;
89             case WizardButton::PREVIOUS:    return WZB_PREVIOUS;
90             case WizardButton::FINISH:      return WZB_FINISH;
91             case WizardButton::CANCEL:      return WZB_CANCEL;
92             case WizardButton::HELP:        return WZB_HELP;
93             }
94             OSL_ENSURE( false, "lcl_convertWizardButtonToWZB: invalid WizardButton constant!" );
95             return WZB_NONE;
96         }
97     }
98 
99 	//==================================================================================================================
100 	//= Wizard - implementation
101 	//==================================================================================================================
102 	//------------------------------------------------------------------------------------------------------------------
103     Wizard::Wizard( const Reference< XComponentContext >& _rxContext )
104         :Wizard_Base( _rxContext )
105         ,m_aContext( _rxContext )
106     {
107     }
108 
109     //--------------------------------------------------------------------
110     Wizard::~Wizard()
111     {
112         // we do this here cause the base class' call to destroyDialog won't reach us anymore : we're within an dtor,
113         // so this virtual-method-call the base class does does not work, we're already dead then ...
114         if ( m_pDialog )
115         {
116             ::osl::MutexGuard aGuard( m_aMutex );
117             if ( m_pDialog )
118                 destroyDialog();
119         }
120     }
121 
122     //--------------------------------------------------------------------
123     Reference< XInterface > SAL_CALL Wizard::Create( const Reference< XComponentContext >& _rxContext )
124     {
125         return *(new Wizard( _rxContext ) );
126     }
127 
128     //--------------------------------------------------------------------
129     namespace
130     {
131         static void lcl_checkPaths( const Sequence< Sequence< sal_Int16 > >& i_rPaths, const Reference< XInterface >& i_rContext )
132         {
133             // need at least one path
134             if ( i_rPaths.getLength() == 0 )
135                 throw IllegalArgumentException( ::rtl::OUString(), i_rContext, 2 );
136 
137             // each path must be of length 1, at least
138             for ( sal_Int32 i = 0; i < i_rPaths.getLength(); ++i )
139             {
140                 if ( i_rPaths[i].getLength() == 0 )
141                     throw IllegalArgumentException( ::rtl::OUString(), i_rContext, 2 );
142 
143                 // page IDs must be in ascending order
144                 sal_Int16 nPreviousPageID = i_rPaths[i][0];
145                 for ( sal_Int32 j=1; j<i_rPaths[i].getLength(); ++j )
146                 {
147                     if ( i_rPaths[i][j] <= nPreviousPageID )
148                     {
149                         ::rtl::OStringBuffer message;
150                         message.append( "Path " );
151                         message.append( i );
152                         message.append( ": invalid page ID sequence - each page ID must be greater than the previous one." );
153                         throw IllegalArgumentException(
154                             ::rtl::OStringToOUString( message.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ),
155                             i_rContext, 2 );
156                     }
157                     nPreviousPageID = i_rPaths[i][j];
158                 }
159             }
160 
161             // if we have one path, that's okay
162             if ( i_rPaths.getLength() == 1 )
163                 return;
164 
165             // if we have multiple paths, they must start with the same page id
166             const sal_Int16 nFirstPageId = i_rPaths[0][0];
167             for ( sal_Int32 i = 0; i < i_rPaths.getLength(); ++i )
168             {
169                 if ( i_rPaths[i][0] != nFirstPageId )
170                     throw IllegalArgumentException(
171                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "All paths must start with the same page id." ) ),
172                         i_rContext, 2 );
173             }
174         }
175     }
176 
177     //--------------------------------------------------------------------
178     void SAL_CALL Wizard::initialize( const Sequence< Any >& i_Arguments ) throw (Exception, RuntimeException)
179     {
180         ::osl::MutexGuard aGuard( m_aMutex );
181         if ( m_bInitialized )
182             throw AlreadyInitializedException( ::rtl::OUString(), *this );
183 
184         if ( i_Arguments.getLength() != 2 )
185             throw IllegalArgumentException( ::rtl::OUString(), *this, -1 );
186 
187         // the second argument must be a XWizardController, for each constructor
188         m_xController.set( i_Arguments[1], UNO_QUERY );
189         if ( !m_xController.is() )
190             throw IllegalArgumentException( ::rtl::OUString(), *this, 2 );
191 
192         // the first arg is either a single path (short[]), or multiple paths (short[][])
193         Sequence< sal_Int16 > aSinglePath;
194         i_Arguments[0] >>= aSinglePath;
195         Sequence< Sequence< sal_Int16 > > aMultiplePaths;
196         i_Arguments[0] >>= aMultiplePaths;
197 
198         if ( !aMultiplePaths.getLength() )
199         {
200             aMultiplePaths.realloc(1);
201             aMultiplePaths[0] = aSinglePath;
202         }
203         lcl_checkPaths( aMultiplePaths, *this );
204         // if we survived this, the paths are valid, and we're done here ...
205         m_aWizardSteps = aMultiplePaths;
206 
207         m_bInitialized = true;
208     }
209 
210 	static rtl::OString lcl_getHelpId( const ::rtl::OUString& _rHelpURL )
211     {
212         INetURLObject aHID( _rHelpURL );
213         if ( aHID.GetProtocol() == INET_PROT_HID )
214             return rtl::OUStringToOString( aHID.GetURLPath(), RTL_TEXTENCODING_UTF8 );
215         else
216             return rtl::OUStringToOString( _rHelpURL, RTL_TEXTENCODING_UTF8 );
217     }
218 
219 	//------------------------------------------------------------------------
220     static ::rtl::OUString lcl_getHelpURL( const rtl::OString& sHelpId )
221     {
222         ::rtl::OUStringBuffer aBuffer;
223         ::rtl::OUString aTmp( sHelpId, sHelpId.getLength(), RTL_TEXTENCODING_UTF8 );
224         INetURLObject aHID( aTmp );
225         if ( aHID.GetProtocol() == INET_PROT_NOT_VALID )
226             aBuffer.appendAscii( INET_HID_SCHEME );
227         aBuffer.append( aTmp.getStr() );
228         return aBuffer.makeStringAndClear();
229     }
230 
231     //--------------------------------------------------------------------
232 	Dialog*	Wizard::createDialog( Window* i_pParent )
233     {
234         WizardShell* pDialog( new WizardShell( i_pParent, this, m_xController, m_aWizardSteps ) );
235         pDialog->SetHelpId(  lcl_getHelpId( m_sHelpURL ) );
236         pDialog->setTitleBase( m_sTitle );
237         return pDialog;
238     }
239 
240     //--------------------------------------------------------------------
241     void Wizard::destroyDialog()
242     {
243         if ( m_pDialog )
244             m_sHelpURL = lcl_getHelpURL( m_pDialog->GetHelpId() );
245 
246 	    Wizard_Base::destroyDialog();
247     }
248 
249     //--------------------------------------------------------------------
250     ::rtl::OUString SAL_CALL Wizard::getImplementationName_static() throw(RuntimeException)
251     {
252         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.svtools.uno.Wizard" ) );
253     }
254 
255     //--------------------------------------------------------------------
256     Sequence< ::rtl::OUString > SAL_CALL Wizard::getSupportedServiceNames_static() throw(RuntimeException)
257     {
258         Sequence< ::rtl::OUString > aServices(1);
259         aServices[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.Wizard" ) );
260         return aServices;
261     }
262 
263     //--------------------------------------------------------------------
264     ::rtl::OUString SAL_CALL Wizard::getImplementationName() throw(RuntimeException)
265     {
266         return getImplementationName_static();
267     }
268 
269     //--------------------------------------------------------------------
270     Sequence< ::rtl::OUString > SAL_CALL Wizard::getSupportedServiceNames() throw(RuntimeException)
271     {
272         return getSupportedServiceNames_static();
273     }
274 
275     //--------------------------------------------------------------------
276 	Reference< XPropertySetInfo > SAL_CALL Wizard::getPropertySetInfo() throw(RuntimeException)
277     {
278 	    return createPropertySetInfo( getInfoHelper() );
279     }
280 
281     //--------------------------------------------------------------------
282 	::cppu::IPropertyArrayHelper& SAL_CALL Wizard::getInfoHelper()
283     {
284     	return *const_cast< Wizard* >( this )->getArrayHelper();
285     }
286 
287     //--------------------------------------------------------------------
288 	::cppu::IPropertyArrayHelper* Wizard::createArrayHelper( ) const
289     {
290 	    Sequence< Property > aProps;
291 	    describeProperties( aProps );
292 	    return new ::cppu::OPropertyArrayHelper( aProps );
293     }
294 
295     //------------------------------------------------------------------------------------------------------------------
296     ::rtl::OUString SAL_CALL Wizard::getHelpURL() throw (RuntimeException)
297     {
298         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
299         ::osl::MutexGuard aGuard( m_aMutex );
300 
301         if ( !m_pDialog )
302             return m_sHelpURL;
303 
304         return lcl_getHelpURL( m_pDialog->GetHelpId() );
305     }
306 
307     //------------------------------------------------------------------------------------------------------------------
308     void SAL_CALL Wizard::setHelpURL( const ::rtl::OUString& i_HelpURL ) throw (RuntimeException)
309     {
310         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
311         ::osl::MutexGuard aGuard( m_aMutex );
312 
313         if ( !m_pDialog )
314             m_sHelpURL = i_HelpURL;
315         else
316             m_pDialog->SetHelpId( lcl_getHelpId( i_HelpURL ) );
317     }
318 
319     //------------------------------------------------------------------------------------------------------------------
320     Reference< XWindow > SAL_CALL Wizard::getDialogWindow() throw (RuntimeException)
321     {
322         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
323         ::osl::MutexGuard aGuard( m_aMutex );
324 
325         ENSURE_OR_RETURN( m_pDialog, "Wizard::getDialogWindow: illegal call (execution did not start, yet)!", NULL );
326         return Reference< XWindow >( m_pDialog->GetComponentInterface(), UNO_QUERY );
327     }
328 
329     //------------------------------------------------------------------------------------------------------------------
330     void SAL_CALL Wizard::enableButton( ::sal_Int16 i_WizardButton, ::sal_Bool i_Enable ) throw (RuntimeException)
331     {
332         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
333         ::osl::MutexGuard aGuard( m_aMutex );
334 
335         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
336         ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::enableButtons: invalid dialog implementation!" );
337 
338         pWizardImpl->enableButtons( lcl_convertWizardButtonToWZB( i_WizardButton ), i_Enable );
339     }
340 
341     //------------------------------------------------------------------------------------------------------------------
342     void SAL_CALL Wizard::setDefaultButton( ::sal_Int16 i_WizardButton ) throw (RuntimeException)
343     {
344         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
345         ::osl::MutexGuard aGuard( m_aMutex );
346 
347         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
348         ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::setDefaultButton: invalid dialog implementation!" );
349 
350         pWizardImpl->defaultButton( lcl_convertWizardButtonToWZB( i_WizardButton ) );
351     }
352 
353     //------------------------------------------------------------------------------------------------------------------
354     sal_Bool SAL_CALL Wizard::travelNext(  ) throw (RuntimeException)
355     {
356         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
357         ::osl::MutexGuard aGuard( m_aMutex );
358 
359         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
360         ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::travelNext: invalid dialog implementation!" );
361 
362         return pWizardImpl->travelNext();
363     }
364 
365     //------------------------------------------------------------------------------------------------------------------
366     sal_Bool SAL_CALL Wizard::travelPrevious(  ) throw (RuntimeException)
367     {
368         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
369         ::osl::MutexGuard aGuard( m_aMutex );
370 
371         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
372         ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::travelPrevious: invalid dialog implementation!" );
373 
374         return pWizardImpl->travelPrevious();
375     }
376 
377     //------------------------------------------------------------------------------------------------------------------
378     void SAL_CALL Wizard::enablePage( ::sal_Int16 i_PageID, ::sal_Bool i_Enable ) throw (NoSuchElementException, InvalidStateException, RuntimeException)
379     {
380         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
381         ::osl::MutexGuard aGuard( m_aMutex );
382 
383         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
384         ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::enablePage: invalid dialog implementation!" );
385 
386         if ( !pWizardImpl->knowsPage( i_PageID ) )
387             throw NoSuchElementException( ::rtl::OUString(), *this );
388 
389         if ( i_PageID == pWizardImpl->getCurrentPage() )
390             throw InvalidStateException( ::rtl::OUString(), *this );
391 
392         pWizardImpl->enablePage( i_PageID, i_Enable );
393     }
394 
395     //------------------------------------------------------------------------------------------------------------------
396     void SAL_CALL Wizard::updateTravelUI(  ) throw (RuntimeException)
397     {
398         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
399         ::osl::MutexGuard aGuard( m_aMutex );
400 
401         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
402         ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::updateTravelUI: invalid dialog implementation!" );
403 
404         pWizardImpl->updateTravelUI();
405     }
406 
407     //------------------------------------------------------------------------------------------------------------------
408     ::sal_Bool SAL_CALL Wizard::advanceTo( ::sal_Int16 i_PageId ) throw (RuntimeException)
409     {
410         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
411         ::osl::MutexGuard aGuard( m_aMutex );
412 
413         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
414         ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::advanceTo: invalid dialog implementation!" );
415 
416         return pWizardImpl->advanceTo( i_PageId );
417     }
418 
419     //------------------------------------------------------------------------------------------------------------------
420     ::sal_Bool SAL_CALL Wizard::goBackTo( ::sal_Int16 i_PageId ) throw (RuntimeException)
421     {
422         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
423         ::osl::MutexGuard aGuard( m_aMutex );
424 
425         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
426         ENSURE_OR_RETURN_FALSE( pWizardImpl, "Wizard::goBackTo: invalid dialog implementation!" );
427 
428         return pWizardImpl->goBackTo( i_PageId );
429     }
430 
431     //------------------------------------------------------------------------------------------------------------------
432     Reference< XWizardPage > SAL_CALL Wizard::getCurrentPage(  ) throw (RuntimeException)
433     {
434         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
435         ::osl::MutexGuard aGuard( m_aMutex );
436 
437         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
438         ENSURE_OR_RETURN( pWizardImpl, "Wizard::getCurrentPage: invalid dialog implementation!", Reference< XWizardPage >() );
439 
440         return pWizardImpl->getCurrentWizardPage();
441     }
442 
443     //------------------------------------------------------------------------------------------------------------------
444     void SAL_CALL Wizard::activatePath( ::sal_Int16 i_PathIndex, ::sal_Bool i_Final ) throw (NoSuchElementException, InvalidStateException, RuntimeException)
445     {
446         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
447         ::osl::MutexGuard aGuard( m_aMutex );
448 
449         if ( ( i_PathIndex < 0 ) || ( i_PathIndex >= m_aWizardSteps.getLength() ) )
450             throw NoSuchElementException( ::rtl::OUString(), *this );
451 
452         WizardShell* pWizardImpl = dynamic_cast< WizardShell* >( m_pDialog );
453         ENSURE_OR_RETURN_VOID( pWizardImpl, "Wizard::activatePath: invalid dialog implementation!" );
454 
455         pWizardImpl->activatePath( i_PathIndex, i_Final );
456     }
457 
458     //------------------------------------------------------------------------------------------------------------------
459     void SAL_CALL Wizard::setTitle( const ::rtl::OUString& i_Title ) throw (RuntimeException)
460     {
461         // simply disambiguate
462         Wizard_Base::OGenericUnoDialog::setTitle( i_Title );
463     }
464 
465     //------------------------------------------------------------------------------------------------------------------
466     ::sal_Int16 SAL_CALL Wizard::execute(  ) throw (RuntimeException)
467     {
468         return Wizard_Base::OGenericUnoDialog::execute();
469     }
470 
471 //......................................................................................................................
472 } } // namespace svt::uno
473 //......................................................................................................................
474