mac-sandboxing: also exclude AppleRemote when using --enable-mergelibs
[LibreOffice.git] / vcl / source / control / roadmapwizard.cxx
blob4306acbaa564f7a4ef5ee6fdcfb0fb86ae79c497
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
27 #include <svdata.hxx>
28 #include <wizdlg.hxx>
30 #include <vector>
32 #include "wizimpldata.hxx"
33 #include <uiobject-internal.hxx>
35 namespace vcl
37 sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath )
39 sal_Int32 nStateIndexInPath = 0;
40 for (auto const& path : _rPath)
42 if (path == _nState)
43 return nStateIndexInPath;
44 ++nStateIndexInPath;
46 return -1;
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 ] )
64 return nCheck;
66 return nMinLength;
69 //= RoadmapWizard
70 RoadmapWizard::RoadmapWizard(vcl::Window* pParent, WinBits nStyle, InitFlag eFlag)
71 : Dialog(pParent, nStyle, eFlag)
72 , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
73 , m_pFinish(nullptr)
74 , m_pCancel(nullptr)
75 , m_pNextPage(nullptr)
76 , m_pPrevPage(nullptr)
77 , m_pHelp(nullptr)
78 , m_xWizardImpl(new WizardMachineImplData)
79 , m_xRoadmapImpl(new RoadmapWizardImpl)
81 mpFirstPage = nullptr;
82 mpFirstBtn = nullptr;
83 mpCurTabPage = nullptr;
84 mpPrevBtn = nullptr;
85 mpNextBtn = nullptr;
86 mpViewWindow = nullptr;
87 mnCurLevel = 0;
88 mbEmptyViewMargin = false;
89 mnLeftAlignCount = 0;
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);
122 CalcAndSetSize();
125 RoadmapWizard::~RoadmapWizard()
127 disposeOnce();
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();
144 if (m_xWizardImpl)
146 for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
148 TabPage *pPage = GetPage(i);
149 if (pPage)
150 pPage->disposeOnce();
152 m_xWizardImpl.reset();
155 maWizardLayoutIdle.Stop();
157 // Remove all buttons
158 while ( mpFirstBtn )
159 RemoveButton( mpFirstBtn->mpButton );
161 // Remove all pages
162 while ( mpFirstPage )
163 RemovePage( mpFirstPage->mpPage );
165 mpCurTabPage.clear();
166 mpPrevBtn.clear();
167 mpNextBtn.clear();
168 mpViewWindow.clear();
169 Dialog::dispose();
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 );
194 else
195 implUpdateRoadmap( );
198 void RoadmapWizardMachine::activatePath( PathId _nPathId, bool _bDecideForIt )
200 if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) )
201 // nothing to do
202 return;
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() )
208 return;
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
219 // states
220 if ( static_cast<sal_Int32>(aNewPathPos->second.size()) <= nCurrentStatePathIndex )
221 return;
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!" );
230 return;
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)
248 return;
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
260 continue;
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
266 continue;
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;
284 if ( bExistentItem )
286 if ( !bNeedItem )
288 while ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() )
289 m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
290 break;
292 else
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 );
301 bInsertItem = true;
305 else
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 ] );
312 if ( bInsertItem )
314 m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(
315 nItemIndex,
316 getStateDisplayName( nState ),
317 nState,
318 true
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)
338 return;
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
349 continue;
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
355 continue;
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() );
366 if ( pCurrentPage )
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;
383 if ( bExistentItem )
385 if ( !bNeedItem )
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);
391 --nRoadmapItems;
393 break;
395 else
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);
404 bInsertItem = true;
408 else
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 ] );
416 if ( bInsertItem )
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() )
454 ++nNextStateIndex;
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() )
483 ++nNextStateIndex;
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)
502 return false;
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
514 nPossiblePaths += 1;
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 )
521 return true;
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;
541 break;
545 enableButtons( WizardButtonFlags::PREVIOUS, bHaveEnabledState );
547 implUpdateRoadmap();
550 IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void)
552 RoadmapTypes::ItemId nCurItemId = m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
553 if ( nCurItemId == getCurrentState() )
554 // nothing to do
555 return;
557 if ( isTravelingSuspended() )
558 return;
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 ) )
569 return;
572 bool bResult = true;
573 if ( nNewIndex > nCurrentIndex )
575 bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
576 WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
577 while( nTemp )
579 if( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
580 removePageFromHistory( nTemp );
583 else
584 bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
586 if ( !bResult )
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())
595 // nothing to do
596 return false;
598 if ( isTravelingSuspended() )
599 return false;
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 ) )
610 return false;
613 bool bResult = true;
614 if ( nNewIndex > nCurrentIndex )
616 bResult = skipUntil(nSelectedState);
617 WizardTypes::WizardState nTemp = nSelectedState;
618 while( nTemp )
620 if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() )
621 removePageFromHistory( nTemp );
624 else
625 bResult = skipBackwardUntil(nSelectedState);
627 return bResult;
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
642 implUpdateRoadmap();
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;
655 return sDisplayName;
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;
668 return sDisplayName;
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 );
684 return pPage;
687 void RoadmapWizardMachine::enableState( WizardTypes::WizardState _nState, bool _bEnable )
689 // remember this (in case the state appears in the roadmap later on)
690 if ( _bEnable )
691 m_pImpl->aDisabledStates.erase( _nState );
692 else
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 )
709 return true;
712 return false;
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;
751 namespace
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();
781 if (pFocusControl)
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");
795 // tabpages
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);
807 // buttons
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);
831 } // namespace vcl
833 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */