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