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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 #include <svtools/wizardmachine.hxx>
27 #include <svtools/helpid.hrc>
28 #include <tools/debug.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <vcl/msgbox.hxx>
31 #include <svtools/svtdata.hxx>
32 #ifndef _SVTOOLS_HRC
33 #include <svtools/svtools.hrc>
34 #endif
35 
36 //.........................................................................
37 namespace svt
38 {
39 //.........................................................................
40 
41 	//=====================================================================
42 	//= WizardPageImplData
43 	//=====================================================================
44 	struct WizardPageImplData
45 	{
WizardPageImplDatasvt::WizardPageImplData46 		WizardPageImplData()
47 		{
48 		}
49 	};
50 
51 	//=====================================================================
52 	//= OWizardPage
53 	//=====================================================================
54 	//---------------------------------------------------------------------
OWizardPage(Window * _pParent,WinBits _nStyle)55     OWizardPage::OWizardPage( Window* _pParent, WinBits _nStyle )
56 		:TabPage( _pParent, _nStyle )
57 		,m_pImpl( new WizardPageImplData )
58 	{
59 	}
60 
61 	//---------------------------------------------------------------------
OWizardPage(Window * _pParent,const ResId & _rResId)62     OWizardPage::OWizardPage( Window* _pParent, const ResId& _rResId )
63 		:TabPage( _pParent, _rResId )
64 		,m_pImpl( new WizardPageImplData )
65 	{
66 	}
67 
68 	//---------------------------------------------------------------------
~OWizardPage()69 	OWizardPage::~OWizardPage()
70 	{
71 		delete m_pImpl;
72 	}
73 
74 	//---------------------------------------------------------------------
initializePage()75 	void OWizardPage::initializePage()
76 	{
77 	}
78 
79 	//---------------------------------------------------------------------
ActivatePage()80 	void OWizardPage::ActivatePage()
81 	{
82 		TabPage::ActivatePage();
83         updateDialogTravelUI();
84 	}
85 
86     //---------------------------------------------------------------------
updateDialogTravelUI()87     void OWizardPage::updateDialogTravelUI()
88     {
89         OWizardMachine* pWizardMachine = dynamic_cast< OWizardMachine* >( GetParent() );
90         if ( pWizardMachine )
91             pWizardMachine->updateTravelUI();
92     }
93 
94 	//---------------------------------------------------------------------
canAdvance() const95 	bool OWizardPage::canAdvance() const
96 	{
97         return true;
98 	}
99 
100 	//---------------------------------------------------------------------
commitPage(WizardTypes::CommitPageReason)101 	sal_Bool OWizardPage::commitPage( WizardTypes::CommitPageReason )
102 	{
103 		return sal_True;
104 	}
105 
106 	//=====================================================================
107 	//= WizardMachineImplData
108 	//=====================================================================
109     struct WizardMachineImplData : public WizardTypes
110 	{
111         String                          sTitleBase;         // the base for the title
112         ::std::stack< WizardState >     aStateHistory;      // the history of all states (used for implementing "Back")
113 
114         WizardState                     nFirstUnknownPage;
115             // the WizardDialog does not allow non-linear transitions (e.g. it's
116             // not possible to add pages in a non-linear order), so we need some own maintainance data
117 
118 		sal_Bool						m_bAutoNextButtonState;
119 
120         bool                            m_bTravelingSuspended;
121 
WizardMachineImplDatasvt::WizardMachineImplData122         WizardMachineImplData()
123             :nFirstUnknownPage( 0 )
124             ,m_bAutoNextButtonState( sal_False )
125             ,m_bTravelingSuspended( false )
126         {
127         }
128 	};
129 
calcRightHelpOffset(sal_uInt32 _nButtonFlags)130     long OWizardMachine::calcRightHelpOffset(sal_uInt32 _nButtonFlags)
131     {
132         sal_Int32 nMask = 1;
133         sal_Int32 nRightAlignedButtonCount = -1;
134         for (unsigned int i = 0; i < 8*sizeof(_nButtonFlags); i++ )
135         {
136             if( ( _nButtonFlags & nMask ) != 0 )
137                 nRightAlignedButtonCount++;
138             nMask <<= 1;
139         }
140         Size aSize = GetPageSizePixel();
141         sal_Int32 nTotButtonWidth = nRightAlignedButtonCount * LogicalCoordinateToPixel(50);
142         sal_Int32 nTotRightButtonSpaceOffset = (nRightAlignedButtonCount) * WIZARDDIALOG_BUTTON_STDOFFSET_X;
143         if ((_nButtonFlags & WZB_NEXT) && (_nButtonFlags & WZB_NEXT))
144             nTotRightButtonSpaceOffset = (nTotRightButtonSpaceOffset - WIZARDDIALOG_BUTTON_STDOFFSET_X) + WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X;
145         return aSize.Width() - nTotButtonWidth - nTotRightButtonSpaceOffset;
146     }
147 
148 	//=====================================================================
149 	//= OWizardMachine
150 	//=====================================================================
151 	//---------------------------------------------------------------------
OWizardMachine(Window * _pParent,const ResId & _rRes,sal_uInt32 _nButtonFlags)152 	OWizardMachine::OWizardMachine(Window* _pParent, const ResId& _rRes, sal_uInt32 _nButtonFlags )
153 		:WizardDialog( _pParent, _rRes )
154 		,m_pFinish(NULL)
155 		,m_pCancel(NULL)
156 		,m_pNextPage(NULL)
157 		,m_pPrevPage(NULL)
158 		,m_pHelp(NULL)
159 		,m_pImpl( new WizardMachineImplData )
160 	{
161         implConstruct( _nButtonFlags );
162 	}
163 
164 	//---------------------------------------------------------------------
OWizardMachine(Window * _pParent,const WinBits i_nStyle,sal_uInt32 _nButtonFlags)165     OWizardMachine::OWizardMachine(Window* _pParent, const WinBits i_nStyle, sal_uInt32 _nButtonFlags )
166 		:WizardDialog( _pParent, i_nStyle )
167 		,m_pFinish(NULL)
168 		,m_pCancel(NULL)
169 		,m_pNextPage(NULL)
170 		,m_pPrevPage(NULL)
171 		,m_pHelp(NULL)
172 		,m_pImpl( new WizardMachineImplData )
173     {
174         implConstruct( _nButtonFlags );
175     }
176 
177 	//---------------------------------------------------------------------
implConstruct(const sal_uInt32 _nButtonFlags)178     void OWizardMachine::implConstruct( const sal_uInt32 _nButtonFlags )
179     {
180 		m_pImpl->sTitleBase = GetText();
181 
182 		// create the buttons according to the wizard button flags
183 		// the help button
184 		if (_nButtonFlags & WZB_HELP)
185 		{
186 			m_pHelp= new HelpButton(this, WB_TABSTOP);
187 			m_pHelp->SetSizePixel( LogicToPixel( Size( 50, 14 ), MAP_APPFONT ) );
188 			m_pHelp->Show();
189 			AddButton( m_pHelp, WIZARDDIALOG_BUTTON_STDOFFSET_X);
190 		}
191 
192 		// the previous button
193 		if (_nButtonFlags & WZB_PREVIOUS)
194 		{
195 			m_pPrevPage = new PushButton(this, WB_TABSTOP);
196             m_pPrevPage->SetHelpId( HID_WIZARD_PREVIOUS );
197 			m_pPrevPage->SetSizePixel( LogicToPixel( Size( 50, 14 ), MAP_APPFONT ) );
198 			m_pPrevPage->SetText(String(SvtResId(STR_WIZDLG_PREVIOUS)));
199 			m_pPrevPage->Show();
200 
201 			if (_nButtonFlags & WZB_NEXT)
202 				AddButton( m_pPrevPage, ( WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X) );		// half x-offset to the next button
203 			else
204 				AddButton( m_pPrevPage, WIZARDDIALOG_BUTTON_STDOFFSET_X );
205 			SetPrevButton( m_pPrevPage );
206 			m_pPrevPage->SetClickHdl( LINK( this, OWizardMachine, OnPrevPage ) );
207 		}
208 
209 		// the next button
210 		if (_nButtonFlags & WZB_NEXT)
211 		{
212 			m_pNextPage = new PushButton(this, WB_TABSTOP);
213             m_pNextPage->SetHelpId( HID_WIZARD_NEXT );
214 			m_pNextPage->SetSizePixel( LogicToPixel( Size( 50, 14 ), MAP_APPFONT ) );
215 			m_pNextPage->SetText(String(SvtResId(STR_WIZDLG_NEXT)));
216 			m_pNextPage->Show();
217 
218 			AddButton( m_pNextPage, WIZARDDIALOG_BUTTON_STDOFFSET_X );
219 			SetNextButton( m_pNextPage );
220 			m_pNextPage->SetClickHdl( LINK( this, OWizardMachine, OnNextPage ) );
221 		}
222 
223 		// the finish button
224 		if (_nButtonFlags & WZB_FINISH)
225 		{
226 			m_pFinish = new OKButton(this, WB_TABSTOP);
227 			m_pFinish->SetSizePixel( LogicToPixel( Size( 50, 14 ), MAP_APPFONT ) );
228 			m_pFinish->SetText(String(SvtResId(STR_WIZDLG_FINISH)));
229 			m_pFinish->Show();
230 
231 			AddButton( m_pFinish, WIZARDDIALOG_BUTTON_STDOFFSET_X );
232 			m_pFinish->SetClickHdl( LINK( this, OWizardMachine, OnFinish ) );
233 		}
234 
235         // the cancel button
236 		if (_nButtonFlags & WZB_CANCEL)
237 		{
238 			m_pCancel = new CancelButton(this, WB_TABSTOP);
239 			m_pCancel->SetSizePixel( LogicToPixel( Size( 50, 14 ), MAP_APPFONT ) );
240 			m_pCancel->Show();
241 
242 			AddButton( m_pCancel, WIZARDDIALOG_BUTTON_STDOFFSET_X );
243 		}
244     }
245 
246     //---------------------------------------------------------------------
~OWizardMachine()247 	OWizardMachine::~OWizardMachine()
248 	{
249 		delete m_pFinish;
250 		delete m_pCancel;
251 		delete m_pNextPage;
252 		delete m_pPrevPage;
253 		delete m_pHelp;
254 
255 		for (WizardState i=0; i<m_pImpl->nFirstUnknownPage; ++i)
256 			delete GetPage(i);
257 
258 		delete m_pImpl;
259 	}
260 
261 	//---------------------------------------------------------------------
implUpdateTitle()262 	void OWizardMachine::implUpdateTitle()
263 	{
264 		String sCompleteTitle(m_pImpl->sTitleBase);
265 
266         // append the page title
267 		TabPage* pCurrentPage = GetPage(getCurrentState());
268 		if ( pCurrentPage && pCurrentPage->GetText().Len() )
269 		{
270 			sCompleteTitle += String::CreateFromAscii(" - ");
271 			sCompleteTitle += pCurrentPage->GetText();
272 		}
273 
274         SetText(sCompleteTitle);
275 	}
276 
277 	//---------------------------------------------------------------------
getTitleBase() const278 	const String& OWizardMachine::getTitleBase() const
279 	{
280 		return m_pImpl->sTitleBase;
281 	}
282 
283 	//---------------------------------------------------------------------
setTitleBase(const String & _rTitleBase)284 	void OWizardMachine::setTitleBase(const String& _rTitleBase)
285 	{
286 		m_pImpl->sTitleBase = _rTitleBase;
287 		implUpdateTitle();
288 	}
289 
290 	//---------------------------------------------------------------------
GetOrCreatePage(const WizardState i_nState)291     TabPage* OWizardMachine::GetOrCreatePage( const WizardState i_nState )
292     {
293 		if ( NULL == GetPage( i_nState ) )
294 		{
295 			TabPage* pNewPage = createPage( i_nState );
296 			DBG_ASSERT( pNewPage, "OWizardMachine::GetOrCreatePage: invalid new page (NULL)!" );
297 
298 			// fill up the page sequence of our base class (with dummies)
299 			while ( m_pImpl->nFirstUnknownPage < i_nState )
300 			{
301 				AddPage( NULL );
302 				++m_pImpl->nFirstUnknownPage;
303 			}
304 
305 			if ( m_pImpl->nFirstUnknownPage == i_nState )
306 			{
307 				// encountered this page number the first time
308 				AddPage( pNewPage );
309 				++m_pImpl->nFirstUnknownPage;
310 			}
311 			else
312 				// already had this page - just change it
313 				SetPage( i_nState, pNewPage );
314 		}
315         return GetPage( i_nState );
316     }
317 
318 	//---------------------------------------------------------------------
ActivatePage()319 	void OWizardMachine::ActivatePage()
320 	{
321 		WizardDialog::ActivatePage();
322 
323 		WizardState nCurrentLevel = GetCurLevel();
324         GetOrCreatePage( nCurrentLevel );
325 
326 		enterState( nCurrentLevel );
327 	}
328 
329 	//---------------------------------------------------------------------
DeactivatePage()330 	long OWizardMachine::DeactivatePage()
331 	{
332 		WizardState nCurrentState = getCurrentState();
333 		if (!leaveState(nCurrentState) || !WizardDialog::DeactivatePage())
334 			return sal_False;
335 		return sal_True;
336 	}
337 
338 	//---------------------------------------------------------------------
defaultButton(sal_uInt32 _nWizardButtonFlags)339 	void OWizardMachine::defaultButton(sal_uInt32 _nWizardButtonFlags)
340 	{
341 		// the new default button
342 		PushButton* pNewDefButton = NULL;
343 		if (m_pFinish && (_nWizardButtonFlags & WZB_FINISH))
344 			pNewDefButton = m_pFinish;
345 		if (m_pNextPage && (_nWizardButtonFlags & WZB_NEXT))
346 			pNewDefButton = m_pNextPage;
347 		if (m_pPrevPage && (_nWizardButtonFlags & WZB_PREVIOUS))
348 			pNewDefButton = m_pPrevPage;
349 		if (m_pHelp && (_nWizardButtonFlags & WZB_HELP))
350 			pNewDefButton = m_pHelp;
351 		if (m_pCancel && (_nWizardButtonFlags & WZB_CANCEL))
352 			pNewDefButton = m_pCancel;
353 
354 		if ( pNewDefButton )
355 			defaultButton( pNewDefButton );
356         else
357             implResetDefault( this );
358 	}
359 
360 	//---------------------------------------------------------------------
implResetDefault(Window * _pWindow)361 	void OWizardMachine::implResetDefault(Window* _pWindow)
362 	{
363 		Window* pChildLoop = _pWindow->GetWindow(WINDOW_FIRSTCHILD);
364 		while (pChildLoop)
365 		{
366 			// does the window participate in the tabbing order?
367 			if (pChildLoop->GetStyle() & WB_DIALOGCONTROL)
368 				implResetDefault(pChildLoop);
369 
370 			// is it a button?
371 			WindowType eType = pChildLoop->GetType();
372 			if	(	(WINDOW_BUTTON == eType)
373 				||	(WINDOW_PUSHBUTTON == eType)
374 				||	(WINDOW_OKBUTTON == eType)
375 				||	(WINDOW_CANCELBUTTON == eType)
376 				||	(WINDOW_HELPBUTTON == eType)
377 				||	(WINDOW_IMAGEBUTTON == eType)
378 				||	(WINDOW_MENUBUTTON == eType)
379 				||	(WINDOW_MOREBUTTON == eType)
380 				)
381 			{
382 				pChildLoop->SetStyle(pChildLoop->GetStyle() & ~WB_DEFBUTTON);
383 			}
384 
385 			// the next one ...
386 			pChildLoop = pChildLoop->GetWindow(WINDOW_NEXT);
387 		}
388 	}
389 
390 	//---------------------------------------------------------------------
defaultButton(PushButton * _pNewDefButton)391 	void OWizardMachine::defaultButton(PushButton* _pNewDefButton)
392 	{
393 		// loop through all (direct and indirect) descendants which participate in our tabbing order, and
394 		// reset the WB_DEFBUTTON for every window which is a button
395 		implResetDefault(this);
396 
397 		// set it's new style
398 		if (_pNewDefButton)
399 			_pNewDefButton->SetStyle(_pNewDefButton->GetStyle() | WB_DEFBUTTON);
400 	}
401 
402 	//---------------------------------------------------------------------
enableButtons(sal_uInt32 _nWizardButtonFlags,sal_Bool _bEnable)403 	void OWizardMachine::enableButtons(sal_uInt32 _nWizardButtonFlags, sal_Bool _bEnable)
404 	{
405 		if (m_pFinish && (_nWizardButtonFlags & WZB_FINISH))
406 			m_pFinish->Enable(_bEnable);
407 		if (m_pNextPage && (_nWizardButtonFlags & WZB_NEXT))
408 			m_pNextPage->Enable(_bEnable);
409 		if (m_pPrevPage && (_nWizardButtonFlags & WZB_PREVIOUS))
410 			m_pPrevPage->Enable(_bEnable);
411 		if (m_pHelp && (_nWizardButtonFlags & WZB_HELP))
412 			m_pHelp->Enable(_bEnable);
413 		if (m_pCancel && (_nWizardButtonFlags & WZB_CANCEL))
414 			m_pCancel->Enable(_bEnable);
415 	}
416 
417 	//---------------------------------------------------------------------
enterState(WizardState _nState)418 	void OWizardMachine::enterState(WizardState _nState)
419 	{
420 		// tell the page
421 		IWizardPageController* pController = getPageController( GetPage( _nState ) );
422         OSL_ENSURE( pController, "OWizardMachine::enterState: no controller for the given page!" );
423 		if ( pController )
424 			pController->initializePage();
425 
426 		if ( isAutomaticNextButtonStateEnabled() )
427 			enableButtons( WZB_NEXT, canAdvance() );
428 
429 		enableButtons( WZB_PREVIOUS, !m_pImpl->aStateHistory.empty() );
430 
431 		// set the new title - it depends on the current page (i.e. state)
432 		implUpdateTitle();
433 	}
434 
435 	//---------------------------------------------------------------------
leaveState(WizardState)436 	sal_Bool OWizardMachine::leaveState(WizardState)
437 	{
438 		// no need to ask the page here.
439 		// If we reach this point, we already gave the current page the chance to commit it's data,
440 		// and it was allowed to commit it's data
441 
442 		return sal_True;
443 	}
444 
445 	//---------------------------------------------------------------------
onFinish()446 	sal_Bool OWizardMachine::onFinish()
447 	{
448 		return Finnish( RET_OK );
449 	}
450 
451 	//---------------------------------------------------------------------
IMPL_LINK(OWizardMachine,OnFinish,PushButton *,EMPTYARG)452 	IMPL_LINK(OWizardMachine, OnFinish, PushButton*, EMPTYARG)
453 	{
454 		if ( isTravelingSuspended() )
455             return 0;
456         WizardTravelSuspension aTravelGuard( *this );
457         if ( !prepareLeaveCurrentState( eFinish ) )
458         {
459 			return 0L;
460         }
461         return onFinish() ? 1L : 0L;
462 	}
463 
464 	//---------------------------------------------------------------------
determineNextState(WizardState _nCurrentState) const465 	OWizardMachine::WizardState OWizardMachine::determineNextState( WizardState _nCurrentState ) const
466 	{
467 		return _nCurrentState + 1;
468 	}
469 
470 	//---------------------------------------------------------------------
prepareLeaveCurrentState(CommitPageReason _eReason)471     sal_Bool OWizardMachine::prepareLeaveCurrentState( CommitPageReason _eReason )
472 	{
473 		IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
474         ENSURE_OR_RETURN( pController != NULL, "OWizardMachine::prepareLeaveCurrentState: no controller for the current page!", sal_True );
475         return pController->commitPage( _eReason );
476 	}
477 
478 	//---------------------------------------------------------------------
skipBackwardUntil(WizardState _nTargetState)479 	sal_Bool OWizardMachine::skipBackwardUntil( WizardState _nTargetState )
480     {
481 		// alowed to leave the current page?
482 		if ( !prepareLeaveCurrentState( eTravelBackward ) )
483 			return sal_False;
484 
485         // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong
486         ::std::stack< WizardState > aTravelVirtually = m_pImpl->aStateHistory;
487 		::std::stack< WizardState > aOldStateHistory = m_pImpl->aStateHistory;
488 
489         WizardState nCurrentRollbackState = getCurrentState();
490         while ( nCurrentRollbackState != _nTargetState )
491         {
492             DBG_ASSERT( !aTravelVirtually.empty(), "OWizardMachine::skipBackwardUntil: this target state does not exist in the history!" );
493 		    nCurrentRollbackState = aTravelVirtually.top();
494     		aTravelVirtually.pop();
495         }
496         m_pImpl->aStateHistory = aTravelVirtually;
497 		if ( !ShowPage( _nTargetState ) )
498 		{
499 	        m_pImpl->aStateHistory = aOldStateHistory;
500 			return sal_False;
501 		}
502 		return sal_True;
503     }
504 
505 	//---------------------------------------------------------------------
skipUntil(WizardState _nTargetState)506 	sal_Bool OWizardMachine::skipUntil( WizardState _nTargetState )
507     {
508 		WizardState nCurrentState = getCurrentState();
509 
510         // alowed to leave the current page?
511         if ( !prepareLeaveCurrentState( nCurrentState < _nTargetState ? eTravelForward : eTravelBackward ) )
512 			return sal_False;
513 
514         // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong
515         ::std::stack< WizardState > aTravelVirtually = m_pImpl->aStateHistory;
516 		::std::stack< WizardState > aOldStateHistory = m_pImpl->aStateHistory;
517         while ( nCurrentState != _nTargetState )
518         {
519     		WizardState nNextState = determineNextState( nCurrentState );
520 			if ( WZS_INVALID_STATE == nNextState )
521             {
522                 DBG_ERROR( "OWizardMachine::skipUntil: the given target state does not exist!" );
523 				return sal_False;
524             }
525 
526             // remember the skipped state in the history
527 			aTravelVirtually.push( nCurrentState );
528 
529 			// get the next state
530 			nCurrentState = nNextState;
531         }
532         m_pImpl->aStateHistory = aTravelVirtually;
533 		// show the target page
534 		if ( !ShowPage( nCurrentState ) )
535         {
536             // argh! prepareLeaveCurrentPage succeeded, determineNextState succeeded,
537             // but ShowPage doesn't? Somebody behaves very strange here ....
538 			DBG_ERROR( "OWizardMachine::skipUntil: very unpolite ...." );
539 	        m_pImpl->aStateHistory = aOldStateHistory;
540 			return sal_False;
541         }
542 		return sal_True;
543     }
544 
545 	//---------------------------------------------------------------------
skip(sal_Int32 _nSteps)546 	sal_Bool OWizardMachine::skip(sal_Int32 _nSteps)
547 	{
548 		DBG_ASSERT(_nSteps > 0, "OWizardMachine::skip: invalid number of steps!");
549 		// alowed to leave the current page?
550 		if ( !prepareLeaveCurrentState( eTravelForward ) )
551 			return sal_False;
552 
553 		WizardState nCurrentState = getCurrentState();
554 		WizardState nNextState = determineNextState(nCurrentState);
555 		// loop _nSteps steps
556 		while (_nSteps-- > 0)
557 		{
558 			if (WZS_INVALID_STATE == nNextState)
559 				return sal_False;
560 
561 			// remember the skipped state in the history
562 			m_pImpl->aStateHistory.push(nCurrentState);
563 
564 			// get the next state
565 			nCurrentState = nNextState;
566 			nNextState = determineNextState(nCurrentState);
567 		}
568 
569 		// show the (n+1)th page
570 		if (!ShowPage(nCurrentState))
571 		{
572 			// TODO: this leaves us in a state where we have no current page and an inconsistent state history.
573 			// Perhaps we should rollback the skipping here ....
574 			DBG_ERROR("OWizardMachine::skip: very unpolite ....");
575 				// if somebody does a skip and then does not allow to leave ...
576 				// (can't be a commit error, as we've already committed the current page. So if ShowPage fails here,
577 				// somebody behaves really strange ...)
578 			return sal_False;
579 		}
580 
581 		// all fine
582 		return sal_True;
583 	}
584 
585 	//---------------------------------------------------------------------
travelNext()586 	sal_Bool OWizardMachine::travelNext()
587 	{
588 		// allowed to leave the current page?
589 		if ( !prepareLeaveCurrentState( eTravelForward ) )
590 			return sal_False;
591 
592 		// determine the next state to travel to
593 		WizardState nCurrentState = getCurrentState();
594 		WizardState nNextState = determineNextState(nCurrentState);
595 		if (WZS_INVALID_STATE == nNextState)
596 			return sal_False;
597 
598 		// the state history is used by the enterState method
599 		// all fine
600 		m_pImpl->aStateHistory.push(nCurrentState);
601 		if (!ShowPage(nNextState))
602 		{
603 			m_pImpl->aStateHistory.pop();
604 			return sal_False;
605 		}
606 
607 		return sal_True;
608 	}
609 
610 	//---------------------------------------------------------------------
travelPrevious()611 	sal_Bool OWizardMachine::travelPrevious()
612 	{
613 		DBG_ASSERT(m_pImpl->aStateHistory.size() > 0, "OWizardMachine::travelPrevious: have no previous page!");
614 
615 		// alowed to leave the current page?
616 		if ( !prepareLeaveCurrentState( eTravelBackward ) )
617 			return sal_False;
618 
619 		// the next state to switch to
620 		WizardState nPreviousState = m_pImpl->aStateHistory.top();
621 
622 		// the state history is used by the enterState method
623 		m_pImpl->aStateHistory.pop();
624 		// show this page
625 		if (!ShowPage(nPreviousState))
626 		{
627 			m_pImpl->aStateHistory.push(nPreviousState);
628 			return sal_False;
629 		}
630 
631 		// all fine
632 		return sal_True;
633 	}
634 
635     //---------------------------------------------------------------------
removePageFromHistory(WizardState nToRemove)636     void  OWizardMachine::removePageFromHistory( WizardState nToRemove )
637     {
638 
639         ::std::stack< WizardState > aTemp;
640         while(!m_pImpl->aStateHistory.empty())
641         {
642             WizardState nPreviousState = m_pImpl->aStateHistory.top();
643             m_pImpl->aStateHistory.pop();
644             if(nPreviousState != nToRemove)
645                 aTemp.push( nPreviousState );
646             else
647                 break;
648         }
649         while(!aTemp.empty())
650         {
651             m_pImpl->aStateHistory.push( aTemp.top() );
652             aTemp.pop();
653         }
654     }
655 
656 	//---------------------------------------------------------------------
enableAutomaticNextButtonState(bool _bEnable)657     void OWizardMachine::enableAutomaticNextButtonState( bool _bEnable )
658     {
659         m_pImpl->m_bAutoNextButtonState = _bEnable;
660     }
661 
662     //---------------------------------------------------------------------
isAutomaticNextButtonStateEnabled() const663     bool OWizardMachine::isAutomaticNextButtonStateEnabled() const
664     {
665         return m_pImpl->m_bAutoNextButtonState;
666     }
667 
668     //---------------------------------------------------------------------
IMPL_LINK(OWizardMachine,OnPrevPage,PushButton *,EMPTYARG)669 	IMPL_LINK(OWizardMachine, OnPrevPage, PushButton*, EMPTYARG)
670 	{
671 		if ( isTravelingSuspended() )
672             return 0;
673         WizardTravelSuspension aTravelGuard( *this );
674 		sal_Int32 nRet = travelPrevious();
675         return nRet;
676 	}
677 
678 	//---------------------------------------------------------------------
IMPL_LINK(OWizardMachine,OnNextPage,PushButton *,EMPTYARG)679 	IMPL_LINK(OWizardMachine, OnNextPage, PushButton*, EMPTYARG)
680 	{
681 		if ( isTravelingSuspended() )
682             return 0;
683         WizardTravelSuspension aTravelGuard( *this );
684 		sal_Int32 nRet = travelNext();
685         return nRet;
686 	}
687 
688     //---------------------------------------------------------------------
getPageController(TabPage * _pCurrentPage) const689 	IWizardPageController* OWizardMachine::getPageController( TabPage* _pCurrentPage ) const
690 	{
691 		IWizardPageController* pController = dynamic_cast< IWizardPageController* >( _pCurrentPage );
692 		return pController;
693 	}
694 
695     //---------------------------------------------------------------------
getStateHistory(::std::vector<WizardState> & _out_rHistory)696     void OWizardMachine::getStateHistory( ::std::vector< WizardState >& _out_rHistory )
697     {
698         ::std::stack< WizardState > aHistoryCopy( m_pImpl->aStateHistory );
699         while ( !aHistoryCopy.empty() )
700         {
701             _out_rHistory.push_back( aHistoryCopy.top() );
702             aHistoryCopy.pop();
703         }
704     }
705 
706     //---------------------------------------------------------------------
canAdvance() const707     bool OWizardMachine::canAdvance() const
708     {
709         return WZS_INVALID_STATE != determineNextState( getCurrentState() );
710     }
711 
712     //---------------------------------------------------------------------
updateTravelUI()713     void OWizardMachine::updateTravelUI()
714     {
715         const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
716         OSL_ENSURE( pController != NULL, "RoadmapWizard::updateTravelUI: no controller for the current page!" );
717 
718         bool bCanAdvance =
719                 ( !pController || pController->canAdvance() )   // the current page allows to advance
720             &&  canAdvance();                                   // the dialog as a whole allows to advance
721         enableButtons( WZB_NEXT, bCanAdvance );
722     }
723 
724     //---------------------------------------------------------------------
isTravelingSuspended() const725     bool OWizardMachine::isTravelingSuspended() const
726     {
727         return m_pImpl->m_bTravelingSuspended;
728     }
729 
730 	//---------------------------------------------------------------------
suspendTraveling(AccessGuard)731     void OWizardMachine::suspendTraveling( AccessGuard )
732     {
733         DBG_ASSERT( !m_pImpl->m_bTravelingSuspended, "OWizardMachine::suspendTraveling: already suspended!" );
734        m_pImpl->m_bTravelingSuspended = true;
735     }
736 
737 	//---------------------------------------------------------------------
resumeTraveling(AccessGuard)738     void OWizardMachine::resumeTraveling( AccessGuard )
739     {
740         DBG_ASSERT( m_pImpl->m_bTravelingSuspended, "OWizardMachine::resumeTraveling: nothing to resume!" );
741        m_pImpl->m_bTravelingSuspended = false;
742     }
743 
744 //.........................................................................
745 }	// namespace svt
746 //.........................................................................
747