1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <vcl/toolkit/roadmap.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/json_writer.hxx>
24 #include <osl/diagnose.h>
26 #include <strings.hrc>
32 #include "wizimpldata.hxx"
33 #include <uiobject-internal.hxx>
37 sal_Int32
RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState
, const WizardPath
& _rPath
)
39 sal_Int32 nStateIndexInPath
= 0;
41 for (auto const& path
: _rPath
)
51 nStateIndexInPath
= -1;
52 return nStateIndexInPath
;
56 sal_Int32
RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState
, PathId _nPathId
)
58 sal_Int32 nStateIndexInPath
= -1;
59 Paths::const_iterator aPathPos
= aPaths
.find( _nPathId
);
60 if ( aPathPos
!= aPaths
.end( ) )
61 nStateIndexInPath
= getStateIndexInPath( _nState
, aPathPos
->second
);
62 return nStateIndexInPath
;
66 sal_Int32
RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath
& _rLHS
, const WizardPath
& _rRHS
)
68 sal_Int32 nMinLength
= ::std::min( _rLHS
.size(), _rRHS
.size() );
69 for ( sal_Int32 nCheck
= 0; nCheck
< nMinLength
; ++nCheck
)
71 if ( _rLHS
[ nCheck
] != _rRHS
[ nCheck
] )
78 RoadmapWizard::RoadmapWizard(vcl::Window
* pParent
, WinBits nStyle
, InitFlag eFlag
)
79 : Dialog(pParent
, nStyle
, eFlag
)
80 , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
83 , m_pNextPage(nullptr)
84 , m_pPrevPage(nullptr)
86 , m_xWizardImpl(new WizardMachineImplData
)
87 , m_xRoadmapImpl(new RoadmapWizardImpl
)
89 mpFirstPage
= nullptr;
91 mpCurTabPage
= nullptr;
94 mpViewWindow
= nullptr;
96 mbEmptyViewMargin
= false;
99 maWizardLayoutIdle
.SetPriority(TaskPriority::RESIZE
);
100 maWizardLayoutIdle
.SetInvokeHandler( LINK( this, RoadmapWizard
, ImplHandleWizardLayoutTimerHdl
) );
102 implConstruct(WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
);
104 SetLeftAlignedButtonCount( 1 );
105 mbEmptyViewMargin
= true;
107 m_xRoadmapImpl
->pRoadmap
.disposeAndReset( VclPtr
<ORoadmap
>::Create( this, WB_TABSTOP
) );
108 m_xRoadmapImpl
->pRoadmap
->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE
) );
109 m_xRoadmapImpl
->pRoadmap
->SetPosPixel( Point( 0, 0 ) );
110 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl( LINK( this, RoadmapWizard
, OnRoadmapItemSelected
) );
112 Size aRoadmapSize
= LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont
));
113 aRoadmapSize
.setHeight( GetSizePixel().Height() );
114 m_xRoadmapImpl
->pRoadmap
->SetSizePixel( aRoadmapSize
);
116 mpViewWindow
= m_xRoadmapImpl
->pRoadmap
;
117 m_xRoadmapImpl
->pRoadmap
->Show();
120 RoadmapWizardMachine::RoadmapWizardMachine(weld::Window
* pParent
)
121 : WizardMachine(pParent
, WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
)
122 , m_pImpl( new RoadmapWizardImpl
)
124 m_xAssistant
->connect_jump_page(LINK(this, RoadmapWizardMachine
, OnRoadmapItemSelected
));
127 void RoadmapWizard::ShowRoadmap(bool bShow
)
129 m_xRoadmapImpl
->pRoadmap
->Show(bShow
);
133 RoadmapWizard::~RoadmapWizard()
138 RoadmapWizardMachine::~RoadmapWizardMachine()
142 void RoadmapWizard::dispose()
144 m_xRoadmapImpl
.reset();
146 m_pFinish
.disposeAndClear();
147 m_pCancel
.disposeAndClear();
148 m_pNextPage
.disposeAndClear();
149 m_pPrevPage
.disposeAndClear();
150 m_pHelp
.disposeAndClear();
154 for (WizardTypes::WizardState i
= 0; i
< m_xWizardImpl
->nFirstUnknownPage
; ++i
)
156 TabPage
*pPage
= GetPage(i
);
158 pPage
->disposeOnce();
160 m_xWizardImpl
.reset();
163 maWizardLayoutIdle
.Stop();
165 // Remove all buttons
167 RemoveButton( mpFirstBtn
->mpButton
);
170 while ( mpFirstPage
)
171 RemovePage( mpFirstPage
->mpPage
);
173 mpCurTabPage
.clear();
176 mpViewWindow
.clear();
180 void RoadmapWizard::SetRoadmapHelpId( const OUString
& _rId
)
182 m_xRoadmapImpl
->pRoadmap
->SetHelpId( _rId
);
185 void RoadmapWizard::SetRoadmapBitmap(const BitmapEx
& rBmp
)
187 m_xRoadmapImpl
->pRoadmap
->SetRoadmapBitmap(rBmp
);
190 void RoadmapWizardMachine::SetRoadmapHelpId(const OUString
& rId
)
192 m_xAssistant
->set_page_side_help_id(rId
);
195 void RoadmapWizardMachine::declarePath( PathId _nPathId
, const WizardPath
& _lWizardStates
)
197 m_pImpl
->aPaths
.emplace( _nPathId
, _lWizardStates
);
199 if ( m_pImpl
->aPaths
.size() == 1 )
200 // the very first path -> activate it
201 activatePath( _nPathId
);
203 implUpdateRoadmap( );
206 void RoadmapWizardMachine::activatePath( PathId _nPathId
, bool _bDecideForIt
)
208 if ( ( _nPathId
== m_pImpl
->nActivePath
) && ( _bDecideForIt
== m_pImpl
->bActivePathIsDefinite
) )
212 // does the given path exist?
213 Paths::const_iterator aNewPathPos
= m_pImpl
->aPaths
.find( _nPathId
);
214 DBG_ASSERT( aNewPathPos
!= m_pImpl
->aPaths
.end(), "RoadmapWizard::activate: there is no such path!" );
215 if ( aNewPathPos
== m_pImpl
->aPaths
.end() )
218 // determine the index of the current state in the current path
219 sal_Int32 nCurrentStatePathIndex
= -1;
220 if ( m_pImpl
->nActivePath
!= -1 )
221 nCurrentStatePathIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
223 DBG_ASSERT( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) > nCurrentStatePathIndex
,
224 "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
225 // If this asserts, this for instance means that we are already in state number, say, 5
226 // of our current path, and the caller tries to activate a path which has less than 5
228 if ( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) <= nCurrentStatePathIndex
)
231 // assert that the current and the new path are equal, up to nCurrentStatePathIndex
232 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
233 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
235 if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos
->second
, aNewPathPos
->second
) <= nCurrentStatePathIndex
)
237 OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
242 m_pImpl
->nActivePath
= _nPathId
;
243 m_pImpl
->bActivePathIsDefinite
= _bDecideForIt
;
245 implUpdateRoadmap( );
248 void RoadmapWizard::implUpdateRoadmap( )
250 DBG_ASSERT( m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
) != m_xRoadmapImpl
->aPaths
.end(),
251 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
252 const WizardPath
& rActivePath( m_xRoadmapImpl
->aPaths
[ m_xRoadmapImpl
->nActivePath
] );
254 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
255 if (nCurrentStatePathIndex
< 0)
258 // determine up to which index (in the new path) we have to display the items
259 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
260 bool bIncompletePath
= false;
261 if ( !m_xRoadmapImpl
->bActivePathIsDefinite
)
263 for (auto const& path
: m_xRoadmapImpl
->aPaths
)
265 if ( path
.first
== m_xRoadmapImpl
->nActivePath
)
266 // it's the path we are just activating -> no need to check anything
268 // the index from which on both paths differ
269 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
270 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
271 // they differ in an index which we have already left behind us
272 // -> this is no conflict anymore
275 // the path conflicts with our new path -> don't activate the
276 // *complete* new path, but only up to the step which is unambiguous
277 nUpperStepBoundary
= nDivergenceIndex
;
278 bIncompletePath
= true;
282 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
283 // path, up to (excluding) nUpperStepBoundary
284 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
285 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
287 bool bExistentItem
= ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
288 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
290 bool bInsertItem
= false;
295 while ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() )
296 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
301 // there is an item with this index in the roadmap - does it match what is requested by
302 // the respective state in the active path?
303 RoadmapTypes::ItemId nPresentItemId
= m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
);
304 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
305 if ( nPresentItemId
!= nRequiredState
)
307 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
314 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
315 bInsertItem
= bNeedItem
;
318 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
321 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(
323 getStateDisplayName( nState
),
329 const bool bEnable
= m_xRoadmapImpl
->aDisabledStates
.find( nState
) == m_xRoadmapImpl
->aDisabledStates
.end();
330 m_xRoadmapImpl
->pRoadmap
->EnableRoadmapItem( m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
), bEnable
);
333 m_xRoadmapImpl
->pRoadmap
->SetRoadmapComplete( !bIncompletePath
);
336 void RoadmapWizardMachine::implUpdateRoadmap( )
339 DBG_ASSERT( m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
) != m_pImpl
->aPaths
.end(),
340 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
341 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
343 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
344 if (nCurrentStatePathIndex
< 0)
347 // determine up to which index (in the new path) we have to display the items
348 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
349 if ( !m_pImpl
->bActivePathIsDefinite
)
351 for (auto const& path
: m_pImpl
->aPaths
)
353 if ( path
.first
== m_pImpl
->nActivePath
)
354 // it's the path we are just activating -> no need to check anything
356 // the index from which on both paths differ
357 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
358 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
359 // they differ in an index which we have already left behind us
360 // -> this is no conflict anymore
363 // the path conflicts with our new path -> don't activate the
364 // *complete* new path, but only up to the step which is unambiguous
365 nUpperStepBoundary
= nDivergenceIndex
;
369 // can we advance from the current page?
370 bool bCurrentPageCanAdvance
= true;
371 BuilderPage
* pCurrentPage
= GetPage( getCurrentState() );
374 const IWizardPageController
* pController
= getPageController( GetPage( getCurrentState() ) );
375 OSL_ENSURE( pController
!= nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
376 bCurrentPageCanAdvance
= !pController
|| pController
->canAdvance();
379 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
380 // path, up to (excluding) nUpperStepBoundary
381 RoadmapTypes::ItemIndex nRoadmapItems
= m_xAssistant
->get_n_pages();
382 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, nRoadmapItems
);
383 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
385 bool bExistentItem
= ( nItemIndex
< nRoadmapItems
);
386 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
388 bool bInsertItem
= false;
393 int nPages
= nRoadmapItems
;
394 for (int i
= nPages
- 1; i
>= nItemIndex
; --i
)
396 m_xAssistant
->set_page_title(m_xAssistant
->get_page_ident(i
), "");
403 // there is an item with this index in the roadmap - does it match what is requested by
404 // the respective state in the active path?
405 RoadmapTypes::ItemId nPresentItemId
= m_xAssistant
->get_page_ident(nItemIndex
).toInt32();
406 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
407 if ( nPresentItemId
!= nRequiredState
)
409 m_xAssistant
->set_page_title(OUString::number(nPresentItemId
), "");
416 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
417 bInsertItem
= bNeedItem
;
420 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
424 GetOrCreatePage(nState
);
427 OUString
sIdent(getPageIdentForState(nState
));
428 m_xAssistant
->set_page_index(sIdent
, nItemIndex
);
429 m_xAssistant
->set_page_title(sIdent
, getStateDisplayName(nState
));
431 // if the item is *after* the current state, but the current page does not
432 // allow advancing, the disable the state. This relieves derived classes
433 // from disabling all future states just because the current state does not
434 // (yet) allow advancing.
435 const bool bUnconditionedDisable
= !bCurrentPageCanAdvance
&& ( nItemIndex
> nCurrentStatePathIndex
);
436 const bool bEnable
= !bUnconditionedDisable
&& ( m_pImpl
->aDisabledStates
.find( nState
) == m_pImpl
->aDisabledStates
.end() );
437 m_xAssistant
->set_page_sensitive(sIdent
, bEnable
);
441 WizardTypes::WizardState
RoadmapWizard::determineNextState( WizardTypes::WizardState _nCurrentState
) const
443 sal_Int32 nCurrentStatePathIndex
= -1;
445 Paths::const_iterator aActivePathPos
= m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
);
446 if ( aActivePathPos
!= m_xRoadmapImpl
->aPaths
.end() )
447 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
449 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
450 if ( nCurrentStatePathIndex
== -1 )
451 return WZS_INVALID_STATE
;
453 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
455 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
456 && ( m_xRoadmapImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_xRoadmapImpl
->aDisabledStates
.end() )
462 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
463 // there is no next state in the current path (at least none which is enabled)
464 return WZS_INVALID_STATE
;
466 return aActivePathPos
->second
[ nNextStateIndex
];
469 WizardTypes::WizardState
RoadmapWizardMachine::determineNextState( WizardTypes::WizardState _nCurrentState
) const
471 sal_Int32 nCurrentStatePathIndex
= -1;
473 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
474 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
475 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
477 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
478 if ( nCurrentStatePathIndex
== -1 )
479 return WZS_INVALID_STATE
;
481 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
483 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
484 && ( m_pImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_pImpl
->aDisabledStates
.end() )
490 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
491 // there is no next state in the current path (at least none which is enabled)
492 return WZS_INVALID_STATE
;
494 return aActivePathPos
->second
[ nNextStateIndex
];
497 bool RoadmapWizardMachine::canAdvance() const
499 if ( !m_pImpl
->bActivePathIsDefinite
)
501 // check how many paths are still allowed
502 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
504 // if current path has only the base item, it is not possible to proceed without activating another path
505 if(rActivePath
.size()<=1)
508 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
510 size_t nPossiblePaths(0);
511 for (auto const& path
: m_pImpl
->aPaths
)
513 // the index from which on both paths differ
514 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
516 if ( nDivergenceIndex
> nCurrentStatePathIndex
)
517 // this path is still a possible path
521 // if we have more than one path which is still possible, then we assume
522 // to always have a next state. Though there might be scenarios where this
523 // is not true, but this is too sophisticated (means not really needed) right now.
524 if ( nPossiblePaths
> 1 )
528 const WizardPath
& rPath
= m_pImpl
->aPaths
[ m_pImpl
->nActivePath
];
529 return *rPath
.rbegin() != getCurrentState();
532 void RoadmapWizardMachine::updateTravelUI()
534 WizardMachine::updateTravelUI();
536 // disable the "Previous" button if all states in our history are disabled
537 std::vector
< WizardTypes::WizardState
> aHistory
;
538 getStateHistory( aHistory
);
539 bool bHaveEnabledState
= false;
540 for (auto const& state
: aHistory
)
542 if ( isStateEnabled(state
) )
544 bHaveEnabledState
= true;
549 enableButtons( WizardButtonFlags::PREVIOUS
, bHaveEnabledState
);
554 IMPL_LINK_NOARG(RoadmapWizard
, OnRoadmapItemSelected
, LinkParamNone
*, void)
556 RoadmapTypes::ItemId nCurItemId
= m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
557 if ( nCurItemId
== getCurrentState() )
561 if ( isTravelingSuspended() )
564 RoadmapWizardTravelSuspension
aTravelGuard( *this );
566 sal_Int32 nCurrentIndex
= m_xRoadmapImpl
->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl
->nActivePath
);
567 sal_Int32 nNewIndex
= m_xRoadmapImpl
->getStateIndexInPath( nCurItemId
, m_xRoadmapImpl
->nActivePath
);
569 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
570 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
571 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
577 if ( nNewIndex
> nCurrentIndex
)
579 bResult
= skipUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
580 WizardTypes::WizardState nTemp
= static_cast<WizardTypes::WizardState
>(nCurItemId
);
583 if( m_xRoadmapImpl
->aDisabledStates
.find( --nTemp
) != m_xRoadmapImpl
->aDisabledStates
.end() )
584 removePageFromHistory( nTemp
);
588 bResult
= skipBackwardUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
591 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
594 IMPL_LINK(RoadmapWizardMachine
, OnRoadmapItemSelected
, const OUString
&, rCurItemId
, bool)
596 WizardTypes::WizardState nSelectedState
= getStateFromPageIdent(rCurItemId
);
598 if (nSelectedState
== getCurrentState())
602 if ( isTravelingSuspended() )
605 WizardTravelSuspension
aTravelGuard( *this );
607 sal_Int32 nCurrentIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
608 sal_Int32 nNewIndex
= m_pImpl
->getStateIndexInPath( nSelectedState
, m_pImpl
->nActivePath
);
610 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
611 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
612 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
618 if ( nNewIndex
> nCurrentIndex
)
620 bResult
= skipUntil(nSelectedState
);
621 WizardTypes::WizardState nTemp
= nSelectedState
;
624 if( m_pImpl
->aDisabledStates
.find( --nTemp
) != m_pImpl
->aDisabledStates
.end() )
625 removePageFromHistory( nTemp
);
629 bResult
= skipBackwardUntil(nSelectedState
);
634 void RoadmapWizard::enterState(WizardTypes::WizardState
/*nState*/)
636 // synchronize the roadmap
637 implUpdateRoadmap( );
638 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
641 void RoadmapWizardMachine::enterState( WizardTypes::WizardState _nState
)
643 WizardMachine::enterState( _nState
);
645 // synchronize the roadmap
649 OUString
RoadmapWizard::getStateDisplayName( WizardTypes::WizardState _nState
) const
651 OUString sDisplayName
;
653 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
654 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
655 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
656 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
657 sDisplayName
= pos
->second
.first
;
662 OUString
RoadmapWizardMachine::getStateDisplayName( WizardTypes::WizardState _nState
) const
664 OUString sDisplayName
;
666 StateDescriptions::const_iterator pos
= m_pImpl
->aStateDescriptors
.find( _nState
);
667 OSL_ENSURE( pos
!= m_pImpl
->aStateDescriptors
.end(),
668 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
669 if ( pos
!= m_pImpl
->aStateDescriptors
.end() )
670 sDisplayName
= pos
->second
.first
;
675 VclPtr
<TabPage
> RoadmapWizard::createPage( WizardTypes::WizardState _nState
)
677 VclPtr
<TabPage
> pPage
;
679 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
680 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
681 "RoadmapWizard::createPage: no default implementation available for this state!" );
682 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
684 RoadmapPageFactory pFactory
= pos
->second
.second
;
685 pPage
= (*pFactory
)( *this );
691 void RoadmapWizardMachine::enableState( WizardTypes::WizardState _nState
, bool _bEnable
)
693 // remember this (in case the state appears in the roadmap later on)
695 m_pImpl
->aDisabledStates
.erase( _nState
);
698 m_pImpl
->aDisabledStates
.insert( _nState
);
699 removePageFromHistory( _nState
);
702 // if the state is currently in the roadmap, reflect it's new status
703 m_xAssistant
->set_page_sensitive(getPageIdentForState(_nState
), _bEnable
);
706 bool RoadmapWizardMachine::knowsState( WizardTypes::WizardState i_nState
) const
708 for (auto const& path
: m_pImpl
->aPaths
)
710 for (auto const& state
: path
.second
)
712 if ( state
== i_nState
)
719 bool RoadmapWizardMachine::isStateEnabled( WizardTypes::WizardState _nState
) const
721 return m_pImpl
->aDisabledStates
.find( _nState
) == m_pImpl
->aDisabledStates
.end();
724 void RoadmapWizard::InsertRoadmapItem(int nItemIndex
, const OUString
& rText
, int nItemId
, bool bEnable
)
726 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(nItemIndex
, rText
, nItemId
, bEnable
);
729 void RoadmapWizard::SelectRoadmapItemByID(int nItemId
, bool bGrabFocus
)
731 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID(nItemId
, bGrabFocus
);
734 void RoadmapWizard::DeleteRoadmapItems()
736 while (m_xRoadmapImpl
->pRoadmap
->GetItemCount())
737 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem(0);
740 void RoadmapWizard::SetItemSelectHdl( const Link
<LinkParamNone
*,void>& _rHdl
)
742 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl(_rHdl
);
745 int RoadmapWizard::GetCurrentRoadmapItemID() const
747 return m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
750 FactoryFunction
RoadmapWizard::GetUITestFactory() const
752 return RoadmapWizardUIObject::create
;
757 bool isButton(WindowType eType
)
759 return eType
== WindowType::PUSHBUTTON
|| eType
== WindowType::OKBUTTON
760 || eType
== WindowType::CANCELBUTTON
|| eType
== WindowType::HELPBUTTON
;
764 void RoadmapWizard::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
766 rJsonWriter
.put("id", get_id());
767 rJsonWriter
.put("type", "dialog");
768 rJsonWriter
.put("title", GetText());
770 OUString sDialogId
= GetHelpId();
771 sal_Int32 nStartPos
= sDialogId
.lastIndexOf('/');
772 nStartPos
= nStartPos
>= 0 ? nStartPos
+ 1 : 0;
773 rJsonWriter
.put("dialogid", sDialogId
.copy(nStartPos
));
775 auto aResponses
= rJsonWriter
.startArray("responses");
776 for (const auto& rResponse
: m_xRoadmapImpl
->maResponses
)
778 auto aResponse
= rJsonWriter
.startStruct();
779 rJsonWriter
.put("id", rResponse
.first
->get_id());
780 rJsonWriter
.put("response", rResponse
.second
);
784 vcl::Window
* pFocusControl
= GetFirstControlForFocus();
786 rJsonWriter
.put("init_focus_id", pFocusControl
->get_id());
789 auto childrenNode
= rJsonWriter
.startArray("children");
791 auto containerNode
= rJsonWriter
.startStruct();
792 rJsonWriter
.put("id", "container");
793 rJsonWriter
.put("type", "container");
794 rJsonWriter
.put("vertical", true);
797 auto containerChildrenNode
= rJsonWriter
.startArray("children");
800 for (int i
= 0; i
< GetChildCount(); i
++)
802 vcl::Window
* pChild
= GetChild(i
);
804 if (!isButton(pChild
->GetType()) && pChild
!= mpViewWindow
)
806 auto childNode
= rJsonWriter
.startStruct();
807 pChild
->DumpAsPropertyTree(rJsonWriter
);
813 auto buttonsNode
= rJsonWriter
.startStruct();
814 rJsonWriter
.put("id", "buttons");
815 rJsonWriter
.put("type", "buttonbox");
816 rJsonWriter
.put("layoutstyle", "end");
818 auto buttonsChildrenNode
= rJsonWriter
.startArray("children");
819 for (int i
= 0; i
< GetChildCount(); i
++)
821 vcl::Window
* pChild
= GetChild(i
);
823 if (isButton(pChild
->GetType()))
825 auto childNode
= rJsonWriter
.startStruct();
826 pChild
->DumpAsPropertyTree(rJsonWriter
);
837 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */