Line data Source code
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 : #ifndef INCLUDED_SVTOOLS_WIZARDMACHINE_HXX
20 : #define INCLUDED_SVTOOLS_WIZARDMACHINE_HXX
21 :
22 : #include <svtools/svtdllapi.h>
23 : #include <svtools/wizdlg.hxx>
24 : #include <vcl/button.hxx>
25 : #include <vcl/tabpage.hxx>
26 : #include <o3tl/typed_flags_set.hxx>
27 :
28 : class Bitmap;
29 :
30 : enum class WizardButtonFlags
31 : {
32 : NONE = 0x0000,
33 : NEXT = 0x0001,
34 : PREVIOUS = 0x0002,
35 : FINISH = 0x0004,
36 : CANCEL = 0x0008,
37 : HELP = 0x0010,
38 : };
39 : namespace o3tl
40 : {
41 : template<> struct typed_flags<WizardButtonFlags> : is_typed_flags<WizardButtonFlags, 0x001f> {};
42 : }
43 :
44 : namespace svt
45 : {
46 :
47 :
48 : // wizard states
49 : #define WZS_INVALID_STATE ((WizardState)-1)
50 :
51 :
52 : //= WizardTypes
53 :
54 0 : struct WizardTypes
55 : {
56 : typedef sal_Int16 WizardState;
57 : enum CommitPageReason
58 : {
59 : eTravelForward, // traveling forward (maybe with skipping pages)
60 : eTravelBackward, // traveling backward (maybe with skipping pages)
61 : eFinish, // the wizard is about to be finished
62 : eValidate // the data should be validated only, no traveling wll happen
63 : };
64 : };
65 :
66 0 : class SAL_NO_VTABLE IWizardPageController
67 : {
68 : public:
69 :
70 : // This methods behave somewhat different than ActivatePage/DeactivatePage
71 : // The latter are handled by the base class itself whenever changing the pages is in the offing,
72 : // i.e., when it's already decided which page is the next.
73 : // We may have situations where the next page depends on the state of the current, which needs
74 : // to be committed for this.
75 : // So initializePage and commitPage are designated to initialitzing/committing data on the page.
76 : virtual void initializePage() = 0;
77 : virtual bool commitPage( WizardTypes::CommitPageReason _eReason ) = 0;
78 :
79 : /** determines whether or not it is allowed to advance to a next page
80 :
81 : You should make this dependent on the current state of the page only, not on
82 : states on other pages of the whole dialog.
83 :
84 : The default implementation always returns <TRUE/>.
85 : */
86 : virtual bool canAdvance() const = 0;
87 :
88 : protected:
89 0 : ~IWizardPageController() {}
90 : };
91 :
92 :
93 : //= OWizardPage
94 :
95 : class OWizardMachine;
96 : struct WizardPageImplData;
97 :
98 : class SVT_DLLPUBLIC OWizardPage : public TabPage, public IWizardPageController
99 : {
100 : private:
101 : WizardPageImplData* m_pImpl;
102 :
103 : public:
104 : /** @param _pParent
105 : if the OWizardPage is used in an OWizardMachine, this parameter
106 : must be the OWizardMachine (which is derived from Window)
107 : */
108 : OWizardPage(vcl::Window *pParent, const OString& rID, const OUString& rUIXMLDescription);
109 : virtual ~OWizardPage();
110 : virtual void dispose() SAL_OVERRIDE;
111 :
112 : // IWizardPageController overridables
113 : virtual void initializePage() SAL_OVERRIDE;
114 : virtual bool commitPage( WizardTypes::CommitPageReason _eReason ) SAL_OVERRIDE;
115 : virtual bool canAdvance() const SAL_OVERRIDE;
116 :
117 : protected:
118 : // TabPage overridables
119 : virtual void ActivatePage() SAL_OVERRIDE;
120 :
121 : /** updates the travel-related UI elements of the OWizardMachine we live in (if any)
122 :
123 : If the parent of the tab page is a OWizardMachine, then updateTravelUI at this instance
124 : is called. Otherwise, nothing happens.
125 : */
126 : void updateDialogTravelUI();
127 : };
128 :
129 :
130 : //= OWizardMachine
131 :
132 : struct WizardMachineImplData;
133 : /** implements some kind of finite automata, where the states of the automata exactly correlate
134 : with tab pages.
135 :
136 : That is, the machine can have up to n states, where at each point in time exactly one state is
137 : the current one. A state being current is represented as one of n tab pages being displayed
138 : currently.
139 :
140 : The class handles the UI for traveling between the states (e.g. it administrates the <em>Next</em> and
141 : <em>Previous</em> buttons which you usually find in a wizard.
142 :
143 : Derived classes have to implement the travel logic by overriding <member>determineNextState</member>,
144 : which has to determine the state which follows the current state. Since this may depend
145 : on the actual data presented in the wizard (e.g. checkboxes checked, or something like this),
146 : they can implement non-linear traveling this way.
147 : */
148 :
149 : class SVT_DLLPUBLIC OWizardMachine : public WizardDialog, public WizardTypes
150 : {
151 : private:
152 : // restrict access to some aspects of our base class
153 0 : SVT_DLLPRIVATE void AddPage( TabPage* pPage ) { WizardDialog::AddPage(pPage); }
154 : SVT_DLLPRIVATE void RemovePage( TabPage* pPage ) { WizardDialog::RemovePage(pPage); }
155 0 : SVT_DLLPRIVATE void SetPage( sal_uInt16 nLevel, TabPage* pPage ) { WizardDialog::SetPage(nLevel, pPage); }
156 : // TabPage* GetPage( sal_uInt16 nLevel ) const { return WizardDialog::GetPage(nLevel); }
157 : // TODO: probably the complete page handling (next, previous etc.) should be prohibited ...
158 :
159 : // IMPORTANT:
160 : // traveling pages should not be done by calling these base class member, some mechanisms of this class
161 : // here (e.g. committing page data) depend on having full control over page traveling.
162 : // So use the travelXXX methods if you need to travel
163 :
164 : protected:
165 : VclPtr<OKButton> m_pFinish;
166 : VclPtr<CancelButton> m_pCancel;
167 : VclPtr<PushButton> m_pNextPage;
168 : VclPtr<PushButton> m_pPrevPage;
169 : VclPtr<HelpButton> m_pHelp;
170 :
171 : private:
172 : // hold members in this structure to allow keeping compatible when members are added
173 : WizardMachineImplData* m_pImpl;
174 :
175 : SVT_DLLPRIVATE void addButtons(vcl::Window* _pParent, sal_uInt32 _nButtonFlags);
176 :
177 : public:
178 : OWizardMachine(vcl::Window* _pParent, const WinBits i_nStyle, WizardButtonFlags _nButtonFlags );
179 : OWizardMachine(vcl::Window* _pParent, WizardButtonFlags _nButtonFlags );
180 : virtual ~OWizardMachine();
181 : virtual void dispose() SAL_OVERRIDE;
182 :
183 : /// enable (or disable) buttons
184 : void enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable);
185 : /// set the default style for a button
186 : void defaultButton(WizardButtonFlags _nWizardButtonFlags);
187 : /// set the default style for a button
188 : void defaultButton(PushButton* _pNewDefButton);
189 :
190 : /// set the base of the title to use - the title of the current page is appended
191 : void setTitleBase(const OUString& _rTitleBase);
192 :
193 : /// determines whether there is a next state to which we can advance
194 : virtual bool canAdvance() const;
195 :
196 : /** updates the user interface which deals with traveling in the wizard
197 :
198 : The default implementation simply checks whether both the current page and the wizard
199 : itself allow to advance to the next state (<code>canAdvance</code>), and enables the "Next"
200 : button if and only if this is the case.
201 : */
202 : virtual void updateTravelUI();
203 :
204 : protected:
205 : // WizardDialog overridables
206 : virtual void ActivatePage() SAL_OVERRIDE;
207 : virtual bool DeactivatePage() SAL_OVERRIDE;
208 :
209 : // our own overridables
210 :
211 : /// to override to create new pages
212 : virtual VclPtr<TabPage> createPage(WizardState _nState) = 0;
213 :
214 : /// will be called when a new page is about to be displayed
215 : virtual void enterState(WizardState _nState);
216 :
217 : /** will be called when the current state is about to be left for the given reason
218 :
219 : The base implementation in this class will simply call <member>OWizardPage::commitPage</member>
220 : for the current page, and return whatever this call returns.
221 :
222 : @param _eReason
223 : The reason why the state is to be left.
224 : @return
225 : <TRUE/> if and only if the page is allowed to be left
226 : */
227 : virtual bool prepareLeaveCurrentState( CommitPageReason _eReason );
228 :
229 : /** will be called when the given state is left
230 :
231 : This is the very last possibility for derived classes to veto the deactivation
232 : of a page.
233 :
234 : @todo Normally, we would not need the return value here - derived classes now have
235 : the possibility to veto page deactivations in <member>prepareLeaveCurrentState</member>. However,
236 : changing this return type is too incompatible at the moment ...
237 :
238 : @return
239 : <TRUE/> if and only if the page is allowed to be left
240 : */
241 : virtual bool leaveState( WizardState _nState );
242 :
243 : /** determine the next state to travel from the given one
244 :
245 : The default behaviour is linear traveling, overwrite this to change it
246 :
247 : Return WZS_INVALID_STATE to prevent traveling.
248 : */
249 : virtual WizardState determineNextState( WizardState _nCurrentState ) const;
250 :
251 : /** called when the finish button is pressed
252 : <p>By default, only the base class' Finish method (which is not virtual) is called</p>
253 : */
254 : virtual bool onFinish();
255 :
256 : /// travel to the next state
257 : bool travelNext();
258 :
259 : /// travel to the previous state
260 : bool travelPrevious();
261 :
262 : /** enables the automatic enabled/disabled state of the "Next" button
263 :
264 : If this is <TRUE/>, then upon entering a new state, the "Next" button will automatically be
265 : enabled if and only if determineNextState does not return WZS_INVALID_STATE.
266 : */
267 : void enableAutomaticNextButtonState( bool _bEnable = true );
268 : bool isAutomaticNextButtonStateEnabled() const;
269 :
270 : /** removes a page from the history. Should be called when the page is being disabled
271 : */
272 : void removePageFromHistory( WizardState nToRemove );
273 :
274 : /** skip a state
275 :
276 : The method behaves as if from the current state, <arg>_nSteps</arg> <method>travelNext</method>s were
277 : called, but without actually creating or displaying the \EDntermediate pages. Only the
278 : (<arg>_nSteps</arg> + 1)th page is created.
279 :
280 : The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them.
281 :
282 : A very essential precondition for using this method is that your <method>determineNextState</method>
283 : method is able to determine the next state without actually having the page of the current state.
284 :
285 : @return
286 : <TRUE/> if and only if traveling was successful
287 :
288 : @see skipUntil
289 : @see skipBackwardUntil
290 : */
291 : bool skip( sal_Int32 _nSteps = 1 );
292 :
293 : /** skips one or more states, until a given state is reached
294 :
295 : The method behaves as if from the current state, <method>travelNext</method>s were called
296 : successively, until <arg>_nTargetState</arg> is reached, but without actually creating or
297 : displaying the \EDntermediate pages.
298 :
299 : The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them.
300 :
301 : @return
302 : <TRUE/> if and only if traveling was successful
303 :
304 : @see skip
305 : @see skipBackwardUntil
306 : */
307 : bool skipUntil( WizardState _nTargetState );
308 :
309 : /** moves back one or more states, until a given state is reached
310 :
311 : This method allows traveling backwards more than one state without actually showing the intermediate
312 : states.
313 :
314 : For instance, if you want to travel two steps backward at a time, you could used
315 : two travelPrevious calls, but this would <em>show</em> both pages, which is not necessary,
316 : since you're interested in the target page only. Using <member>skipBackwardUntil</member> relieves
317 : you of this.
318 :
319 : @return
320 : <TRUE/> if and only if traveling was successful
321 :
322 : @see skipUntil
323 : @see skip
324 : */
325 : bool skipBackwardUntil( WizardState _nTargetState );
326 :
327 : /** returns the current state of the machine
328 :
329 : Vulgo, this is the identifier of the current tab page :)
330 : */
331 0 : WizardState getCurrentState() const { return WizardDialog::GetCurLevel(); }
332 :
333 : virtual IWizardPageController*
334 : getPageController( TabPage* _pCurrentPage ) const;
335 :
336 : /** retrieves a copy of the state history, i.e. all states we already visited
337 : */
338 : void getStateHistory( ::std::vector< WizardState >& _out_rHistory );
339 :
340 : public:
341 : class AccessGuard
342 : {
343 : friend class WizardTravelSuspension;
344 : private:
345 0 : AccessGuard() { }
346 : };
347 :
348 : void suspendTraveling( AccessGuard );
349 : void resumeTraveling( AccessGuard );
350 : bool isTravelingSuspended() const;
351 :
352 : protected:
353 : TabPage* GetOrCreatePage( const WizardState i_nState );
354 :
355 : private:
356 : DECL_DLLPRIVATE_LINK(OnNextPage, void*);
357 : DECL_DLLPRIVATE_LINK(OnPrevPage, void*);
358 : DECL_DLLPRIVATE_LINK(OnFinish, void*);
359 :
360 : SVT_DLLPRIVATE void implResetDefault(vcl::Window* _pWindow);
361 : SVT_DLLPRIVATE void implUpdateTitle();
362 : SVT_DLLPRIVATE void implConstruct( const WizardButtonFlags _nButtonFlags );
363 : };
364 :
365 : /// helper class to temporarily suspend any traveling in the wizard
366 : class WizardTravelSuspension
367 : {
368 : public:
369 0 : WizardTravelSuspension( OWizardMachine& _rWizard )
370 0 : :m_rWizard( _rWizard )
371 : {
372 0 : m_rWizard.suspendTraveling( OWizardMachine::AccessGuard() );
373 0 : }
374 :
375 0 : ~WizardTravelSuspension()
376 : {
377 0 : m_rWizard.resumeTraveling( OWizardMachine::AccessGuard() );
378 0 : }
379 :
380 : private:
381 : OWizardMachine& m_rWizard;
382 : };
383 :
384 :
385 : } // namespace svt
386 :
387 :
388 : #endif // INCLUDED_SVTOOLS_WIZARDMACHINE_HXX
389 :
390 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|