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 
31 #include <svtools/roadmapwizard.hxx>
32 #include <svtools/svtools.hrc>
33 #include <svtools/svtdata.hxx>
34 #include <svtools/roadmap.hxx>
35 #include <tools/debug.hxx>
36 
37 #include <stdarg.h>
38 
39 #include <vector>
40 #include <map>
41 #include <set>
42 
43 //........................................................................
44 namespace svt
45 {
46 //........................................................................
47 
48     namespace
49     {
50         typedef ::std::set< WizardTypes::WizardState >          StateSet;
51 
52         typedef ::std::map<
53                     RoadmapWizardTypes::PathId,
54                     RoadmapWizardTypes::WizardPath
55                 >                                               Paths;
56 
57         typedef ::std::map<
58                     WizardTypes::WizardState,
59                     ::std::pair<
60                         String,
61                         RoadmapWizardTypes::RoadmapPageFactory
62                     >
63                 >                                               StateDescriptions;
64     }
65 
66     struct RoadmapWizardImpl : public RoadmapWizardTypes
67     {
68         ORoadmap*           pRoadmap;
69         Paths               aPaths;
70         PathId              nActivePath;
71         StateDescriptions   aStateDescriptors;
72         StateSet            aDisabledStates;
73         bool                bActivePathIsDefinite;
74        	FixedLine*	        pFixedLine;
75 
76         RoadmapWizardImpl()
77             :pRoadmap( NULL )
78             ,nActivePath( -1 )
79             ,bActivePathIsDefinite( false )
80             ,pFixedLine(NULL)
81         {
82         }
83 
84         ~RoadmapWizardImpl()
85         {
86             delete pRoadmap;
87             delete pFixedLine;
88         }
89 
90         /// returns the index of the current state in given path, or -1
91         sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath );
92         /// returns the index of the current state in the path with the given id, or -1
93         sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, PathId _nPathId );
94         /// returns the index of the first state in which the two given paths differ
95         sal_Int32 getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS );
96     };
97 
98     //--------------------------------------------------------------------
99     sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath )
100     {
101         sal_Int32 nStateIndexInPath = 0;
102         WizardPath::const_iterator aPathLoop = _rPath.begin();
103         for ( ; aPathLoop != _rPath.end(); ++aPathLoop, ++nStateIndexInPath )
104             if ( *aPathLoop == _nState )
105                 break;
106         if ( aPathLoop == _rPath.end() )
107             nStateIndexInPath = -1;
108         return nStateIndexInPath;
109     }
110 
111     //--------------------------------------------------------------------
112     sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState, PathId _nPathId )
113     {
114         sal_Int32 nStateIndexInPath = -1;
115         Paths::const_iterator aPathPos = aPaths.find( _nPathId );
116         if ( aPathPos != aPaths.end( ) )
117             nStateIndexInPath = getStateIndexInPath( _nState, aPathPos->second );
118         return nStateIndexInPath;
119     }
120 
121     //--------------------------------------------------------------------
122     sal_Int32 RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS )
123     {
124         sal_Int32 nMinLength = ::std::min( _rLHS.size(), _rRHS.size() );
125         for ( sal_Int32 nCheck = 0; nCheck < nMinLength; ++nCheck )
126         {
127             if ( _rLHS[ nCheck ] != _rRHS[ nCheck ] )
128                 return nCheck;
129         }
130         return nMinLength;
131     }
132 
133     //====================================================================
134 	//= RoadmapWizard
135 	//====================================================================
136     DBG_NAME( RoadmapWizard )
137     //--------------------------------------------------------------------
138 #if OSL_DEBUG_LEVEL > 0
139     const char* CheckInvariants( const void* pVoid )
140     {
141         return static_cast< const RoadmapWizard* >( pVoid )->checkInvariants();
142     }
143 
144     //--------------------------------------------------------------------
145     const sal_Char* RoadmapWizard::checkInvariants() const
146     {
147         // all paths have to start with the same state
148         WizardState nSharedFirstState = WZS_INVALID_STATE;
149         for ( Paths::const_iterator aPath = m_pImpl->aPaths.begin();
150               aPath != m_pImpl->aPaths.end();
151               ++aPath
152             )
153         {
154             if ( aPath->second.empty() )
155                 return "RoadmapWizard::checkInvariants: paths should not be empty!";
156 
157             if ( nSharedFirstState == WZS_INVALID_STATE )
158                 // first path
159                 nSharedFirstState = aPath->second[ 0 ];
160             else
161                 if ( nSharedFirstState != aPath->second[ 0 ] )
162                     return "RoadmapWizard::checkInvariants: alls paths must start with the same state!";
163         }
164 
165         if ( !m_pImpl->aPaths.empty() )
166         {
167             Paths::const_iterator aCurrentPathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
168             if ( aCurrentPathPos == m_pImpl->aPaths.end() )
169                 return "RoadmapWizard::checkInvariants: invalid active path!";
170 
171             if ( -1 == m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath ) )
172                 return "RoadmapWizard::checkInvariants: the current state is not part of the current path!";
173         }
174 
175         return NULL;
176     }
177 #endif
178 
179     //--------------------------------------------------------------------
180     RoadmapWizard::RoadmapWizard( Window* _pParent, const ResId& _rRes, sal_uInt32 _nButtonFlags )
181         :OWizardMachine( _pParent, _rRes, _nButtonFlags )
182         ,m_pImpl( new RoadmapWizardImpl )
183     {
184         DBG_CTOR( RoadmapWizard, CheckInvariants );
185         impl_construct();
186     }
187 
188     //--------------------------------------------------------------------
189     RoadmapWizard::RoadmapWizard( Window* _pParent, const WinBits i_nStyle, sal_uInt32 _nButtonFlags )
190         :OWizardMachine( _pParent, i_nStyle, _nButtonFlags )
191         ,m_pImpl( new RoadmapWizardImpl )
192     {
193         DBG_CTOR( RoadmapWizard, CheckInvariants );
194         impl_construct();
195     }
196 
197     //--------------------------------------------------------------------
198     void RoadmapWizard::impl_construct()
199     {
200         SetLeftAlignedButtonCount( 1 );
201         SetEmptyViewMargin();
202 
203         m_pImpl->pRoadmap = new ORoadmap( this, WB_TABSTOP );
204         m_pImpl->pRoadmap->SetText( SvtResId( STR_WIZDLG_ROADMAP_TITLE ) );
205         m_pImpl->pRoadmap->SetPosPixel( Point( 0, 0 ) );
206         m_pImpl->pRoadmap->SetItemSelectHdl( LINK( this, RoadmapWizard, OnRoadmapItemSelected ) );
207 
208         Size aRoadmapSize =( LogicToPixel( Size( 85, 0 ), MAP_APPFONT ) );
209         aRoadmapSize.Height() = GetSizePixel().Height();
210         m_pImpl->pRoadmap->SetSizePixel( aRoadmapSize );
211 
212         m_pImpl->pFixedLine = new FixedLine( this, WB_VERT );
213         m_pImpl->pFixedLine->Show();
214         m_pImpl->pFixedLine->SetPosPixel( Point( aRoadmapSize.Width() + 1, 0 ) );
215         m_pImpl->pFixedLine->SetSizePixel( Size( LogicToPixel( Size( 2, 0 ) ).Width(), aRoadmapSize.Height() ) );
216 
217         SetViewWindow( m_pImpl->pRoadmap );
218         SetViewAlign( WINDOWALIGN_LEFT );
219         m_pImpl->pRoadmap->Show();
220     }
221 
222     //--------------------------------------------------------------------
223     RoadmapWizard::~RoadmapWizard()
224     {
225         delete m_pImpl;
226         DBG_DTOR( RoadmapWizard, CheckInvariants );
227     }
228 
229     //--------------------------------------------------------------------
230     void RoadmapWizard::SetRoadmapBitmap( const BitmapEx& _rBitmap )
231     {
232         m_pImpl->pRoadmap->SetRoadmapBitmap( _rBitmap );
233     }
234 
235     //--------------------------------------------------------------------
236     const BitmapEx&	RoadmapWizard::GetRoadmapBitmap( ) const
237     {
238         return m_pImpl->pRoadmap->GetRoadmapBitmap();
239     }
240 
241     //--------------------------------------------------------------------
242     void RoadmapWizard::SetRoadmapHelpId( const rtl::OString& _rId )
243     {
244         m_pImpl->pRoadmap->SetHelpId( _rId );
245     }
246 
247     //--------------------------------------------------------------------
248     const rtl::OString& RoadmapWizard::GetRoadmapHelpId() const
249     {
250         return m_pImpl->pRoadmap->GetHelpId();
251     }
252 
253     //--------------------------------------------------------------------
254     void RoadmapWizard::SetRoadmapInteractive( sal_Bool _bInteractive )
255     {
256         m_pImpl->pRoadmap->SetRoadmapInteractive( _bInteractive );
257     }
258 
259     //--------------------------------------------------------------------
260     sal_Bool RoadmapWizard::IsRoadmapInteractive()
261     {
262         return m_pImpl->pRoadmap->IsRoadmapInteractive();
263     }
264 
265     //--------------------------------------------------------------------
266     void RoadmapWizard::declarePath( PathId _nPathId, const WizardPath& _lWizardStates)
267     {
268         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
269 
270         m_pImpl->aPaths.insert( Paths::value_type( _nPathId, _lWizardStates ) );
271 
272         if ( m_pImpl->aPaths.size() == 1 )
273             // the very first path -> activate it
274             activatePath( _nPathId, false );
275         else
276             implUpdateRoadmap( );
277     }
278 
279     //--------------------------------------------------------------------
280     void RoadmapWizard::declarePath( PathId _nPathId, WizardState _nFirstState, ... )
281     {
282         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
283 
284         DBG_ASSERT( _nFirstState != WZS_INVALID_STATE, "RoadmapWizard::declarePath: there should be at least one state in the path!" );
285         if ( _nFirstState == WZS_INVALID_STATE )
286             return;
287 
288         WizardPath aNewPath;
289 
290         // collect the elements of the path
291         va_list aStateList;
292         va_start( aStateList, _nFirstState );
293 
294         WizardState nState = _nFirstState;
295         while ( nState != WZS_INVALID_STATE )
296         {
297             aNewPath.push_back( nState );
298             nState = sal::static_int_cast< WizardState >(
299                 va_arg( aStateList, int ));
300         }
301         va_end( aStateList );
302 
303         DBG_ASSERT( _nFirstState == 0, "RoadmapWizard::declarePath: first state must be NULL." );
304             // The WizardDialog (our very base class) always starts with a mnCurLevel == 0
305 
306         declarePath( _nPathId, aNewPath );
307     }
308 
309     //--------------------------------------------------------------------
310     void RoadmapWizard::describeState( WizardState _nState, const String& _rStateDisplayName, RoadmapPageFactory _pPageFactory )
311     {
312         OSL_ENSURE( m_pImpl->aStateDescriptors.find( _nState ) == m_pImpl->aStateDescriptors.end(),
313             "RoadmapWizard::describeState: there already is a descriptor for this state!" );
314         m_pImpl->aStateDescriptors[ _nState ] = StateDescriptions::mapped_type( _rStateDisplayName, _pPageFactory );
315     }
316 
317     //--------------------------------------------------------------------
318     void RoadmapWizard::activatePath( PathId _nPathId, bool _bDecideForIt )
319     {
320         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
321 
322         if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) )
323             // nothing to do
324             return;
325 
326         // does the given path exist?
327         Paths::const_iterator aNewPathPos = m_pImpl->aPaths.find( _nPathId );
328         DBG_ASSERT( aNewPathPos != m_pImpl->aPaths.end(), "RoadmapWizard::activate: there is no such path!" );
329         if ( aNewPathPos == m_pImpl->aPaths.end() )
330             return;
331 
332         // determine the index of the current state in the current path
333         sal_Int32 nCurrentStatePathIndex = -1;
334         if ( m_pImpl->nActivePath != -1 )
335             nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
336 
337         DBG_ASSERT( (sal_Int32)aNewPathPos->second.size() > nCurrentStatePathIndex,
338             "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
339             // If this asserts, this for instance means that we are already in state number, say, 5
340             // of our current path, and the caller tries to activate a path which has less than 5
341             // states
342         if ( (sal_Int32)aNewPathPos->second.size() <= nCurrentStatePathIndex )
343             return;
344 
345         // assert that the current and the new path are equal, up to nCurrentStatePathIndex
346         Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
347         if ( aActivePathPos != m_pImpl->aPaths.end() )
348 		{
349             if ( m_pImpl->getFirstDifferentIndex( aActivePathPos->second, aNewPathPos->second ) <= nCurrentStatePathIndex )
350             {
351                 OSL_ENSURE( false, "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
352                 return;
353             }
354 		}
355 
356         m_pImpl->nActivePath = _nPathId;
357         m_pImpl->bActivePathIsDefinite = _bDecideForIt;
358 
359         implUpdateRoadmap( );
360     }
361 
362     //--------------------------------------------------------------------
363     void RoadmapWizard::implUpdateRoadmap( )
364     {
365         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
366 
367         DBG_ASSERT( m_pImpl->aPaths.find( m_pImpl->nActivePath ) != m_pImpl->aPaths.end(),
368             "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
369         const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
370 
371         sal_Int32 nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), rActivePath );
372 
373         // determine up to which index (in the new path) we have to display the items
374         RoadmapTypes::ItemIndex nUpperStepBoundary = (RoadmapTypes::ItemIndex)rActivePath.size();
375         sal_Bool bIncompletePath = sal_False;
376         if ( !m_pImpl->bActivePathIsDefinite )
377         {
378             for ( Paths::const_iterator aPathPos = m_pImpl->aPaths.begin();
379                   aPathPos != m_pImpl->aPaths.end();
380                   ++aPathPos
381                 )
382             {
383                 if ( aPathPos->first == m_pImpl->nActivePath )
384                     // it's the path we are just activating -> no need to check anything
385                     continue;
386                 // the index from which on both paths differ
387                 sal_Int32 nDivergenceIndex = m_pImpl->getFirstDifferentIndex( rActivePath, aPathPos->second );
388                 if ( nDivergenceIndex <= nCurrentStatePathIndex )
389                     // they differ in an index which we have already left behind us
390                     // -> this is no conflict anymore
391                     continue;
392 
393                 // the path conflicts with our new path -> don't activate the
394                 // *complete* new path, but only up to the step which is unambiguous
395                 nUpperStepBoundary = nDivergenceIndex;
396                 bIncompletePath = sal_True;
397             }
398         }
399 
400         // can we advance from the current page?
401         bool bCurrentPageCanAdvance = true;
402         TabPage* pCurrentPage = GetPage( getCurrentState() );
403         if ( pCurrentPage )
404         {
405             const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
406             OSL_ENSURE( pController != NULL, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
407             bCurrentPageCanAdvance = !pController || pController->canAdvance();
408         }
409 
410         // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
411         // path, up to (excluding) nUpperStepBoundary
412         RoadmapTypes::ItemIndex nLoopUntil = ::std::max( (RoadmapTypes::ItemIndex)nUpperStepBoundary, m_pImpl->pRoadmap->GetItemCount() );
413         for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
414         {
415             bool bExistentItem = ( nItemIndex < m_pImpl->pRoadmap->GetItemCount() );
416             bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
417 
418             bool bInsertItem = false;
419             if ( bExistentItem )
420             {
421                 if ( !bNeedItem )
422                 {
423                     while ( nItemIndex < m_pImpl->pRoadmap->GetItemCount() )
424                         m_pImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
425                     break;
426                 }
427                 else
428                 {
429                     // there is an item with this index in the roadmap - does it match what is requested by
430                     // the respective state in the active path?
431                     RoadmapTypes::ItemId nPresentItemId = m_pImpl->pRoadmap->GetItemID( nItemIndex );
432                     WizardState nRequiredState = rActivePath[ nItemIndex ];
433                     if ( nPresentItemId != nRequiredState )
434                     {
435                         m_pImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
436                         bInsertItem = true;
437                     }
438                 }
439             }
440             else
441             {
442                 DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
443                 bInsertItem = bNeedItem;
444             }
445 
446             WizardState nState( rActivePath[ nItemIndex ] );
447             if ( bInsertItem )
448             {
449                 m_pImpl->pRoadmap->InsertRoadmapItem(
450                     nItemIndex,
451                     getStateDisplayName( nState ),
452                     nState
453                 );
454             }
455 
456             // if the item is *after* the current state, but the current page does not
457             // allow advancing, the disable the state. This relieves derived classes
458             // from disabling all future states just because the current state does not
459             // (yet) allow advancing.
460             const bool nUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex );
461             const bool bEnable = !nUnconditionedDisable && ( m_pImpl->aDisabledStates.find( nState ) == m_pImpl->aDisabledStates.end() );
462 
463             m_pImpl->pRoadmap->EnableRoadmapItem( m_pImpl->pRoadmap->GetItemID( nItemIndex ), bEnable );
464         }
465 
466         m_pImpl->pRoadmap->SetRoadmapComplete( !bIncompletePath );
467     }
468 
469     //--------------------------------------------------------------------
470     WizardTypes::WizardState RoadmapWizard::determineNextState( WizardState _nCurrentState ) const
471     {
472         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
473 
474         sal_Int32 nCurrentStatePathIndex = -1;
475 
476         Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
477         if ( aActivePathPos != m_pImpl->aPaths.end() )
478             nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( _nCurrentState, aActivePathPos->second );
479 
480         DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
481         if ( nCurrentStatePathIndex == -1 )
482             return WZS_INVALID_STATE;
483 
484         sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
485 
486         while   (   ( nNextStateIndex < (sal_Int32)aActivePathPos->second.size() )
487                 &&  ( m_pImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_pImpl->aDisabledStates.end() )
488                 )
489         {
490             ++nNextStateIndex;
491         }
492 
493         if ( nNextStateIndex >= (sal_Int32)aActivePathPos->second.size() )
494             // there is no next state in the current path (at least none which is enabled)
495             return WZS_INVALID_STATE;
496 
497         return aActivePathPos->second[ nNextStateIndex ];
498     }
499 
500 	//---------------------------------------------------------------------
501 	bool RoadmapWizard::canAdvance() const
502 	{
503         if ( !m_pImpl->bActivePathIsDefinite )
504         {
505             // check how many paths are still allowed
506             const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
507             sal_Int32 nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), rActivePath );
508 
509             size_t nPossiblePaths(0);
510             for (   Paths::const_iterator aPathPos = m_pImpl->aPaths.begin();
511                     aPathPos != m_pImpl->aPaths.end();
512                     ++aPathPos
513                 )
514             {
515                 // the index from which on both paths differ
516                 sal_Int32 nDivergenceIndex = m_pImpl->getFirstDifferentIndex( rActivePath, aPathPos->second );
517 
518                 if ( nDivergenceIndex > nCurrentStatePathIndex )
519                     // this path is still a possible path
520                     nPossiblePaths += 1;
521             }
522 
523             // if we have more than one path which is still possible, then we assume
524             // to always have a next state. Though there might be scenarios where this
525             // is not true, but this is too sophisticated (means not really needed) right now.
526             if ( nPossiblePaths > 1 )
527                 return true;
528         }
529 
530         const WizardPath& rPath = m_pImpl->aPaths[ m_pImpl->nActivePath ];
531         if ( *rPath.rbegin() == getCurrentState() )
532             return false;
533 
534         return true;
535 	}
536 
537     //---------------------------------------------------------------------
538     void RoadmapWizard::updateTravelUI()
539     {
540         OWizardMachine::updateTravelUI();
541 
542         // disable the "Previous" button if all states in our history are disabled
543         ::std::vector< WizardState > aHistory;
544         getStateHistory( aHistory );
545         bool bHaveEnabledState = false;
546         for (   ::std::vector< WizardState >::const_iterator state = aHistory.begin();
547                 state != aHistory.end() && !bHaveEnabledState;
548                 ++state
549             )
550         {
551             if ( isStateEnabled( *state ) )
552                 bHaveEnabledState = true;
553         }
554 
555         enableButtons( WZB_PREVIOUS, bHaveEnabledState );
556 
557         implUpdateRoadmap();
558     }
559 
560     //--------------------------------------------------------------------
561     IMPL_LINK( RoadmapWizard, OnRoadmapItemSelected, void*, EMPTYARG )
562     {
563         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
564 
565         RoadmapTypes::ItemId nCurItemId = m_pImpl->pRoadmap->GetCurrentRoadmapItemID();
566         if ( nCurItemId == getCurrentState() )
567             // nothing to do
568             return 1L;
569 
570         if ( isTravelingSuspended() )
571             return 0;
572 
573         WizardTravelSuspension aTravelGuard( *this );
574 
575         sal_Int32 nCurrentIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
576         sal_Int32 nNewIndex     = m_pImpl->getStateIndexInPath( nCurItemId, m_pImpl->nActivePath );
577 
578         DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
579             "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
580         if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
581         {
582             return 0L;
583         }
584 
585         sal_Bool bResult = sal_True;
586         if ( nNewIndex > nCurrentIndex )
587         {
588             bResult = skipUntil( (WizardState)nCurItemId );
589             WizardState nTemp = (WizardState)nCurItemId;
590             while( nTemp )
591             {
592                 if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() )
593                     removePageFromHistory( nTemp );
594             }
595         }
596         else
597             bResult = skipBackwardUntil( (WizardState)nCurItemId );
598 
599         if ( !bResult )
600             m_pImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
601 
602         return 1L;
603     }
604 
605     //--------------------------------------------------------------------
606     void RoadmapWizard::enterState( WizardState _nState )
607     {
608         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
609 
610         OWizardMachine::enterState( _nState );
611 
612         // synchronize the roadmap
613         implUpdateRoadmap( );
614         m_pImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
615     }
616 
617     //--------------------------------------------------------------------
618     String RoadmapWizard::getStateDisplayName( WizardState _nState ) const
619     {
620         String sDisplayName;
621 
622         StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState );
623         OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(),
624             "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
625         if ( pos != m_pImpl->aStateDescriptors.end() )
626             sDisplayName = pos->second.first;
627 
628         return sDisplayName;
629     }
630 
631     //--------------------------------------------------------------------
632     TabPage* RoadmapWizard::createPage( WizardState _nState )
633     {
634         TabPage* pPage( NULL );
635 
636         StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState );
637         OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(),
638             "RoadmapWizard::createPage: no default implementation available for this state!" );
639         if ( pos != m_pImpl->aStateDescriptors.end() )
640         {
641             RoadmapPageFactory pFactory = pos->second.second;
642             pPage = (*pFactory)( *this );
643         }
644 
645         return pPage;
646     }
647 
648     //--------------------------------------------------------------------
649     void RoadmapWizard::enableState( WizardState _nState, bool _bEnable )
650     {
651         DBG_CHKTHIS( RoadmapWizard, CheckInvariants );
652 
653         // remember this (in case the state appears in the roadmap later on)
654         if ( _bEnable )
655             m_pImpl->aDisabledStates.erase( _nState );
656         else
657         {
658             m_pImpl->aDisabledStates.insert( _nState );
659             removePageFromHistory( _nState );
660         }
661 
662         // if the state is currently in the roadmap, reflect it's new status
663         m_pImpl->pRoadmap->EnableRoadmapItem( (RoadmapTypes::ItemId)_nState, _bEnable );
664     }
665 
666     //--------------------------------------------------------------------
667     bool RoadmapWizard::knowsState( WizardState i_nState ) const
668     {
669         for (   Paths::const_iterator path = m_pImpl->aPaths.begin();
670                 path != m_pImpl->aPaths.end();
671                 ++path
672             )
673         {
674             for (   WizardPath::const_iterator state = path->second.begin();
675                     state != path->second.end();
676                     ++state
677                 )
678             {
679                 if ( *state == i_nState )
680                     return true;
681             }
682         }
683         return false;
684     }
685 
686     //--------------------------------------------------------------------
687     bool RoadmapWizard::isStateEnabled( WizardState _nState ) const
688     {
689         return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end();
690     }
691 
692     //--------------------------------------------------------------------
693     void RoadmapWizard::Resize()
694     {
695         OWizardMachine::Resize();
696 
697         if ( IsReallyShown() && !IsInInitShow() )
698             ResizeFixedLine();
699     }
700 
701 
702 	//--------------------------------------------------------------------
703 	void RoadmapWizard::StateChanged( StateChangedType nType )
704 	{
705 		WizardDialog::StateChanged( nType );
706 
707         if ( nType == STATE_CHANGE_INITSHOW )
708             ResizeFixedLine();
709 	}
710 
711 	//--------------------------------------------------------------------
712     void RoadmapWizard::ResizeFixedLine()
713     {
714         Size aSize( m_pImpl->pRoadmap->GetSizePixel() );
715         aSize.Width() = m_pImpl->pFixedLine->GetSizePixel().Width();
716         m_pImpl->pFixedLine->SetSizePixel( aSize );
717     }
718 
719 	//--------------------------------------------------------------------
720     void RoadmapWizard::updateRoadmapItemLabel( WizardState _nState )
721     {
722         const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
723         RoadmapTypes::ItemIndex nUpperStepBoundary = (RoadmapTypes::ItemIndex)rActivePath.size();
724         RoadmapTypes::ItemIndex nLoopUntil = ::std::max( (RoadmapTypes::ItemIndex)nUpperStepBoundary, m_pImpl->pRoadmap->GetItemCount() );
725         sal_Int32 nCurrentStatePathIndex = -1;
726         if ( m_pImpl->nActivePath != -1 )
727             nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
728         for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
729         {
730             bool bExistentItem = ( nItemIndex < m_pImpl->pRoadmap->GetItemCount() );
731             if ( bExistentItem )
732             {
733                 // there is an item with this index in the roadmap - does it match what is requested by
734                 // the respective state in the active path?
735                 RoadmapTypes::ItemId nPresentItemId = m_pImpl->pRoadmap->GetItemID( nItemIndex );
736                 WizardState nRequiredState = rActivePath[ nItemIndex ];
737                 if ( _nState == nRequiredState )
738                 {
739                     m_pImpl->pRoadmap->ChangeRoadmapItemLabel( nPresentItemId, getStateDisplayName( nRequiredState ) );
740                     break;
741                 }
742             }
743         }
744     }
745 
746 //........................................................................
747 }   // namespace svt
748 //........................................................................
749