Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/vcl/wizardmachine.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
#pragma once
20
21
#include <memory>
22
#include <vcl/dllapi.h>
23
#include <vcl/builderpage.hxx>
24
#include <vcl/vclenum.hxx>
25
#include <vcl/weld/AssistantController.hxx>
26
#include <vcl/weld/Button.hxx>
27
#include <vcl/weld/DialogController.hxx>
28
29
struct WizPageData;
30
31
// wizard states
32
0
#define WZS_INVALID_STATE (::vcl::WizardTypes::WizardState(-1))
33
34
namespace vcl
35
{
36
    //= WizardTypes
37
    namespace WizardTypes
38
    {
39
        typedef sal_Int16  WizardState;
40
        enum CommitPageReason
41
        {
42
            eTravelForward,         // traveling forward (maybe with skipping pages)
43
            eTravelBackward,        // traveling backward (maybe with skipping pages)
44
            eFinish,                // the wizard is about to be finished
45
            eValidate               // the data should be validated only, no traveling will happen
46
        };
47
    };
48
49
    class SAL_NO_VTABLE SAL_LOPLUGIN_ANNOTATE("crosscast") IWizardPageController
50
    {
51
    public:
52
53
        // This methods  behave somewhat different than ActivatePage/DeactivatePage
54
        // The latter are handled by the base class itself whenever changing the pages is in the offing,
55
        // i.e., when it's already decided which page is the next.
56
        // We may have situations where the next page depends on the state of the current, which needs
57
        // to be committed for this.
58
        // So initializePage and commitPage are designated to initializing/committing data on the page.
59
        virtual void        initializePage() = 0;
60
        virtual bool        commitPage( WizardTypes::CommitPageReason _eReason ) = 0;
61
62
        /** determines whether or not it is allowed to advance to a next page
63
64
            You should make this dependent on the current state of the page only, not on
65
            states on other pages of the whole dialog.
66
67
            The default implementation always returns <TRUE/>.
68
        */
69
        virtual bool        canAdvance() const = 0;
70
71
    protected:
72
0
        ~IWizardPageController() {}
73
    };
74
75
    //= OWizardPage
76
    class VCL_DLLPUBLIC OWizardPage : public BuilderPage, public IWizardPageController
77
    {
78
    public:
79
        OWizardPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& rID);
80
        virtual ~OWizardPage() override;
81
82
        // IWizardPageController overridables
83
        virtual void        initializePage() override;
84
        virtual bool        commitPage( WizardTypes::CommitPageReason _eReason ) override;
85
        virtual bool        canAdvance() const override;
86
87
    protected:
88
        // BuilderPage overridables
89
        virtual void        Activate() override;
90
91
        /** updates the travel-related UI elements of the OWizardMachine we live in (if any)
92
93
            If the parent of the tab page is an OWizardMachine, then updateTravelUI at this instance
94
            is called. Otherwise, nothing happens.
95
        */
96
        void                updateDialogTravelUI();
97
    };
98
99
    //= OWizardMachine
100
    struct WizardMachineImplData;
101
    /** implements some kind of finite automata, where the states of the automata exactly correlate
102
        with tab pages.
103
104
        That is, the machine can have up to n states, where at each point in time exactly one state is
105
        the current one. A state being current is represented as one of n tab pages being displayed
106
        currently.
107
108
        The class handles the UI for traveling between the states (e.g. it administrates the <em>Next</em> and
109
        <em>Previous</em> buttons which you usually find in a wizard.
110
111
        Derived classes have to implement the travel logic by overriding <member>determineNextState</member>,
112
        which has to determine the state which follows the current state. Since this may depend
113
        on the actual data presented in the wizard (e.g. checkboxes checked, or something like this),
114
        they can implement non-linear traveling this way.
115
    */
116
    class VCL_DLLPUBLIC WizardMachine : public weld::AssistantController
117
    {
118
    protected:
119
        BuilderPage* m_pCurTabPage;
120
    private:
121
        WizardTypes::WizardState m_nCurState;
122
        WizPageData* m_pFirstPage;
123
124
    protected:
125
        std::unique_ptr<weld::Button> m_xFinish;
126
        std::unique_ptr<weld::Button> m_xCancel;
127
        std::unique_ptr<weld::Button> m_xNextPage;
128
        std::unique_ptr<weld::Button> m_xPrevPage;
129
        std::unique_ptr<weld::Button> m_xHelp;
130
131
    private:
132
        // hold members in this structure to allow keeping compatible when members are added
133
        std::unique_ptr<WizardMachineImplData>  m_pImpl;
134
135
    public:
136
        WizardMachine(weld::Window* _pParent, WizardButtonFlags _nButtonFlags );
137
        virtual ~WizardMachine() override;
138
139
        bool Finish(short nResult = RET_CANCEL);
140
        bool ShowPage(WizardTypes::WizardState nState);
141
142
        bool ShowNextPage();
143
        bool ShowPrevPage();
144
145
        void                AddPage( std::unique_ptr<BuilderPage> xPage );
146
        SAL_DLLPRIVATE void RemovePage( const BuilderPage* pPage );
147
        SAL_DLLPRIVATE void SetPage( WizardTypes::WizardState nLevel, std::unique_ptr<BuilderPage> xPage );
148
        BuilderPage*        GetPage( WizardTypes::WizardState eState ) const;
149
150
        /// enable (or disable) buttons
151
        void                enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable);
152
        /// set the default style for a button
153
        void                defaultButton(WizardButtonFlags _nWizardButtonFlags);
154
        /// set the default style for a button
155
        void                defaultButton(weld::Button* _pNewDefButton);
156
157
        /// set the base of the title to use - the title of the current page is appended
158
        void                setTitleBase(const OUString& _rTitleBase);
159
160
        /// determines whether there is a next state to which we can advance
161
        virtual bool        canAdvance() const;
162
163
        /** updates the user interface which deals with traveling in the wizard
164
165
            The default implementation simply checks whether both the current page and the wizard
166
            itself allow to advance to the next state (<code>canAdvance</code>), and enables the "Next"
167
            button if and only if this is the case.
168
        */
169
        virtual void        updateTravelUI();
170
171
    protected:
172
        virtual void        ActivatePage();
173
        virtual bool        DeactivatePage();
174
175
        // our own overridables
176
177
        /// to override to create new pages
178
        virtual std::unique_ptr<BuilderPage> createPage(WizardTypes::WizardState _nState) = 0;
179
180
        /// will be called when a new page is about to be displayed
181
        virtual void        enterState(WizardTypes::WizardState _nState);
182
183
        /** will be called when the current state is about to be left for the given reason
184
185
            The base implementation in this class will simply call <member>OWizardPage::commitPage</member>
186
            for the current page, and return whatever this call returns.
187
188
            @param _eReason
189
                The reason why the state is to be left.
190
            @return
191
                <TRUE/> if and only if the page is allowed to be left
192
        */
193
        virtual bool        prepareLeaveCurrentState( WizardTypes::CommitPageReason eReason );
194
195
        /** will be called when the given state is left
196
197
            This is the very last possibility for derived classes to veto the deactivation
198
            of a page.
199
200
            @todo Normally, we would not need the return value here - derived classes now have
201
            the possibility to veto page deactivations in <member>prepareLeaveCurrentState</member>. However,
202
            changing this return type is too incompatible at the moment ...
203
204
            @return
205
                <TRUE/> if and only if the page is allowed to be left
206
        */
207
        virtual bool        leaveState(WizardTypes::WizardState nState);
208
209
        /** determine the next state to travel from the given one
210
211
            The default behaviour is linear traveling, overwrite this to change it
212
213
            Return WZS_INVALID_STATE to prevent traveling.
214
        */
215
        virtual WizardTypes::WizardState determineNextState(WizardTypes::WizardState nCurrentState) const;
216
217
        /** called when the finish button is pressed
218
            <p>By default, only the base class' Finish method (which is not virtual) is called</p>
219
        */
220
        virtual bool        onFinish();
221
222
        /// travel to the next state
223
        bool                travelNext();
224
225
        /// travel to the previous state
226
        bool                travelPrevious();
227
228
        /** enables the automatic enabled/disabled state of the "Next" button
229
230
            If this is <TRUE/>, then upon entering a new state, the "Next" button will automatically be
231
            enabled if and only if determineNextState does not return WZS_INVALID_STATE.
232
        */
233
        void                enableAutomaticNextButtonState();
234
        SAL_DLLPRIVATE bool isAutomaticNextButtonStateEnabled() const;
235
236
        /** removes a page from the history. Should be called when the page is being disabled
237
        */
238
        SAL_DLLPRIVATE void removePageFromHistory(WizardTypes::WizardState nToRemove);
239
240
        /** skip a state
241
242
            The method behaves as if from the current state, <arg>_nSteps</arg> <method>travelNext</method>s were
243
            called, but without actually creating or displaying the \EDntermediate pages. Only the
244
            (<arg>_nSteps</arg> + 1)th page is created.
245
246
            The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them.
247
248
            A very essential precondition for using this method is that your <method>determineNextState</method>
249
            method is able to determine the next state without actually having the page of the current state.
250
251
            @see skipUntil
252
            @see skipBackwardUntil
253
        */
254
        void                    skip();
255
256
        /** skips one or more states, until a given state is reached
257
258
            The method behaves as if from the current state, <method>travelNext</method>s were called
259
            successively, until <arg>_nTargetState</arg> is reached, but without actually creating or
260
            displaying the \EDntermediate pages.
261
262
            The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them.
263
264
            @return
265
                <TRUE/> if and only if traveling was successful
266
267
            @see skip
268
            @see skipBackwardUntil
269
        */
270
        bool                    skipUntil(WizardTypes::WizardState nTargetState);
271
272
        /** moves back one or more states, until a given state is reached
273
274
            This method allows traveling backwards more than one state without actually showing the intermediate
275
            states.
276
277
            For instance, if you want to travel two steps backward at a time, you could used
278
            two travelPrevious calls, but this would <em>show</em> both pages, which is not necessary,
279
            since you're interested in the target page only. Using <member>skipBackwardUntil</member> relieves
280
            you of this.
281
282
            @return
283
                <TRUE/> if and only if traveling was successful
284
285
            @see skipUntil
286
            @see skip
287
        */
288
        bool                    skipBackwardUntil(WizardTypes::WizardState nTargetState);
289
290
        /** returns the current state of the machine
291
292
            Vulgo, this is the identifier of the current tab page :)
293
        */
294
0
        WizardTypes::WizardState getCurrentState() const { return m_nCurState; }
295
296
        virtual IWizardPageController* getPageController(BuilderPage* pCurrentPage) const;
297
298
        /** retrieves a copy of the state history, i.e. all states we already visited
299
        */
300
        SAL_DLLPRIVATE void getStateHistory(std::vector<WizardTypes::WizardState>& out_rHistory);
301
302
        virtual OUString         getPageIdentForState(WizardTypes::WizardState nState) const;
303
        virtual WizardTypes::WizardState getStateFromPageIdent(const OUString& rIdent) const;
304
305
    public:
306
        class AccessGuard
307
        {
308
            friend class WizardTravelSuspension;
309
        private:
310
0
            AccessGuard() { }
311
        };
312
313
        SAL_DLLPRIVATE void    suspendTraveling( AccessGuard );
314
        SAL_DLLPRIVATE void    resumeTraveling( AccessGuard );
315
        SAL_DLLPRIVATE bool    isTravelingSuspended() const;
316
317
    protected:
318
        BuilderPage* GetOrCreatePage(const WizardTypes::WizardState i_nState);
319
320
    private:
321
        DECL_DLLPRIVATE_LINK(OnNextPage, weld::Button&, void);
322
        DECL_DLLPRIVATE_LINK(OnPrevPage, weld::Button&, void);
323
        DECL_DLLPRIVATE_LINK(OnFinish, weld::Button&, void);
324
        DECL_DLLPRIVATE_LINK(OnCancel, weld::Button&, void);
325
326
        SAL_DLLPRIVATE void     implUpdateTitle();
327
        SAL_DLLPRIVATE void     implConstruct( const WizardButtonFlags _nButtonFlags );
328
    };
329
330
331
    /// helper class to temporarily suspend any traveling in the wizard
332
    class WizardTravelSuspension
333
    {
334
    public:
335
        WizardTravelSuspension(WizardMachine& rWizard)
336
            : m_pWizard(&rWizard)
337
0
        {
338
0
            m_pWizard->suspendTraveling(WizardMachine::AccessGuard());
339
0
        }
340
341
        ~WizardTravelSuspension()
342
0
        {
343
0
            m_pWizard->resumeTraveling(WizardMachine::AccessGuard());
344
0
        }
345
346
    private:
347
        WizardMachine* m_pWizard;
348
    };
349
}   // namespace vcl
350
351
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */