cid#1606940 Check of thread-shared field evades lock acquisition
[LibreOffice.git] / svtools / source / uno / wizard / unowizard.cxx
blob4b2a9249f90ed98c4ee72fe9d7b94268f78b0365
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
47 namespace {
49 using css::uno::Reference;
50 using css::uno::XInterface;
51 using css::uno::UNO_QUERY;
52 using css::uno::Any;
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
85 > Wizard_Base;
86 class Wizard;
87 typedef ::comphelper::OPropertyArrayUsageHelper< Wizard > Wizard_PBase;
88 class Wizard : public Wizard_Base
89 , public Wizard_PBase
91 public:
92 explicit Wizard( const css::uno::Reference< css::uno::XComponentContext >& i_rContext );
94 // lang::XServiceInfo
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;
127 protected:
128 virtual ~Wizard() override;
130 protected:
131 virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
133 private:
134 css::uno::Sequence< css::uno::Sequence< sal_Int16 > > m_aWizardSteps;
135 css::uno::Reference< ui::dialogs::XWizardController > m_xController;
136 OUString m_sHelpURL;
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();
154 Wizard::~Wizard()
156 if (m_xDialog)
158 ::osl::MutexGuard aGuard( m_aMutex );
159 if (m_xDialog)
161 m_sHelpURL = lcl_getHelpURL(m_xDialog->get_help_id());
162 destroyDialog();
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
174 sal_Int32 i = 0;
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.",
187 i_rContext, 2 );
189 ++i;
192 // if we have one path, that's okay
193 if ( i_rPaths.getLength() == 1 )
194 return;
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,
202 i_rContext, 2 );
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();
241 else
242 return _rHelpURL;
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 );
250 return xDialog;
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 );
285 if (!m_xDialog)
286 return m_sHelpURL;
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 );
296 if (!m_xDialog)
297 m_sHelpURL = i_HelpURL;
298 else
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: */