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;
40 for (auto const& path
: _rPath
)
43 return nStateIndexInPath
;
49 sal_Int32
RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState
, PathId _nPathId
)
51 sal_Int32 nStateIndexInPath
= -1;
52 Paths::const_iterator aPathPos
= aPaths
.find( _nPathId
);
53 if ( aPathPos
!= aPaths
.end( ) )
54 nStateIndexInPath
= getStateIndexInPath( _nState
, aPathPos
->second
);
55 return nStateIndexInPath
;
58 sal_Int32
RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath
& _rLHS
, const WizardPath
& _rRHS
)
60 sal_Int32 nMinLength
= ::std::min( _rLHS
.size(), _rRHS
.size() );
61 for ( sal_Int32 nCheck
= 0; nCheck
< nMinLength
; ++nCheck
)
63 if ( _rLHS
[ nCheck
] != _rRHS
[ nCheck
] )
70 RoadmapWizard::RoadmapWizard(vcl::Window
* pParent
, WinBits nStyle
, InitFlag eFlag
)
71 : Dialog(pParent
, nStyle
, eFlag
)
72 , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
75 , m_pNextPage(nullptr)
76 , m_pPrevPage(nullptr)
78 , m_xWizardImpl(new WizardMachineImplData
)
79 , m_xRoadmapImpl(new RoadmapWizardImpl
)
81 mpFirstPage
= nullptr;
83 mpCurTabPage
= nullptr;
86 mpViewWindow
= nullptr;
88 mbEmptyViewMargin
= false;
91 maWizardLayoutIdle
.SetPriority(TaskPriority::RESIZE
);
92 maWizardLayoutIdle
.SetInvokeHandler( LINK( this, RoadmapWizard
, ImplHandleWizardLayoutTimerHdl
) );
94 implConstruct(WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
);
96 SetLeftAlignedButtonCount( 1 );
97 mbEmptyViewMargin
= true;
99 m_xRoadmapImpl
->pRoadmap
.disposeAndReset( VclPtr
<ORoadmap
>::Create( this, WB_TABSTOP
) );
100 m_xRoadmapImpl
->pRoadmap
->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE
) );
101 m_xRoadmapImpl
->pRoadmap
->SetPosPixel( Point( 0, 0 ) );
102 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl( LINK( this, RoadmapWizard
, OnRoadmapItemSelected
) );
104 Size aRoadmapSize
= LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont
));
105 aRoadmapSize
.setHeight( GetSizePixel().Height() );
106 m_xRoadmapImpl
->pRoadmap
->SetSizePixel( aRoadmapSize
);
108 mpViewWindow
= m_xRoadmapImpl
->pRoadmap
;
109 m_xRoadmapImpl
->pRoadmap
->Show();
112 RoadmapWizardMachine::RoadmapWizardMachine(weld::Window
* pParent
)
113 : WizardMachine(pParent
, WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
)
114 , m_pImpl( new RoadmapWizardImpl
)
116 m_xAssistant
->connect_jump_page(LINK(this, RoadmapWizardMachine
, OnRoadmapItemSelected
));
119 void RoadmapWizard::ShowRoadmap(bool bShow
)
121 m_xRoadmapImpl
->pRoadmap
->Show(bShow
);
125 RoadmapWizard::~RoadmapWizard()
130 RoadmapWizardMachine::~RoadmapWizardMachine()
134 void RoadmapWizard::dispose()
136 m_xRoadmapImpl
.reset();
138 m_pFinish
.disposeAndClear();
139 m_pCancel
.disposeAndClear();
140 m_pNextPage
.disposeAndClear();
141 m_pPrevPage
.disposeAndClear();
142 m_pHelp
.disposeAndClear();
146 for (WizardTypes::WizardState i
= 0; i
< m_xWizardImpl
->nFirstUnknownPage
; ++i
)
148 TabPage
*pPage
= GetPage(i
);
150 pPage
->disposeOnce();
152 m_xWizardImpl
.reset();
155 maWizardLayoutIdle
.Stop();
157 // Remove all buttons
159 RemoveButton( mpFirstBtn
->mpButton
);
162 while ( mpFirstPage
)
163 RemovePage( mpFirstPage
->mpPage
);
165 mpCurTabPage
.clear();
168 mpViewWindow
.clear();
172 void RoadmapWizard::SetRoadmapHelpId( const OUString
& _rId
)
174 m_xRoadmapImpl
->pRoadmap
->SetHelpId( _rId
);
177 void RoadmapWizard::SetRoadmapBitmap(const BitmapEx
& rBmp
)
179 m_xRoadmapImpl
->pRoadmap
->SetRoadmapBitmap(rBmp
);
182 void RoadmapWizardMachine::SetRoadmapHelpId(const OUString
& rId
)
184 m_xAssistant
->set_page_side_help_id(rId
);
187 void RoadmapWizardMachine::declarePath( PathId _nPathId
, const WizardPath
& _lWizardStates
)
189 m_pImpl
->aPaths
.emplace( _nPathId
, _lWizardStates
);
191 if ( m_pImpl
->aPaths
.size() == 1 )
192 // the very first path -> activate it
193 activatePath( _nPathId
);
195 implUpdateRoadmap( );
198 void RoadmapWizardMachine::activatePath( PathId _nPathId
, bool _bDecideForIt
)
200 if ( ( _nPathId
== m_pImpl
->nActivePath
) && ( _bDecideForIt
== m_pImpl
->bActivePathIsDefinite
) )
204 // does the given path exist?
205 Paths::const_iterator aNewPathPos
= m_pImpl
->aPaths
.find( _nPathId
);
206 DBG_ASSERT( aNewPathPos
!= m_pImpl
->aPaths
.end(), "RoadmapWizard::activate: there is no such path!" );
207 if ( aNewPathPos
== m_pImpl
->aPaths
.end() )
210 // determine the index of the current state in the current path
211 sal_Int32 nCurrentStatePathIndex
= -1;
212 if ( m_pImpl
->nActivePath
!= PathId::INVALID
)
213 nCurrentStatePathIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
215 DBG_ASSERT( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) > nCurrentStatePathIndex
,
216 "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
217 // If this asserts, this for instance means that we are already in state number, say, 5
218 // of our current path, and the caller tries to activate a path which has less than 5
220 if ( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) <= nCurrentStatePathIndex
)
223 // assert that the current and the new path are equal, up to nCurrentStatePathIndex
224 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
225 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
227 if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos
->second
, aNewPathPos
->second
) <= nCurrentStatePathIndex
)
229 OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
234 m_pImpl
->nActivePath
= _nPathId
;
235 m_pImpl
->bActivePathIsDefinite
= _bDecideForIt
;
237 implUpdateRoadmap( );
240 void RoadmapWizard::implUpdateRoadmap( )
242 DBG_ASSERT( m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
) != m_xRoadmapImpl
->aPaths
.end(),
243 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
244 const WizardPath
& rActivePath( m_xRoadmapImpl
->aPaths
[ m_xRoadmapImpl
->nActivePath
] );
246 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
247 if (nCurrentStatePathIndex
< 0)
249 assert(nCurrentStatePathIndex
>= 0 && o3tl::make_unsigned(nCurrentStatePathIndex
) < rActivePath
.size());
251 // determine up to which index (in the new path) we have to display the items
252 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
253 bool bIncompletePath
= false;
254 if ( !m_xRoadmapImpl
->bActivePathIsDefinite
)
256 for (auto const& path
: m_xRoadmapImpl
->aPaths
)
258 if ( path
.first
== m_xRoadmapImpl
->nActivePath
)
259 // it's the path we are just activating -> no need to check anything
261 // the index from which on both paths differ
262 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
263 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
264 // they differ in an index which we have already left behind us
265 // -> this is no conflict anymore
268 // the path conflicts with our new path -> don't activate the
269 // *complete* new path, but only up to the step which is unambiguous
270 nUpperStepBoundary
= nDivergenceIndex
;
271 bIncompletePath
= true;
275 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
276 // path, up to (excluding) nUpperStepBoundary
277 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
278 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
280 bool bExistentItem
= ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
281 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
283 bool bInsertItem
= false;
288 while ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() )
289 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
294 // there is an item with this index in the roadmap - does it match what is requested by
295 // the respective state in the active path?
296 RoadmapTypes::ItemId nPresentItemId
= m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
);
297 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
298 if ( nPresentItemId
!= nRequiredState
)
300 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
307 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
308 bInsertItem
= bNeedItem
;
311 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
314 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(
316 getStateDisplayName( nState
),
322 const bool bEnable
= m_xRoadmapImpl
->aDisabledStates
.find( nState
) == m_xRoadmapImpl
->aDisabledStates
.end();
323 m_xRoadmapImpl
->pRoadmap
->EnableRoadmapItem( m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
), bEnable
);
326 m_xRoadmapImpl
->pRoadmap
->SetRoadmapComplete( !bIncompletePath
);
329 void RoadmapWizardMachine::implUpdateRoadmap( )
332 DBG_ASSERT( m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
) != m_pImpl
->aPaths
.end(),
333 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
334 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
336 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
337 if (nCurrentStatePathIndex
< 0)
339 assert(nCurrentStatePathIndex
>= 0 && o3tl::make_unsigned(nCurrentStatePathIndex
) < rActivePath
.size());
341 // determine up to which index (in the new path) we have to display the items
342 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
343 if ( !m_pImpl
->bActivePathIsDefinite
)
345 for (auto const& path
: m_pImpl
->aPaths
)
347 if ( path
.first
== m_pImpl
->nActivePath
)
348 // it's the path we are just activating -> no need to check anything
350 // the index from which on both paths differ
351 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
352 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
353 // they differ in an index which we have already left behind us
354 // -> this is no conflict anymore
357 // the path conflicts with our new path -> don't activate the
358 // *complete* new path, but only up to the step which is unambiguous
359 nUpperStepBoundary
= nDivergenceIndex
;
363 // can we advance from the current page?
364 bool bCurrentPageCanAdvance
= true;
365 BuilderPage
* pCurrentPage
= GetPage( getCurrentState() );
368 const IWizardPageController
* pController
= getPageController( GetPage( getCurrentState() ) );
369 OSL_ENSURE( pController
!= nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
370 bCurrentPageCanAdvance
= !pController
|| pController
->canAdvance();
373 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
374 // path, up to (excluding) nUpperStepBoundary
375 RoadmapTypes::ItemIndex nRoadmapItems
= m_xAssistant
->get_n_pages();
376 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, nRoadmapItems
);
377 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
379 bool bExistentItem
= ( nItemIndex
< nRoadmapItems
);
380 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
382 bool bInsertItem
= false;
387 int nPages
= nRoadmapItems
;
388 for (int i
= nPages
- 1; i
>= nItemIndex
; --i
)
390 m_xAssistant
->set_page_title(m_xAssistant
->get_page_ident(i
), u
""_ustr
);
397 // there is an item with this index in the roadmap - does it match what is requested by
398 // the respective state in the active path?
399 RoadmapTypes::ItemId nPresentItemId
= m_xAssistant
->get_page_ident(nItemIndex
).toInt32();
400 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
401 if ( nPresentItemId
!= nRequiredState
)
403 m_xAssistant
->set_page_title(OUString::number(nPresentItemId
), u
""_ustr
);
410 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
411 bInsertItem
= bNeedItem
;
414 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
418 GetOrCreatePage(nState
);
421 OUString
sIdent(getPageIdentForState(nState
));
422 m_xAssistant
->set_page_index(sIdent
, nItemIndex
);
423 m_xAssistant
->set_page_title(sIdent
, getStateDisplayName(nState
));
425 // if the item is *after* the current state, but the current page does not
426 // allow advancing, the disable the state. This relieves derived classes
427 // from disabling all future states just because the current state does not
428 // (yet) allow advancing.
429 const bool bUnconditionedDisable
= !bCurrentPageCanAdvance
&& ( nItemIndex
> nCurrentStatePathIndex
);
430 const bool bEnable
= !bUnconditionedDisable
&& ( m_pImpl
->aDisabledStates
.find( nState
) == m_pImpl
->aDisabledStates
.end() );
431 m_xAssistant
->set_page_sensitive(sIdent
, bEnable
);
435 WizardTypes::WizardState
RoadmapWizard::determineNextState( WizardTypes::WizardState _nCurrentState
) const
437 sal_Int32 nCurrentStatePathIndex
= -1;
439 Paths::const_iterator aActivePathPos
= m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
);
440 if ( aActivePathPos
!= m_xRoadmapImpl
->aPaths
.end() )
441 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
443 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
444 if (nCurrentStatePathIndex
< 0)
445 return WZS_INVALID_STATE
;
446 assert(nCurrentStatePathIndex
>= 0 && o3tl::make_unsigned(nCurrentStatePathIndex
) < aActivePathPos
->second
.size());
448 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
450 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
451 && ( m_xRoadmapImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_xRoadmapImpl
->aDisabledStates
.end() )
457 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
458 // there is no next state in the current path (at least none which is enabled)
459 return WZS_INVALID_STATE
;
461 return aActivePathPos
->second
[ nNextStateIndex
];
464 WizardTypes::WizardState
RoadmapWizardMachine::determineNextState( WizardTypes::WizardState _nCurrentState
) const
466 sal_Int32 nCurrentStatePathIndex
= -1;
468 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
469 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
470 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
472 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
473 if (nCurrentStatePathIndex
< 0)
474 return WZS_INVALID_STATE
;
475 assert(nCurrentStatePathIndex
>= 0 && o3tl::make_unsigned(nCurrentStatePathIndex
) < aActivePathPos
->second
.size());
477 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
479 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
480 && ( m_pImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_pImpl
->aDisabledStates
.end() )
486 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
487 // there is no next state in the current path (at least none which is enabled)
488 return WZS_INVALID_STATE
;
490 return aActivePathPos
->second
[ nNextStateIndex
];
493 bool RoadmapWizardMachine::canAdvance() const
495 if ( !m_pImpl
->bActivePathIsDefinite
)
497 // check how many paths are still allowed
498 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
500 // if current path has only the base item, it is not possible to proceed without activating another path
501 if(rActivePath
.size()<=1)
504 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
506 size_t nPossiblePaths(0);
507 for (auto const& path
: m_pImpl
->aPaths
)
509 // the index from which on both paths differ
510 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
512 if ( nDivergenceIndex
> nCurrentStatePathIndex
)
513 // this path is still a possible path
517 // if we have more than one path which is still possible, then we assume
518 // to always have a next state. Though there might be scenarios where this
519 // is not true, but this is too sophisticated (means not really needed) right now.
520 if ( nPossiblePaths
> 1 )
524 const WizardPath
& rPath
= m_pImpl
->aPaths
[ m_pImpl
->nActivePath
];
525 return *rPath
.rbegin() != getCurrentState();
528 void RoadmapWizardMachine::updateTravelUI()
530 WizardMachine::updateTravelUI();
532 // disable the "Previous" button if all states in our history are disabled
533 std::vector
< WizardTypes::WizardState
> aHistory
;
534 getStateHistory( aHistory
);
535 bool bHaveEnabledState
= false;
536 for (auto const& state
: aHistory
)
538 if ( isStateEnabled(state
) )
540 bHaveEnabledState
= true;
545 enableButtons( WizardButtonFlags::PREVIOUS
, bHaveEnabledState
);
550 IMPL_LINK_NOARG(RoadmapWizard
, OnRoadmapItemSelected
, LinkParamNone
*, void)
552 RoadmapTypes::ItemId nCurItemId
= m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
553 if ( nCurItemId
== getCurrentState() )
557 if ( isTravelingSuspended() )
560 RoadmapWizardTravelSuspension
aTravelGuard( *this );
562 sal_Int32 nCurrentIndex
= m_xRoadmapImpl
->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl
->nActivePath
);
563 sal_Int32 nNewIndex
= m_xRoadmapImpl
->getStateIndexInPath( nCurItemId
, m_xRoadmapImpl
->nActivePath
);
565 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
566 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
567 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
573 if ( nNewIndex
> nCurrentIndex
)
575 bResult
= skipUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
576 WizardTypes::WizardState nTemp
= static_cast<WizardTypes::WizardState
>(nCurItemId
);
579 if( m_xRoadmapImpl
->aDisabledStates
.find( --nTemp
) != m_xRoadmapImpl
->aDisabledStates
.end() )
580 removePageFromHistory( nTemp
);
584 bResult
= skipBackwardUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
587 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
590 IMPL_LINK(RoadmapWizardMachine
, OnRoadmapItemSelected
, const OUString
&, rCurItemId
, bool)
592 WizardTypes::WizardState nSelectedState
= getStateFromPageIdent(rCurItemId
);
594 if (nSelectedState
== getCurrentState())
598 if ( isTravelingSuspended() )
601 WizardTravelSuspension
aTravelGuard( *this );
603 sal_Int32 nCurrentIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
604 sal_Int32 nNewIndex
= m_pImpl
->getStateIndexInPath( nSelectedState
, m_pImpl
->nActivePath
);
606 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
607 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
608 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
614 if ( nNewIndex
> nCurrentIndex
)
616 bResult
= skipUntil(nSelectedState
);
617 WizardTypes::WizardState nTemp
= nSelectedState
;
620 if( m_pImpl
->aDisabledStates
.find( --nTemp
) != m_pImpl
->aDisabledStates
.end() )
621 removePageFromHistory( nTemp
);
625 bResult
= skipBackwardUntil(nSelectedState
);
630 void RoadmapWizard::enterState(WizardTypes::WizardState
/*nState*/)
632 // synchronize the roadmap
633 implUpdateRoadmap( );
634 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
637 void RoadmapWizardMachine::enterState( WizardTypes::WizardState _nState
)
639 WizardMachine::enterState( _nState
);
641 // synchronize the roadmap
645 OUString
RoadmapWizard::getStateDisplayName( WizardTypes::WizardState _nState
) const
647 OUString sDisplayName
;
649 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
650 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
651 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
652 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
653 sDisplayName
= pos
->second
.first
;
658 OUString
RoadmapWizardMachine::getStateDisplayName( WizardTypes::WizardState _nState
) const
660 OUString sDisplayName
;
662 StateDescriptions::const_iterator pos
= m_pImpl
->aStateDescriptors
.find( _nState
);
663 OSL_ENSURE( pos
!= m_pImpl
->aStateDescriptors
.end(),
664 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
665 if ( pos
!= m_pImpl
->aStateDescriptors
.end() )
666 sDisplayName
= pos
->second
.first
;
671 VclPtr
<TabPage
> RoadmapWizard::createPage( WizardTypes::WizardState _nState
)
673 VclPtr
<TabPage
> pPage
;
675 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
676 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
677 "RoadmapWizard::createPage: no default implementation available for this state!" );
678 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
680 RoadmapPageFactory pFactory
= pos
->second
.second
;
681 pPage
= (*pFactory
)( *this );
687 void RoadmapWizardMachine::enableState( WizardTypes::WizardState _nState
, bool _bEnable
)
689 // remember this (in case the state appears in the roadmap later on)
691 m_pImpl
->aDisabledStates
.erase( _nState
);
694 m_pImpl
->aDisabledStates
.insert( _nState
);
695 removePageFromHistory( _nState
);
698 // if the state is currently in the roadmap, reflect it's new status
699 m_xAssistant
->set_page_sensitive(getPageIdentForState(_nState
), _bEnable
);
702 bool RoadmapWizardMachine::knowsState( WizardTypes::WizardState i_nState
) const
704 for (auto const& path
: m_pImpl
->aPaths
)
706 for (auto const& state
: path
.second
)
708 if ( state
== i_nState
)
715 bool RoadmapWizardMachine::isStateEnabled( WizardTypes::WizardState _nState
) const
717 return m_pImpl
->aDisabledStates
.find( _nState
) == m_pImpl
->aDisabledStates
.end();
720 void RoadmapWizard::InsertRoadmapItem(int nItemIndex
, const OUString
& rText
, int nItemId
, bool bEnable
)
722 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(nItemIndex
, rText
, nItemId
, bEnable
);
725 void RoadmapWizard::SelectRoadmapItemByID(int nItemId
, bool bGrabFocus
)
727 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID(nItemId
, bGrabFocus
);
730 void RoadmapWizard::DeleteRoadmapItems()
732 while (m_xRoadmapImpl
->pRoadmap
->GetItemCount())
733 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem(0);
736 void RoadmapWizard::SetItemSelectHdl( const Link
<LinkParamNone
*,void>& _rHdl
)
738 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl(_rHdl
);
741 int RoadmapWizard::GetCurrentRoadmapItemID() const
743 return m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
746 FactoryFunction
RoadmapWizard::GetUITestFactory() const
748 return RoadmapWizardUIObject::create
;
753 bool isButton(WindowType eType
)
755 return eType
== WindowType::PUSHBUTTON
|| eType
== WindowType::OKBUTTON
756 || eType
== WindowType::CANCELBUTTON
|| eType
== WindowType::HELPBUTTON
;
760 void RoadmapWizard::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
762 rJsonWriter
.put("id", get_id());
763 rJsonWriter
.put("type", "dialog");
764 rJsonWriter
.put("title", GetText());
766 OUString sDialogId
= GetHelpId();
767 sal_Int32 nStartPos
= sDialogId
.lastIndexOf('/');
768 nStartPos
= nStartPos
>= 0 ? nStartPos
+ 1 : 0;
769 rJsonWriter
.put("dialogid", sDialogId
.copy(nStartPos
));
771 auto aResponses
= rJsonWriter
.startArray("responses");
772 for (const auto& rResponse
: m_xRoadmapImpl
->maResponses
)
774 auto aResponse
= rJsonWriter
.startStruct();
775 rJsonWriter
.put("id", rResponse
.first
->get_id());
776 rJsonWriter
.put("response", rResponse
.second
);
780 vcl::Window
* pFocusControl
= GetFirstControlForFocus();
782 rJsonWriter
.put("init_focus_id", pFocusControl
->get_id());
785 auto childrenNode
= rJsonWriter
.startArray("children");
787 auto containerNode
= rJsonWriter
.startStruct();
788 rJsonWriter
.put("id", "container");
789 rJsonWriter
.put("type", "container");
790 rJsonWriter
.put("vertical", true);
793 auto containerChildrenNode
= rJsonWriter
.startArray("children");
796 for (int i
= 0; i
< GetChildCount(); i
++)
798 vcl::Window
* pChild
= GetChild(i
);
800 if (!isButton(pChild
->GetType()) && pChild
!= mpViewWindow
)
802 auto childNode
= rJsonWriter
.startStruct();
803 pChild
->DumpAsPropertyTree(rJsonWriter
);
809 auto buttonsNode
= rJsonWriter
.startStruct();
810 rJsonWriter
.put("id", "buttons");
811 rJsonWriter
.put("type", "buttonbox");
812 rJsonWriter
.put("layoutstyle", "end");
814 auto buttonsChildrenNode
= rJsonWriter
.startArray("children");
815 for (int i
= 0; i
< GetChildCount(); i
++)
817 vcl::Window
* pChild
= GetChild(i
);
819 if (isButton(pChild
->GetType()))
821 auto childNode
= rJsonWriter
.startStruct();
822 pChild
->DumpAsPropertyTree(rJsonWriter
);
833 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */