xref: /trunk/main/svtools/source/dialogs/wizardmachine.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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