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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include "wizardshell.hxx"
26 #include <com/sun/star/container/NoSuchElementException.hpp>
27 #include <com/sun/star/beans/XPropertySetInfo.hpp>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
30 #include <com/sun/star/ui/dialogs/XWizard.hpp>
31 #include <com/sun/star/ui/dialogs/XWizardController.hpp>
32 #include <com/sun/star/ui/dialogs/WizardButton.hpp>
33 #include <com/sun/star/util/InvalidStateException.hpp>
35 #include <comphelper/proparrhlp.hxx>
36 #include <cppuhelper/implbase.hxx>
37 #include <svtools/genericunodialog.hxx>
38 #include <toolkit/helper/vclunohelper.hxx>
39 #include <comphelper/diagnose_ex.hxx>
40 #include <osl/mutex.hxx>
41 #include <vcl/svapp.hxx>
42 #include <tools/urlobj.hxx>
44 using namespace ::com::sun::star
;
45 using namespace ::svt::uno
;
49 using css::uno::Reference
;
50 using css::uno::XInterface
;
51 using css::uno::UNO_QUERY
;
53 using css::uno::Sequence
;
54 using css::ui::dialogs::XWizard
;
55 using css::beans::XPropertySetInfo
;
56 using css::uno::XComponentContext
;
57 using css::beans::Property
;
58 using css::lang::IllegalArgumentException
;
59 using css::ucb::AlreadyInitializedException
;
60 using css::ui::dialogs::XWizardController
;
61 using css::ui::dialogs::XWizardPage
;
62 using css::container::NoSuchElementException
;
63 using css::util::InvalidStateException
;
64 using css::awt::XWindow
;
66 namespace WizardButton
= css::ui::dialogs::WizardButton
;
68 WizardButtonFlags
lcl_convertWizardButtonToWZB( const sal_Int16 i_nWizardButton
)
70 switch ( i_nWizardButton
)
72 case WizardButton::NONE
: return WizardButtonFlags::NONE
;
73 case WizardButton::NEXT
: return WizardButtonFlags::NEXT
;
74 case WizardButton::PREVIOUS
: return WizardButtonFlags::PREVIOUS
;
75 case WizardButton::FINISH
: return WizardButtonFlags::FINISH
;
76 case WizardButton::CANCEL
: return WizardButtonFlags::CANCEL
;
77 case WizardButton::HELP
: return WizardButtonFlags::HELP
;
79 OSL_FAIL( "lcl_convertWizardButtonToWZB: invalid WizardButton constant!" );
80 return WizardButtonFlags::NONE
;
83 typedef ::cppu::ImplInheritanceHelper
< ::svt::OGenericUnoDialog
84 , ui::dialogs::XWizard
87 typedef ::comphelper::OPropertyArrayUsageHelper
< Wizard
> Wizard_PBase
;
88 class Wizard
: public Wizard_Base
92 explicit Wizard( const css::uno::Reference
< css::uno::XComponentContext
>& i_rContext
);
95 virtual OUString SAL_CALL
getImplementationName() override
;
96 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
98 // beans::XPropertySet
99 virtual css::uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
getPropertySetInfo() override
;
100 virtual ::cppu::IPropertyArrayHelper
& SAL_CALL
getInfoHelper() override
;
102 // OPropertyArrayUsageHelper
103 virtual ::cppu::IPropertyArrayHelper
* createArrayHelper( ) const override
;
105 // ui::dialogs::XWizard
106 virtual OUString SAL_CALL
getHelpURL() override
;
107 virtual void SAL_CALL
setHelpURL( const OUString
& _helpurl
) override
;
108 virtual css::uno::Reference
< awt::XWindow
> SAL_CALL
getDialogWindow() override
;
109 virtual css::uno::Reference
< ui::dialogs::XWizardPage
> SAL_CALL
getCurrentPage( ) override
;
110 virtual void SAL_CALL
enableButton( ::sal_Int16 WizardButton
, sal_Bool Enable
) override
;
111 virtual void SAL_CALL
setDefaultButton( ::sal_Int16 WizardButton
) override
;
112 virtual sal_Bool SAL_CALL
travelNext( ) override
;
113 virtual sal_Bool SAL_CALL
travelPrevious( ) override
;
114 virtual void SAL_CALL
enablePage( ::sal_Int16 PageID
, sal_Bool Enable
) override
;
115 virtual void SAL_CALL
updateTravelUI( ) override
;
116 virtual sal_Bool SAL_CALL
advanceTo( ::sal_Int16 PageId
) override
;
117 virtual sal_Bool SAL_CALL
goBackTo( ::sal_Int16 PageId
) override
;
118 virtual void SAL_CALL
activatePath( ::sal_Int16 PathIndex
, sal_Bool Final
) override
;
120 // ui::dialogs::XExecutableDialog
121 virtual void SAL_CALL
setTitle( const OUString
& aTitle
) override
;
122 virtual ::sal_Int16 SAL_CALL
execute( ) override
;
124 // lang::XInitialization
125 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
) override
;
128 virtual ~Wizard() override
;
131 virtual std::unique_ptr
<weld::DialogController
> createDialog(const css::uno::Reference
<css::awt::XWindow
>& rParent
) override
;
134 css::uno::Sequence
< css::uno::Sequence
< sal_Int16
> > m_aWizardSteps
;
135 css::uno::Reference
< ui::dialogs::XWizardController
> m_xController
;
139 Wizard::Wizard( const Reference
< XComponentContext
>& _rxContext
)
140 :Wizard_Base( _rxContext
)
144 OUString
lcl_getHelpURL( std::u16string_view sHelpId
)
146 OUStringBuffer aBuffer
;
147 INetURLObject
aHID(sHelpId
);
148 if ( aHID
.GetProtocol() == INetProtocol::NotValid
)
149 aBuffer
.append( INET_HID_SCHEME
);
150 aBuffer
.append(sHelpId
);
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 u
"All paths must start with the same page id."_ustr
,
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
= { aSinglePath
};
229 lcl_checkPaths( aMultiplePaths
, *this );
230 // if we survived this, the paths are valid, and we're done here ...
231 m_aWizardSteps
= std::move(aMultiplePaths
);
233 m_bInitialized
= true;
236 OUString
lcl_getHelpId( const OUString
& _rHelpURL
)
238 INetURLObject
aHID( _rHelpURL
);
239 if ( aHID
.GetProtocol() == INetProtocol::Hid
)
240 return aHID
.GetURLPath();
245 std::unique_ptr
<weld::DialogController
> Wizard::createDialog(const css::uno::Reference
<css::awt::XWindow
>& rParent
)
247 auto xDialog
= std::make_unique
<WizardShell
>(Application::GetFrameWeld(rParent
), m_xController
, m_aWizardSteps
);
248 xDialog
->set_help_id(lcl_getHelpId(m_sHelpURL
));
249 xDialog
->setTitleBase( m_sTitle
);
253 OUString SAL_CALL
Wizard::getImplementationName()
255 return u
"com.sun.star.comp.svtools.uno.Wizard"_ustr
;
258 Sequence
< OUString
> SAL_CALL
Wizard::getSupportedServiceNames()
260 return { u
"com.sun.star.ui.dialogs.Wizard"_ustr
};
263 Reference
< XPropertySetInfo
> SAL_CALL
Wizard::getPropertySetInfo()
265 return createPropertySetInfo( getInfoHelper() );
268 ::cppu::IPropertyArrayHelper
& SAL_CALL
Wizard::getInfoHelper()
270 return *getArrayHelper();
273 ::cppu::IPropertyArrayHelper
* Wizard::createArrayHelper( ) const
275 Sequence
< Property
> aProps
;
276 describeProperties( aProps
);
277 return new ::cppu::OPropertyArrayHelper( aProps
);
280 OUString SAL_CALL
Wizard::getHelpURL()
282 SolarMutexGuard aSolarGuard
;
283 ::osl::MutexGuard
aGuard( m_aMutex
);
288 return lcl_getHelpURL(m_xDialog
->get_help_id());
291 void SAL_CALL
Wizard::setHelpURL( const OUString
& i_HelpURL
)
293 SolarMutexGuard aSolarGuard
;
294 ::osl::MutexGuard
aGuard( m_aMutex
);
297 m_sHelpURL
= i_HelpURL
;
299 m_xDialog
->set_help_id(lcl_getHelpId(i_HelpURL
));
302 Reference
< XWindow
> SAL_CALL
Wizard::getDialogWindow()
304 SolarMutexGuard aSolarGuard
;
305 ::osl::MutexGuard
aGuard( m_aMutex
);
307 ENSURE_OR_RETURN( m_xDialog
, "Wizard::getDialogWindow: illegal call (execution did not start, yet)!", nullptr );
308 return m_xDialog
->getDialog()->GetXWindow();
311 void SAL_CALL
Wizard::enableButton( ::sal_Int16 i_WizardButton
, sal_Bool i_Enable
)
313 SolarMutexGuard aSolarGuard
;
314 ::osl::MutexGuard
aGuard( m_aMutex
);
316 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
317 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::enableButtons: invalid dialog implementation!" );
319 pWizardImpl
->enableButtons( lcl_convertWizardButtonToWZB( i_WizardButton
), i_Enable
);
322 void SAL_CALL
Wizard::setDefaultButton( ::sal_Int16 i_WizardButton
)
324 SolarMutexGuard aSolarGuard
;
325 ::osl::MutexGuard
aGuard( m_aMutex
);
327 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
328 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::setDefaultButton: invalid dialog implementation!" );
330 pWizardImpl
->defaultButton( lcl_convertWizardButtonToWZB( i_WizardButton
) );
333 sal_Bool SAL_CALL
Wizard::travelNext( )
335 SolarMutexGuard aSolarGuard
;
336 ::osl::MutexGuard
aGuard( m_aMutex
);
338 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
339 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::travelNext: invalid dialog implementation!" );
341 return pWizardImpl
->travelNext();
344 sal_Bool SAL_CALL
Wizard::travelPrevious( )
346 SolarMutexGuard aSolarGuard
;
347 ::osl::MutexGuard
aGuard( m_aMutex
);
349 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
350 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::travelPrevious: invalid dialog implementation!" );
352 return pWizardImpl
->travelPrevious();
355 void SAL_CALL
Wizard::enablePage( ::sal_Int16 i_PageID
, sal_Bool i_Enable
)
357 SolarMutexGuard aSolarGuard
;
358 ::osl::MutexGuard
aGuard( m_aMutex
);
360 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
361 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::enablePage: invalid dialog implementation!" );
363 if ( !pWizardImpl
->knowsPage( i_PageID
) )
364 throw NoSuchElementException( OUString(), *this );
366 if ( i_PageID
== pWizardImpl
->getCurrentPage() )
367 throw InvalidStateException( OUString(), *this );
369 pWizardImpl
->enablePage( i_PageID
, i_Enable
);
372 void SAL_CALL
Wizard::updateTravelUI( )
374 SolarMutexGuard aSolarGuard
;
375 ::osl::MutexGuard
aGuard( m_aMutex
);
377 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
378 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::updateTravelUI: invalid dialog implementation!" );
380 pWizardImpl
->updateTravelUI();
383 sal_Bool SAL_CALL
Wizard::advanceTo( ::sal_Int16 i_PageId
)
385 SolarMutexGuard aSolarGuard
;
386 ::osl::MutexGuard
aGuard( m_aMutex
);
388 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
389 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::advanceTo: invalid dialog implementation!" );
391 return pWizardImpl
->advanceTo( i_PageId
);
394 sal_Bool SAL_CALL
Wizard::goBackTo( ::sal_Int16 i_PageId
)
396 SolarMutexGuard aSolarGuard
;
397 ::osl::MutexGuard
aGuard( m_aMutex
);
399 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
400 ENSURE_OR_RETURN_FALSE( pWizardImpl
, "Wizard::goBackTo: invalid dialog implementation!" );
402 return pWizardImpl
->goBackTo( i_PageId
);
405 Reference
< XWizardPage
> SAL_CALL
Wizard::getCurrentPage( )
407 SolarMutexGuard aSolarGuard
;
408 ::osl::MutexGuard
aGuard( m_aMutex
);
410 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
411 ENSURE_OR_RETURN( pWizardImpl
, "Wizard::getCurrentPage: invalid dialog implementation!", Reference
< XWizardPage
>() );
413 return pWizardImpl
->getCurrentWizardPage();
416 void SAL_CALL
Wizard::activatePath( ::sal_Int16 i_PathIndex
, sal_Bool i_Final
)
418 SolarMutexGuard aSolarGuard
;
419 ::osl::MutexGuard
aGuard( m_aMutex
);
421 if ( ( i_PathIndex
< 0 ) || ( i_PathIndex
>= m_aWizardSteps
.getLength() ) )
422 throw NoSuchElementException( OUString(), *this );
424 WizardShell
* pWizardImpl
= dynamic_cast<WizardShell
*>(m_xDialog
.get());
425 ENSURE_OR_RETURN_VOID( pWizardImpl
, "Wizard::activatePath: invalid dialog implementation!" );
427 pWizardImpl
->activatePath( i_PathIndex
, i_Final
);
430 void SAL_CALL
Wizard::setTitle( const OUString
& i_Title
)
432 // simply disambiguate
433 Wizard_Base::OGenericUnoDialog::setTitle( i_Title
);
436 ::sal_Int16 SAL_CALL
Wizard::execute( )
438 return Wizard_Base::OGenericUnoDialog::execute();
442 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
443 com_sun_star_comp_svtools_uno_Wizard_get_implementation(
444 css::uno::XComponentContext
*context
,
445 css::uno::Sequence
<css::uno::Any
> const &)
447 return cppu::acquire(new Wizard(context
));
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */