/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: */ |