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