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 "wizardshell.hxx"
23 #include <com/sun/star/container/NoSuchElementException.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/beans/XPropertySetInfo.hpp>
26 #include <com/sun/star/uno/XComponentContext.hpp>
27 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
28 #include <com/sun/star/ui/dialogs/XWizard.hpp>
29 #include <com/sun/star/ui/dialogs/XWizardController.hpp>
30 #include <com/sun/star/ui/dialogs/WizardButton.hpp>
31 #include <com/sun/star/util/InvalidStateException.hpp>
33 #include <comphelper/proparrhlp.hxx>
34 #include <cppuhelper/implbase.hxx>
35 #include <svtools/genericunodialog.hxx>
36 #include <toolkit/helper/vclunohelper.hxx>
37 #include <tools/diagnose_ex.h>
38 #include <osl/mutex.hxx>
39 #include <vcl/svapp.hxx>
40 #include <tools/urlobj.hxx>
42 using namespace ::com::sun::star
;
43 using namespace ::svt::uno
;
47 using css::uno::Reference
;
48 using css::uno::XInterface
;
49 using css::uno::UNO_QUERY
;
51 using css::uno::Sequence
;
52 using css::ui::dialogs::XWizard
;
53 using css::beans::XPropertySetInfo
;
54 using css::uno::XComponentContext
;
55 using css::beans::Property
;
56 using css::lang::IllegalArgumentException
;
57 using css::ucb::AlreadyInitializedException
;
58 using css::ui::dialogs::XWizardController
;
59 using css::ui::dialogs::XWizardPage
;
60 using css::container::NoSuchElementException
;
61 using css::util::InvalidStateException
;
62 using css::awt::XWindow
;
64 namespace WizardButton
= css::ui::dialogs::WizardButton
;
66 WizardButtonFlags
lcl_convertWizardButtonToWZB( const sal_Int16 i_nWizardButton
)
68 switch ( i_nWizardButton
)
70 case WizardButton::NONE
: return WizardButtonFlags::NONE
;
71 case WizardButton::NEXT
: return WizardButtonFlags::NEXT
;
72 case WizardButton::PREVIOUS
: return WizardButtonFlags::PREVIOUS
;
73 case WizardButton::FINISH
: return WizardButtonFlags::FINISH
;
74 case WizardButton::CANCEL
: return WizardButtonFlags::CANCEL
;
75 case WizardButton::HELP
: return WizardButtonFlags::HELP
;
77 OSL_FAIL( "lcl_convertWizardButtonToWZB: invalid WizardButton constant!" );
78 return WizardButtonFlags::NONE
;
81 typedef ::cppu::ImplInheritanceHelper
< ::svt::OGenericUnoDialog
82 , ui::dialogs::XWizard
85 typedef ::comphelper::OPropertyArrayUsageHelper
< Wizard
> Wizard_PBase
;
86 class Wizard
: public Wizard_Base
90 explicit Wizard( const css::uno::Reference
< css::uno::XComponentContext
>& i_rContext
);
93 virtual OUString SAL_CALL
getImplementationName() override
;
94 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
96 // beans::XPropertySet
97 virtual css::uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
getPropertySetInfo() override
;
98 virtual ::cppu::IPropertyArrayHelper
& SAL_CALL
getInfoHelper() override
;
100 // OPropertyArrayUsageHelper
101 virtual ::cppu::IPropertyArrayHelper
* createArrayHelper( ) const override
;
103 // ui::dialogs::XWizard
104 virtual OUString SAL_CALL
getHelpURL() override
;
105 virtual void SAL_CALL
setHelpURL( const OUString
& _helpurl
) override
;
106 virtual css::uno::Reference
< awt::XWindow
> SAL_CALL
getDialogWindow() override
;
107 virtual css::uno::Reference
< ui::dialogs::XWizardPage
> SAL_CALL
getCurrentPage( ) override
;
108 virtual void SAL_CALL
enableButton( ::sal_Int16 WizardButton
, sal_Bool Enable
) override
;
109 virtual void SAL_CALL
setDefaultButton( ::sal_Int16 WizardButton
) override
;
110 virtual sal_Bool SAL_CALL
travelNext( ) override
;
111 virtual sal_Bool SAL_CALL
travelPrevious( ) override
;
112 virtual void SAL_CALL
enablePage( ::sal_Int16 PageID
, sal_Bool Enable
) override
;
113 virtual void SAL_CALL
updateTravelUI( ) override
;
114 virtual sal_Bool SAL_CALL
advanceTo( ::sal_Int16 PageId
) override
;
115 virtual sal_Bool SAL_CALL
goBackTo( ::sal_Int16 PageId
) override
;
116 virtual void SAL_CALL
activatePath( ::sal_Int16 PathIndex
, sal_Bool Final
) override
;
118 // ui::dialogs::XExecutableDialog
119 virtual void SAL_CALL
setTitle( const OUString
& aTitle
) override
;
120 virtual ::sal_Int16 SAL_CALL
execute( ) override
;
122 // lang::XInitialization
123 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
) override
;
126 virtual ~Wizard() override
;
129 virtual std::unique_ptr
<weld::DialogController
> createDialog(const css::uno::Reference
<css::awt::XWindow
>& rParent
) override
;
132 css::uno::Sequence
< css::uno::Sequence
< sal_Int16
> > m_aWizardSteps
;
133 css::uno::Reference
< ui::dialogs::XWizardController
> m_xController
;
137 Wizard::Wizard( const Reference
< XComponentContext
>& _rxContext
)
138 :Wizard_Base( _rxContext
)
142 OUString
lcl_getHelpURL( const OString
& sHelpId
)
144 OUStringBuffer aBuffer
;
146 OStringToOUString( sHelpId
, RTL_TEXTENCODING_UTF8
) );
147 INetURLObject
aHID( aTmp
);
148 if ( aHID
.GetProtocol() == INetProtocol::NotValid
)
149 aBuffer
.append( INET_HID_SCHEME
);
150 aBuffer
.append( aTmp
);
151 return aBuffer
.makeStringAndClear();
158 ::osl::MutexGuard
aGuard( m_aMutex
);
161 m_sHelpURL
= lcl_getHelpURL(m_xDialog
->get_help_id());
167 void lcl_checkPaths( const Sequence
< Sequence
< sal_Int16
> >& i_rPaths
, const Reference
< XInterface
>& i_rContext
)
169 // need at least one path
170 if ( !i_rPaths
.hasElements() )
171 throw IllegalArgumentException( OUString(), i_rContext
, 2 );
173 // each path must be of length 1, at least
175 for ( const Sequence
< sal_Int16
>& rPath
: i_rPaths
)
177 if ( !rPath
.hasElements() )
178 throw IllegalArgumentException( OUString(), i_rContext
, 2 );
180 // page IDs must be in ascending order
181 auto pPageId
= std::adjacent_find(rPath
.begin(), rPath
.end(), std::greater_equal
<sal_Int16
>());
182 if (pPageId
!= rPath
.end())
184 throw IllegalArgumentException(
185 "Path " + OUString::number(i
)
186 + ": invalid page ID sequence - each page ID must be greater than the previous one.",
192 // if we have one path, that's okay
193 if ( i_rPaths
.getLength() == 1 )
196 // if we have multiple paths, they must start with the same page id
197 const sal_Int16 nFirstPageId
= i_rPaths
[0][0];
198 if (std::any_of(i_rPaths
.begin(), i_rPaths
.end(),
199 [nFirstPageId
](const Sequence
< sal_Int16
>& rPath
) { return rPath
[0] != nFirstPageId
; }))
200 throw IllegalArgumentException(
201 "All paths must start with the same page id.",
205 void SAL_CALL
Wizard::initialize( const Sequence
< Any
>& i_Arguments
)
207 ::osl::MutexGuard
aGuard( m_aMutex
);
208 if ( m_bInitialized
)
209 throw AlreadyInitializedException( OUString(), *this );
211 if ( i_Arguments
.getLength() != 2 )
212 throw IllegalArgumentException( OUString(), *this, -1 );
214 // the second argument must be a XWizardController, for each constructor
215 m_xController
.set( i_Arguments
[1], UNO_QUERY
);
216 if ( !m_xController
.is() )
217 throw IllegalArgumentException( OUString(), *this, 2 );
219 // the first arg is either a single path (short[]), or multiple paths (short[][])
220 Sequence
< sal_Int16
> aSinglePath
;
221 i_Arguments
[0] >>= aSinglePath
;
222 Sequence
< Sequence
< sal_Int16
> > aMultiplePaths
;
223 i_Arguments
[0] >>= aMultiplePaths
;
225 if ( !aMultiplePaths
.hasElements() )
227 aMultiplePaths
.realloc(1);
228 aMultiplePaths
[0] = aSinglePath
;
230 lcl_checkPaths( aMultiplePaths
, *this );
231 // if we survived this, the paths are valid, and we're done here ...
232 m_aWizardSteps
= aMultiplePaths
;
234 m_bInitialized
= true;
237 OString
lcl_getHelpId( const OUString
& _rHelpURL
)
239 INetURLObject
aHID( _rHelpURL
);
240 if ( aHID
.GetProtocol() == INetProtocol::Hid
)
241 return OUStringToOString( aHID
.GetURLPath(), RTL_TEXTENCODING_UTF8
);
243 return OUStringToOString( _rHelpURL
, RTL_TEXTENCODING_UTF8
);
246 std::unique_ptr
<weld::DialogController
> Wizard::createDialog(const css::uno::Reference
<css::awt::XWindow
>& rParent
)
248 auto xDialog
= std::make_unique
<WizardShell
>(Application::GetFrameWeld(rParent
), m_xController
, m_aWizardSteps
);
249 xDialog
->set_help_id(lcl_getHelpId(m_sHelpURL
));
250 xDialog
->setTitleBase( m_sTitle
);
254 OUString SAL_CALL
Wizard::getImplementationName()
256 return "com.sun.star.comp.svtools.uno.Wizard";
259 Sequence
< OUString
> SAL_CALL
Wizard::getSupportedServiceNames()
261 return { "com.sun.star.ui.dialogs.Wizard" };
264 Reference
< XPropertySetInfo
> SAL_CALL
Wizard::getPropertySetInfo()
266 return createPropertySetInfo( getInfoHelper() );
269 ::cppu::IPropertyArrayHelper
& SAL_CALL
Wizard::getInfoHelper()
271 return *getArrayHelper();
274 ::cppu::IPropertyArrayHelper
* Wizard::createArrayHelper( ) const
276 Sequence
< Property
> aProps
;
277 describeProperties( aProps
);
278 return new ::cppu::OPropertyArrayHelper( aProps
);
281 OUString SAL_CALL
Wizard::getHelpURL()
283 SolarMutexGuard aSolarGuard
;
284 ::osl::MutexGuard
aGuard( m_aMutex
);
289 return lcl_getHelpURL(m_xDialog
->get_help_id());
292 void SAL_CALL
Wizard::setHelpURL( const OUString
& i_HelpURL
)
294 SolarMutexGuard aSolarGuard
;
295 ::osl::MutexGuard
aGuard( m_aMutex
);
298 m_sHelpURL
= i_HelpURL
;
300 m_xDialog
->set_help_id(lcl_getHelpId(i_HelpURL
));
303 Reference
< XWindow
> SAL_CALL
Wizard::getDialogWindow()
305 SolarMutexGuard aSolarGuard
;
306 ::osl::MutexGuard
aGuard( m_aMutex
);
308 ENSURE_OR_RETURN( m_xDialog
, "Wizard::getDialogWindow: illegal call (execution did not start, yet)!", nullptr );
309 return m_xDialog
->getDialog()->GetXWindow();
312 void SAL_CALL
Wizard::enableButton( ::sal_Int16 i_WizardButton
, sal_Bool i_Enable
)
314 SolarMutexGuard aSolarGuard
;
315 ::osl::MutexGuard
aGuard( m_aMutex
);
317 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
318 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::enableButtons: invalid dialog implementation!" );
320 pWizardImpl
->enableButtons( lcl_convertWizardButtonToWZB( i_WizardButton
), i_Enable
);
323 void SAL_CALL
Wizard::setDefaultButton( ::sal_Int16 i_WizardButton
)
325 SolarMutexGuard aSolarGuard
;
326 ::osl::MutexGuard
aGuard( m_aMutex
);
328 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
329 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::setDefaultButton: invalid dialog implementation!" );
331 pWizardImpl
->defaultButton( lcl_convertWizardButtonToWZB( i_WizardButton
) );
334 sal_Bool SAL_CALL
Wizard::travelNext( )
336 SolarMutexGuard aSolarGuard
;
337 ::osl::MutexGuard
aGuard( m_aMutex
);
339 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
340 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::travelNext: invalid dialog implementation!" );
342 return pWizardImpl
->travelNext();
345 sal_Bool SAL_CALL
Wizard::travelPrevious( )
347 SolarMutexGuard aSolarGuard
;
348 ::osl::MutexGuard
aGuard( m_aMutex
);
350 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
351 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::travelPrevious: invalid dialog implementation!" );
353 return pWizardImpl
->travelPrevious();
356 void SAL_CALL
Wizard::enablePage( ::sal_Int16 i_PageID
, sal_Bool i_Enable
)
358 SolarMutexGuard aSolarGuard
;
359 ::osl::MutexGuard
aGuard( m_aMutex
);
361 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
362 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::enablePage: invalid dialog implementation!" );
364 if ( !pWizardImpl
->knowsPage( i_PageID
) )
365 throw NoSuchElementException( OUString(), *this );
367 if ( i_PageID
== pWizardImpl
->getCurrentPage() )
368 throw InvalidStateException( OUString(), *this );
370 pWizardImpl
->enablePage( i_PageID
, i_Enable
);
373 void SAL_CALL
Wizard::updateTravelUI( )
375 SolarMutexGuard aSolarGuard
;
376 ::osl::MutexGuard
aGuard( m_aMutex
);
378 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
379 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::updateTravelUI: invalid dialog implementation!" );
381 pWizardImpl
->updateTravelUI();
384 sal_Bool SAL_CALL
Wizard::advanceTo( ::sal_Int16 i_PageId
)
386 SolarMutexGuard aSolarGuard
;
387 ::osl::MutexGuard
aGuard( m_aMutex
);
389 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
390 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::advanceTo: invalid dialog implementation!" );
392 return pWizardImpl
->advanceTo( i_PageId
);
395 sal_Bool SAL_CALL
Wizard::goBackTo( ::sal_Int16 i_PageId
)
397 SolarMutexGuard aSolarGuard
;
398 ::osl::MutexGuard
aGuard( m_aMutex
);
400 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
401 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::goBackTo: invalid dialog implementation!" );
403 return pWizardImpl
->goBackTo( i_PageId
);
406 Reference
< XWizardPage
> SAL_CALL
Wizard::getCurrentPage( )
408 SolarMutexGuard aSolarGuard
;
409 ::osl::MutexGuard
aGuard( m_aMutex
);
411 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
412 ENSURE_OR_RETURN( pWizardImpl
, "Wizard::getCurrentPage: invalid dialog implementation!", Reference
< XWizardPage
>() );
414 return pWizardImpl
->getCurrentWizardPage();
417 void SAL_CALL
Wizard::activatePath( ::sal_Int16 i_PathIndex
, sal_Bool i_Final
)
419 SolarMutexGuard aSolarGuard
;
420 ::osl::MutexGuard
aGuard( m_aMutex
);
422 if ( ( i_PathIndex
< 0 ) || ( i_PathIndex
>= m_aWizardSteps
.getLength() ) )
423 throw NoSuchElementException( OUString(), *this );
425 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
426 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::activatePath: invalid dialog implementation!" );
428 pWizardImpl
->activatePath( i_PathIndex
, i_Final
);
431 void SAL_CALL
Wizard::setTitle( const OUString
& i_Title
)
433 // simply disambiguate
434 Wizard_Base::OGenericUnoDialog::setTitle( i_Title
);
437 ::sal_Int16 SAL_CALL
Wizard::execute( )
439 return Wizard_Base::OGenericUnoDialog::execute();
443 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
444 com_sun_star_comp_svtools_uno_Wizard_get_implementation(
445 css::uno::XComponentContext
*context
,
446 css::uno::Sequence
<css::uno::Any
> const &)
448 return cppu::acquire(new Wizard(context
));
451 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */