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 
392