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>
34 #include "wizimpldata.hxx"
35 #include <uiobject-internal.hxx>
39 using namespace RoadmapWizardTypes
;
43 typedef ::std::set
< WizardTypes::WizardState
> StateSet
;
51 WizardTypes::WizardState
,
59 struct RoadmapWizardImpl
61 ScopedVclPtr
<ORoadmap
> pRoadmap
;
64 StateDescriptions aStateDescriptors
;
65 StateSet aDisabledStates
;
66 bool bActivePathIsDefinite
;
71 ,bActivePathIsDefinite( false )
75 /// returns the index of the current state in given path, or -1
76 static sal_Int32
getStateIndexInPath( WizardTypes::WizardState _nState
, const WizardPath
& _rPath
);
77 /// returns the index of the current state in the path with the given id, or -1
78 sal_Int32
getStateIndexInPath( WizardTypes::WizardState _nState
, PathId _nPathId
);
79 /// returns the index of the first state in which the two given paths differ
80 static sal_Int32
getFirstDifferentIndex( const WizardPath
& _rLHS
, const WizardPath
& _rRHS
);
84 sal_Int32
RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState
, const WizardPath
& _rPath
)
86 sal_Int32 nStateIndexInPath
= 0;
88 for (auto const& path
: _rPath
)
98 nStateIndexInPath
= -1;
99 return nStateIndexInPath
;
103 sal_Int32
RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState
, PathId _nPathId
)
105 sal_Int32 nStateIndexInPath
= -1;
106 Paths::const_iterator aPathPos
= aPaths
.find( _nPathId
);
107 if ( aPathPos
!= aPaths
.end( ) )
108 nStateIndexInPath
= getStateIndexInPath( _nState
, aPathPos
->second
);
109 return nStateIndexInPath
;
113 sal_Int32
RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath
& _rLHS
, const WizardPath
& _rRHS
)
115 sal_Int32 nMinLength
= ::std::min( _rLHS
.size(), _rRHS
.size() );
116 for ( sal_Int32 nCheck
= 0; nCheck
< nMinLength
; ++nCheck
)
118 if ( _rLHS
[ nCheck
] != _rRHS
[ nCheck
] )
125 RoadmapWizard::RoadmapWizard(vcl::Window
* pParent
, WinBits nStyle
, InitFlag eFlag
)
126 : Dialog(pParent
, nStyle
, eFlag
)
127 , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
130 , m_pNextPage(nullptr)
131 , m_pPrevPage(nullptr)
133 , m_xWizardImpl(new WizardMachineImplData
)
134 , m_xRoadmapImpl(new RoadmapWizardImpl
)
136 mpFirstPage
= nullptr;
137 mpFirstBtn
= nullptr;
138 mpCurTabPage
= nullptr;
141 mpViewWindow
= nullptr;
143 mbEmptyViewMargin
= false;
144 mnLeftAlignCount
= 0;
146 maWizardLayoutIdle
.SetPriority(TaskPriority::RESIZE
);
147 maWizardLayoutIdle
.SetInvokeHandler( LINK( this, RoadmapWizard
, ImplHandleWizardLayoutTimerHdl
) );
149 implConstruct(WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
);
151 SetLeftAlignedButtonCount( 1 );
152 mbEmptyViewMargin
= true;
154 m_xRoadmapImpl
->pRoadmap
.disposeAndReset( VclPtr
<ORoadmap
>::Create( this, WB_TABSTOP
) );
155 m_xRoadmapImpl
->pRoadmap
->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE
) );
156 m_xRoadmapImpl
->pRoadmap
->SetPosPixel( Point( 0, 0 ) );
157 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl( LINK( this, RoadmapWizard
, OnRoadmapItemSelected
) );
159 Size aRoadmapSize
= LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont
));
160 aRoadmapSize
.setHeight( GetSizePixel().Height() );
161 m_xRoadmapImpl
->pRoadmap
->SetSizePixel( aRoadmapSize
);
163 mpViewWindow
= m_xRoadmapImpl
->pRoadmap
;
164 m_xRoadmapImpl
->pRoadmap
->Show();
167 RoadmapWizardMachine::RoadmapWizardMachine(weld::Window
* pParent
)
168 : WizardMachine(pParent
, WizardButtonFlags::NEXT
| WizardButtonFlags::PREVIOUS
| WizardButtonFlags::FINISH
| WizardButtonFlags::CANCEL
| WizardButtonFlags::HELP
)
169 , m_pImpl( new RoadmapWizardImpl
)
171 m_xAssistant
->connect_jump_page(LINK(this, RoadmapWizardMachine
, OnRoadmapItemSelected
));
174 void RoadmapWizard::ShowRoadmap(bool bShow
)
176 m_xRoadmapImpl
->pRoadmap
->Show(bShow
);
180 RoadmapWizard::~RoadmapWizard()
185 RoadmapWizardMachine::~RoadmapWizardMachine()
189 void RoadmapWizard::dispose()
191 m_xRoadmapImpl
.reset();
193 m_pFinish
.disposeAndClear();
194 m_pCancel
.disposeAndClear();
195 m_pNextPage
.disposeAndClear();
196 m_pPrevPage
.disposeAndClear();
197 m_pHelp
.disposeAndClear();
201 for (WizardTypes::WizardState i
= 0; i
< m_xWizardImpl
->nFirstUnknownPage
; ++i
)
203 TabPage
*pPage
= GetPage(i
);
205 pPage
->disposeOnce();
207 m_xWizardImpl
.reset();
210 maWizardLayoutIdle
.Stop();
212 // Remove all buttons
214 RemoveButton( mpFirstBtn
->mpButton
);
217 while ( mpFirstPage
)
218 RemovePage( mpFirstPage
->mpPage
);
220 mpCurTabPage
.clear();
223 mpViewWindow
.clear();
227 void RoadmapWizard::SetRoadmapHelpId( const OUString
& _rId
)
229 m_xRoadmapImpl
->pRoadmap
->SetHelpId( _rId
);
232 void RoadmapWizard::SetRoadmapBitmap(const BitmapEx
& rBmp
)
234 m_xRoadmapImpl
->pRoadmap
->SetRoadmapBitmap(rBmp
);
237 void RoadmapWizardMachine::SetRoadmapHelpId(const OUString
& rId
)
239 m_xAssistant
->set_page_side_help_id(rId
);
242 void RoadmapWizardMachine::declarePath( PathId _nPathId
, const WizardPath
& _lWizardStates
)
244 m_pImpl
->aPaths
.emplace( _nPathId
, _lWizardStates
);
246 if ( m_pImpl
->aPaths
.size() == 1 )
247 // the very first path -> activate it
248 activatePath( _nPathId
);
250 implUpdateRoadmap( );
253 void RoadmapWizardMachine::activatePath( PathId _nPathId
, bool _bDecideForIt
)
255 if ( ( _nPathId
== m_pImpl
->nActivePath
) && ( _bDecideForIt
== m_pImpl
->bActivePathIsDefinite
) )
259 // does the given path exist?
260 Paths::const_iterator aNewPathPos
= m_pImpl
->aPaths
.find( _nPathId
);
261 DBG_ASSERT( aNewPathPos
!= m_pImpl
->aPaths
.end(), "RoadmapWizard::activate: there is no such path!" );
262 if ( aNewPathPos
== m_pImpl
->aPaths
.end() )
265 // determine the index of the current state in the current path
266 sal_Int32 nCurrentStatePathIndex
= -1;
267 if ( m_pImpl
->nActivePath
!= -1 )
268 nCurrentStatePathIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
270 DBG_ASSERT( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) > nCurrentStatePathIndex
,
271 "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
272 // If this asserts, this for instance means that we are already in state number, say, 5
273 // of our current path, and the caller tries to activate a path which has less than 5
275 if ( static_cast<sal_Int32
>(aNewPathPos
->second
.size()) <= nCurrentStatePathIndex
)
278 // assert that the current and the new path are equal, up to nCurrentStatePathIndex
279 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
280 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
282 if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos
->second
, aNewPathPos
->second
) <= nCurrentStatePathIndex
)
284 OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
289 m_pImpl
->nActivePath
= _nPathId
;
290 m_pImpl
->bActivePathIsDefinite
= _bDecideForIt
;
292 implUpdateRoadmap( );
295 void RoadmapWizard::implUpdateRoadmap( )
297 DBG_ASSERT( m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
) != m_xRoadmapImpl
->aPaths
.end(),
298 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
299 const WizardPath
& rActivePath( m_xRoadmapImpl
->aPaths
[ m_xRoadmapImpl
->nActivePath
] );
301 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
302 if (nCurrentStatePathIndex
< 0)
305 // determine up to which index (in the new path) we have to display the items
306 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
307 bool bIncompletePath
= false;
308 if ( !m_xRoadmapImpl
->bActivePathIsDefinite
)
310 for (auto const& path
: m_xRoadmapImpl
->aPaths
)
312 if ( path
.first
== m_xRoadmapImpl
->nActivePath
)
313 // it's the path we are just activating -> no need to check anything
315 // the index from which on both paths differ
316 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
317 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
318 // they differ in an index which we have already left behind us
319 // -> this is no conflict anymore
322 // the path conflicts with our new path -> don't activate the
323 // *complete* new path, but only up to the step which is unambiguous
324 nUpperStepBoundary
= nDivergenceIndex
;
325 bIncompletePath
= true;
329 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
330 // path, up to (excluding) nUpperStepBoundary
331 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
332 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
334 bool bExistentItem
= ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() );
335 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
337 bool bInsertItem
= false;
342 while ( nItemIndex
< m_xRoadmapImpl
->pRoadmap
->GetItemCount() )
343 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
348 // there is an item with this index in the roadmap - does it match what is requested by
349 // the respective state in the active path?
350 RoadmapTypes::ItemId nPresentItemId
= m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
);
351 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
352 if ( nPresentItemId
!= nRequiredState
)
354 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem( nItemIndex
);
361 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
362 bInsertItem
= bNeedItem
;
365 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
368 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(
370 getStateDisplayName( nState
),
376 const bool bEnable
= m_xRoadmapImpl
->aDisabledStates
.find( nState
) == m_xRoadmapImpl
->aDisabledStates
.end();
377 m_xRoadmapImpl
->pRoadmap
->EnableRoadmapItem( m_xRoadmapImpl
->pRoadmap
->GetItemID( nItemIndex
), bEnable
);
380 m_xRoadmapImpl
->pRoadmap
->SetRoadmapComplete( !bIncompletePath
);
383 void RoadmapWizardMachine::implUpdateRoadmap( )
386 DBG_ASSERT( m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
) != m_pImpl
->aPaths
.end(),
387 "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
388 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
390 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
391 if (nCurrentStatePathIndex
< 0)
394 // determine up to which index (in the new path) we have to display the items
395 RoadmapTypes::ItemIndex nUpperStepBoundary
= static_cast<RoadmapTypes::ItemIndex
>(rActivePath
.size());
396 if ( !m_pImpl
->bActivePathIsDefinite
)
398 for (auto const& path
: m_pImpl
->aPaths
)
400 if ( path
.first
== m_pImpl
->nActivePath
)
401 // it's the path we are just activating -> no need to check anything
403 // the index from which on both paths differ
404 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
405 if ( nDivergenceIndex
<= nCurrentStatePathIndex
)
406 // they differ in an index which we have already left behind us
407 // -> this is no conflict anymore
410 // the path conflicts with our new path -> don't activate the
411 // *complete* new path, but only up to the step which is unambiguous
412 nUpperStepBoundary
= nDivergenceIndex
;
416 // can we advance from the current page?
417 bool bCurrentPageCanAdvance
= true;
418 BuilderPage
* pCurrentPage
= GetPage( getCurrentState() );
421 const IWizardPageController
* pController
= getPageController( GetPage( getCurrentState() ) );
422 OSL_ENSURE( pController
!= nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
423 bCurrentPageCanAdvance
= !pController
|| pController
->canAdvance();
426 // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
427 // path, up to (excluding) nUpperStepBoundary
428 RoadmapTypes::ItemIndex nRoadmapItems
= m_xAssistant
->get_n_pages();
429 RoadmapTypes::ItemIndex nLoopUntil
= ::std::max( nUpperStepBoundary
, nRoadmapItems
);
430 for ( RoadmapTypes::ItemIndex nItemIndex
= nCurrentStatePathIndex
; nItemIndex
< nLoopUntil
; ++nItemIndex
)
432 bool bExistentItem
= ( nItemIndex
< nRoadmapItems
);
433 bool bNeedItem
= ( nItemIndex
< nUpperStepBoundary
);
435 bool bInsertItem
= false;
440 int nPages
= nRoadmapItems
;
441 for (int i
= nPages
- 1; i
>= nItemIndex
; --i
)
443 m_xAssistant
->set_page_title(m_xAssistant
->get_page_ident(i
), "");
450 // there is an item with this index in the roadmap - does it match what is requested by
451 // the respective state in the active path?
452 RoadmapTypes::ItemId nPresentItemId
= m_xAssistant
->get_page_ident(nItemIndex
).toInt32();
453 WizardTypes::WizardState nRequiredState
= rActivePath
[ nItemIndex
];
454 if ( nPresentItemId
!= nRequiredState
)
456 m_xAssistant
->set_page_title(OUString::number(nPresentItemId
), "");
463 DBG_ASSERT( bNeedItem
, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
464 bInsertItem
= bNeedItem
;
467 WizardTypes::WizardState
nState( rActivePath
[ nItemIndex
] );
471 GetOrCreatePage(nState
);
474 OUString
sIdent(getPageIdentForState(nState
));
475 m_xAssistant
->set_page_index(sIdent
, nItemIndex
);
476 m_xAssistant
->set_page_title(sIdent
, getStateDisplayName(nState
));
478 // if the item is *after* the current state, but the current page does not
479 // allow advancing, the disable the state. This relieves derived classes
480 // from disabling all future states just because the current state does not
481 // (yet) allow advancing.
482 const bool bUnconditionedDisable
= !bCurrentPageCanAdvance
&& ( nItemIndex
> nCurrentStatePathIndex
);
483 const bool bEnable
= !bUnconditionedDisable
&& ( m_pImpl
->aDisabledStates
.find( nState
) == m_pImpl
->aDisabledStates
.end() );
484 m_xAssistant
->set_page_sensitive(sIdent
, bEnable
);
488 WizardTypes::WizardState
RoadmapWizard::determineNextState( WizardTypes::WizardState _nCurrentState
) const
490 sal_Int32 nCurrentStatePathIndex
= -1;
492 Paths::const_iterator aActivePathPos
= m_xRoadmapImpl
->aPaths
.find( m_xRoadmapImpl
->nActivePath
);
493 if ( aActivePathPos
!= m_xRoadmapImpl
->aPaths
.end() )
494 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
496 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
497 if ( nCurrentStatePathIndex
== -1 )
498 return WZS_INVALID_STATE
;
500 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
502 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
503 && ( m_xRoadmapImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_xRoadmapImpl
->aDisabledStates
.end() )
509 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
510 // there is no next state in the current path (at least none which is enabled)
511 return WZS_INVALID_STATE
;
513 return aActivePathPos
->second
[ nNextStateIndex
];
516 WizardTypes::WizardState
RoadmapWizardMachine::determineNextState( WizardTypes::WizardState _nCurrentState
) const
518 sal_Int32 nCurrentStatePathIndex
= -1;
520 Paths::const_iterator aActivePathPos
= m_pImpl
->aPaths
.find( m_pImpl
->nActivePath
);
521 if ( aActivePathPos
!= m_pImpl
->aPaths
.end() )
522 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( _nCurrentState
, aActivePathPos
->second
);
524 DBG_ASSERT( nCurrentStatePathIndex
!= -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
525 if ( nCurrentStatePathIndex
== -1 )
526 return WZS_INVALID_STATE
;
528 sal_Int32 nNextStateIndex
= nCurrentStatePathIndex
+ 1;
530 while ( ( nNextStateIndex
< static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
531 && ( m_pImpl
->aDisabledStates
.find( aActivePathPos
->second
[ nNextStateIndex
] ) != m_pImpl
->aDisabledStates
.end() )
537 if ( nNextStateIndex
>= static_cast<sal_Int32
>(aActivePathPos
->second
.size()) )
538 // there is no next state in the current path (at least none which is enabled)
539 return WZS_INVALID_STATE
;
541 return aActivePathPos
->second
[ nNextStateIndex
];
544 bool RoadmapWizardMachine::canAdvance() const
546 if ( !m_pImpl
->bActivePathIsDefinite
)
548 // check how many paths are still allowed
549 const WizardPath
& rActivePath( m_pImpl
->aPaths
[ m_pImpl
->nActivePath
] );
551 // if current path has only the base item, it is not possible to proceed without activating another path
552 if(rActivePath
.size()<=1)
555 sal_Int32 nCurrentStatePathIndex
= RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath
);
557 size_t nPossiblePaths(0);
558 for (auto const& path
: m_pImpl
->aPaths
)
560 // the index from which on both paths differ
561 sal_Int32 nDivergenceIndex
= RoadmapWizardImpl::getFirstDifferentIndex( rActivePath
, path
.second
);
563 if ( nDivergenceIndex
> nCurrentStatePathIndex
)
564 // this path is still a possible path
568 // if we have more than one path which is still possible, then we assume
569 // to always have a next state. Though there might be scenarios where this
570 // is not true, but this is too sophisticated (means not really needed) right now.
571 if ( nPossiblePaths
> 1 )
575 const WizardPath
& rPath
= m_pImpl
->aPaths
[ m_pImpl
->nActivePath
];
576 return *rPath
.rbegin() != getCurrentState();
579 void RoadmapWizardMachine::updateTravelUI()
581 WizardMachine::updateTravelUI();
583 // disable the "Previous" button if all states in our history are disabled
584 std::vector
< WizardTypes::WizardState
> aHistory
;
585 getStateHistory( aHistory
);
586 bool bHaveEnabledState
= false;
587 for (auto const& state
: aHistory
)
589 if ( isStateEnabled(state
) )
591 bHaveEnabledState
= true;
596 enableButtons( WizardButtonFlags::PREVIOUS
, bHaveEnabledState
);
601 IMPL_LINK_NOARG(RoadmapWizard
, OnRoadmapItemSelected
, LinkParamNone
*, void)
603 RoadmapTypes::ItemId nCurItemId
= m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
604 if ( nCurItemId
== getCurrentState() )
608 if ( isTravelingSuspended() )
611 RoadmapWizardTravelSuspension
aTravelGuard( *this );
613 sal_Int32 nCurrentIndex
= m_xRoadmapImpl
->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl
->nActivePath
);
614 sal_Int32 nNewIndex
= m_xRoadmapImpl
->getStateIndexInPath( nCurItemId
, m_xRoadmapImpl
->nActivePath
);
616 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
617 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
618 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
624 if ( nNewIndex
> nCurrentIndex
)
626 bResult
= skipUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
627 WizardTypes::WizardState nTemp
= static_cast<WizardTypes::WizardState
>(nCurItemId
);
630 if( m_xRoadmapImpl
->aDisabledStates
.find( --nTemp
) != m_xRoadmapImpl
->aDisabledStates
.end() )
631 removePageFromHistory( nTemp
);
635 bResult
= skipBackwardUntil( static_cast<WizardTypes::WizardState
>(nCurItemId
) );
638 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
641 IMPL_LINK(RoadmapWizardMachine
, OnRoadmapItemSelected
, const OUString
&, rCurItemId
, bool)
643 WizardTypes::WizardState nSelectedState
= getStateFromPageIdent(rCurItemId
);
645 if (nSelectedState
== getCurrentState())
649 if ( isTravelingSuspended() )
652 WizardTravelSuspension
aTravelGuard( *this );
654 sal_Int32 nCurrentIndex
= m_pImpl
->getStateIndexInPath( getCurrentState(), m_pImpl
->nActivePath
);
655 sal_Int32 nNewIndex
= m_pImpl
->getStateIndexInPath( nSelectedState
, m_pImpl
->nActivePath
);
657 DBG_ASSERT( ( nCurrentIndex
!= -1 ) && ( nNewIndex
!= -1 ),
658 "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
659 if ( ( nCurrentIndex
== -1 ) || ( nNewIndex
== -1 ) )
665 if ( nNewIndex
> nCurrentIndex
)
667 bResult
= skipUntil(nSelectedState
);
668 WizardTypes::WizardState nTemp
= nSelectedState
;
671 if( m_pImpl
->aDisabledStates
.find( --nTemp
) != m_pImpl
->aDisabledStates
.end() )
672 removePageFromHistory( nTemp
);
676 bResult
= skipBackwardUntil(nSelectedState
);
681 void RoadmapWizard::enterState(WizardTypes::WizardState
/*nState*/)
683 // synchronize the roadmap
684 implUpdateRoadmap( );
685 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID( getCurrentState() );
688 void RoadmapWizardMachine::enterState( WizardTypes::WizardState _nState
)
690 WizardMachine::enterState( _nState
);
692 // synchronize the roadmap
696 OUString
RoadmapWizard::getStateDisplayName( WizardTypes::WizardState _nState
) const
698 OUString sDisplayName
;
700 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
701 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
702 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
703 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
704 sDisplayName
= pos
->second
.first
;
709 OUString
RoadmapWizardMachine::getStateDisplayName( WizardTypes::WizardState _nState
) const
711 OUString sDisplayName
;
713 StateDescriptions::const_iterator pos
= m_pImpl
->aStateDescriptors
.find( _nState
);
714 OSL_ENSURE( pos
!= m_pImpl
->aStateDescriptors
.end(),
715 "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
716 if ( pos
!= m_pImpl
->aStateDescriptors
.end() )
717 sDisplayName
= pos
->second
.first
;
722 VclPtr
<TabPage
> RoadmapWizard::createPage( WizardTypes::WizardState _nState
)
724 VclPtr
<TabPage
> pPage
;
726 StateDescriptions::const_iterator pos
= m_xRoadmapImpl
->aStateDescriptors
.find( _nState
);
727 OSL_ENSURE( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end(),
728 "RoadmapWizard::createPage: no default implementation available for this state!" );
729 if ( pos
!= m_xRoadmapImpl
->aStateDescriptors
.end() )
731 RoadmapPageFactory pFactory
= pos
->second
.second
;
732 pPage
= (*pFactory
)( *this );
738 void RoadmapWizardMachine::enableState( WizardTypes::WizardState _nState
, bool _bEnable
)
740 // remember this (in case the state appears in the roadmap later on)
742 m_pImpl
->aDisabledStates
.erase( _nState
);
745 m_pImpl
->aDisabledStates
.insert( _nState
);
746 removePageFromHistory( _nState
);
749 // if the state is currently in the roadmap, reflect it's new status
750 m_xAssistant
->set_page_sensitive(getPageIdentForState(_nState
), _bEnable
);
753 bool RoadmapWizardMachine::knowsState( WizardTypes::WizardState i_nState
) const
755 for (auto const& path
: m_pImpl
->aPaths
)
757 for (auto const& state
: path
.second
)
759 if ( state
== i_nState
)
766 bool RoadmapWizardMachine::isStateEnabled( WizardTypes::WizardState _nState
) const
768 return m_pImpl
->aDisabledStates
.find( _nState
) == m_pImpl
->aDisabledStates
.end();
771 void RoadmapWizard::InsertRoadmapItem(int nItemIndex
, const OUString
& rText
, int nItemId
, bool bEnable
)
773 m_xRoadmapImpl
->pRoadmap
->InsertRoadmapItem(nItemIndex
, rText
, nItemId
, bEnable
);
776 void RoadmapWizard::SelectRoadmapItemByID(int nItemId
, bool bGrabFocus
)
778 m_xRoadmapImpl
->pRoadmap
->SelectRoadmapItemByID(nItemId
, bGrabFocus
);
781 void RoadmapWizard::DeleteRoadmapItems()
783 while (m_xRoadmapImpl
->pRoadmap
->GetItemCount())
784 m_xRoadmapImpl
->pRoadmap
->DeleteRoadmapItem(0);
787 void RoadmapWizard::SetItemSelectHdl( const Link
<LinkParamNone
*,void>& _rHdl
)
789 m_xRoadmapImpl
->pRoadmap
->SetItemSelectHdl(_rHdl
);
792 int RoadmapWizard::GetCurrentRoadmapItemID() const
794 return m_xRoadmapImpl
->pRoadmap
->GetCurrentRoadmapItemID();
797 FactoryFunction
RoadmapWizard::GetUITestFactory() const
799 return RoadmapWizardUIObject::create
;
804 bool isButton(WindowType eType
)
806 return eType
== WindowType::PUSHBUTTON
|| eType
== WindowType::OKBUTTON
807 || eType
== WindowType::CANCELBUTTON
|| eType
== WindowType::HELPBUTTON
;
811 void RoadmapWizard::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
813 rJsonWriter
.put("id", get_id());
814 rJsonWriter
.put("type", "dialog");
815 rJsonWriter
.put("title", GetText());
817 OUString sDialogId
= GetHelpId();
818 sal_Int32 nStartPos
= sDialogId
.lastIndexOf('/');
819 nStartPos
= nStartPos
>= 0 ? nStartPos
+ 1 : 0;
820 rJsonWriter
.put("dialogid", sDialogId
.copy(nStartPos
));
822 vcl::Window
* pFocusControl
= GetFirstControlForFocus();
824 rJsonWriter
.put("init_focus_id", pFocusControl
->get_id());
827 auto childrenNode
= rJsonWriter
.startArray("children");
829 auto containerNode
= rJsonWriter
.startStruct();
830 rJsonWriter
.put("id", "container");
831 rJsonWriter
.put("type", "container");
832 rJsonWriter
.put("vertical", true);
835 auto containerChildrenNode
= rJsonWriter
.startArray("children");
838 for (int i
= 0; i
< GetChildCount(); i
++)
840 vcl::Window
* pChild
= GetChild(i
);
842 if (!isButton(pChild
->GetType()) && pChild
!= mpViewWindow
)
844 auto childNode
= rJsonWriter
.startStruct();
845 pChild
->DumpAsPropertyTree(rJsonWriter
);
851 auto buttonsNode
= rJsonWriter
.startStruct();
852 rJsonWriter
.put("id", "buttons");
853 rJsonWriter
.put("type", "buttonbox");
854 rJsonWriter
.put("layoutstyle", "end");
856 auto buttonsChildrenNode
= rJsonWriter
.startArray("children");
857 for (int i
= 0; i
< GetChildCount(); i
++)
859 vcl::Window
* pChild
= GetChild(i
);
861 if (isButton(pChild
->GetType()))
863 auto childNode
= rJsonWriter
.startStruct();
864 pChild
->DumpAsPropertyTree(rJsonWriter
);
875 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */