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