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