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