LibreOffice Module vcl (master)  1
roadmapwizard.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 #include <vcl/toolkit/roadmap.hxx>
22 #include <tools/debug.hxx>
23 #include <osl/diagnose.h>
24 
25 #include <strings.hrc>
26 #include <svdata.hxx>
27 #include <wizdlg.hxx>
28 
29 #include <vector>
30 #include <map>
31 #include <set>
32 
33 #include "wizimpldata.hxx"
34 #include <uiobject-internal.hxx>
35 
36 namespace vcl
37 {
38  using namespace RoadmapWizardTypes;
39 
40  namespace
41  {
42  typedef ::std::set< WizardTypes::WizardState > StateSet;
43 
44  typedef ::std::map<
45  PathId,
47  > Paths;
48 
49  typedef ::std::map<
51  ::std::pair<
52  OUString,
54  >
55  > StateDescriptions;
56  }
57 
59  {
61  Paths aPaths;
63  StateDescriptions aStateDescriptors;
64  StateSet aDisabledStates;
66 
68  :pRoadmap( nullptr )
69  ,nActivePath( -1 )
70  ,bActivePathIsDefinite( false )
71  {
72  }
73 
75  static sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath );
77  sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, PathId _nPathId );
79  static sal_Int32 getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS );
80  };
81 
82 
84  {
85  sal_Int32 nStateIndexInPath = 0;
86  bool bFound = false;
87  for (auto const& path : _rPath)
88  {
89  if (path == _nState)
90  {
91  bFound = true;
92  break;
93  }
94  ++nStateIndexInPath;
95  }
96  if (!bFound)
97  nStateIndexInPath = -1;
98  return nStateIndexInPath;
99  }
100 
101 
103  {
104  sal_Int32 nStateIndexInPath = -1;
105  Paths::const_iterator aPathPos = aPaths.find( _nPathId );
106  if ( aPathPos != aPaths.end( ) )
107  nStateIndexInPath = getStateIndexInPath( _nState, aPathPos->second );
108  return nStateIndexInPath;
109  }
110 
111 
112  sal_Int32 RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS )
113  {
114  sal_Int32 nMinLength = ::std::min( _rLHS.size(), _rRHS.size() );
115  for ( sal_Int32 nCheck = 0; nCheck < nMinLength; ++nCheck )
116  {
117  if ( _rLHS[ nCheck ] != _rRHS[ nCheck ] )
118  return nCheck;
119  }
120  return nMinLength;
121  }
122 
123  //= RoadmapWizard
125  : Dialog(pParent, nStyle, eFlag)
126  , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
127  , m_pFinish(nullptr)
128  , m_pCancel(nullptr)
129  , m_pNextPage(nullptr)
130  , m_pPrevPage(nullptr)
131  , m_pHelp(nullptr)
132  , m_xWizardImpl(new WizardMachineImplData)
133  , m_xRoadmapImpl(new RoadmapWizardImpl)
134  {
135  mpFirstPage = nullptr;
136  mpFirstBtn = nullptr;
137  mpCurTabPage = nullptr;
138  mpPrevBtn = nullptr;
139  mpNextBtn = nullptr;
140  mpViewWindow = nullptr;
141  mnCurLevel = 0;
142  mbEmptyViewMargin = false;
143  mnLeftAlignCount = 0;
144 
146  maWizardLayoutIdle.SetInvokeHandler( LINK( this, RoadmapWizard, ImplHandleWizardLayoutTimerHdl ) );
147 
149 
151  mbEmptyViewMargin = true;
152 
153  m_xRoadmapImpl->pRoadmap.disposeAndReset( VclPtr<ORoadmap>::Create( this, WB_TABSTOP ) );
154  m_xRoadmapImpl->pRoadmap->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE ) );
155  m_xRoadmapImpl->pRoadmap->SetPosPixel( Point( 0, 0 ) );
156  m_xRoadmapImpl->pRoadmap->SetItemSelectHdl( LINK( this, RoadmapWizard, OnRoadmapItemSelected ) );
157 
158  Size aRoadmapSize = LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont));
159  aRoadmapSize.setHeight( GetSizePixel().Height() );
160  m_xRoadmapImpl->pRoadmap->SetSizePixel( aRoadmapSize );
161 
162  mpViewWindow = m_xRoadmapImpl->pRoadmap;
163  m_xRoadmapImpl->pRoadmap->Show();
164  }
165 
168  , m_pImpl( new RoadmapWizardImpl )
169  {
170  m_xAssistant->connect_jump_page(LINK(this, RoadmapWizardMachine, OnRoadmapItemSelected));
171  }
172 
173  void RoadmapWizard::ShowRoadmap(bool bShow)
174  {
175  m_xRoadmapImpl->pRoadmap->Show(bShow);
176  CalcAndSetSize();
177  }
178 
180  {
181  disposeOnce();
182  }
183 
185  {
186  }
187 
189  {
190  m_xRoadmapImpl.reset();
191 
197 
198  if (m_xWizardImpl)
199  {
200  for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
201  {
202  TabPage *pPage = GetPage(i);
203  if (pPage)
204  pPage->disposeOnce();
205  }
206  m_xWizardImpl.reset();
207  }
208 
210 
211  // Remove all buttons
212  while ( mpFirstBtn )
214 
215  // Remove all pages
216  while ( mpFirstPage )
218 
220  mpPrevBtn.clear();
221  mpNextBtn.clear();
223  Dialog::dispose();
224  }
225 
226  void RoadmapWizard::SetRoadmapHelpId( const OString& _rId )
227  {
228  m_xRoadmapImpl->pRoadmap->SetHelpId( _rId );
229  }
230 
231  void RoadmapWizardMachine::SetRoadmapHelpId(const OString& rId)
232  {
233  m_xAssistant->set_page_side_help_id(rId);
234  }
235 
236  void RoadmapWizardMachine::declarePath( PathId _nPathId, const WizardPath& _lWizardStates)
237  {
238  m_pImpl->aPaths.emplace( _nPathId, _lWizardStates );
239 
240  if ( m_pImpl->aPaths.size() == 1 )
241  // the very first path -> activate it
242  activatePath( _nPathId );
243  else
245  }
246 
247  void RoadmapWizardMachine::activatePath( PathId _nPathId, bool _bDecideForIt )
248  {
249  if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) )
250  // nothing to do
251  return;
252 
253  // does the given path exist?
254  Paths::const_iterator aNewPathPos = m_pImpl->aPaths.find( _nPathId );
255  DBG_ASSERT( aNewPathPos != m_pImpl->aPaths.end(), "RoadmapWizard::activate: there is no such path!" );
256  if ( aNewPathPos == m_pImpl->aPaths.end() )
257  return;
258 
259  // determine the index of the current state in the current path
260  sal_Int32 nCurrentStatePathIndex = -1;
261  if ( m_pImpl->nActivePath != -1 )
262  nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
263 
264  DBG_ASSERT( static_cast<sal_Int32>(aNewPathPos->second.size()) > nCurrentStatePathIndex,
265  "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
266  // If this asserts, this for instance means that we are already in state number, say, 5
267  // of our current path, and the caller tries to activate a path which has less than 5
268  // states
269  if ( static_cast<sal_Int32>(aNewPathPos->second.size()) <= nCurrentStatePathIndex )
270  return;
271 
272  // assert that the current and the new path are equal, up to nCurrentStatePathIndex
273  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
274  if ( aActivePathPos != m_pImpl->aPaths.end() )
275  {
276  if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos->second, aNewPathPos->second ) <= nCurrentStatePathIndex )
277  {
278  OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
279  return;
280  }
281  }
282 
283  m_pImpl->nActivePath = _nPathId;
284  m_pImpl->bActivePathIsDefinite = _bDecideForIt;
285 
287  }
288 
290  {
291  DBG_ASSERT( m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath ) != m_xRoadmapImpl->aPaths.end(),
292  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
293  const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
294 
295  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
296  if (nCurrentStatePathIndex < 0)
297  return;
298 
299  // determine up to which index (in the new path) we have to display the items
300  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
301  bool bIncompletePath = false;
302  if ( !m_xRoadmapImpl->bActivePathIsDefinite )
303  {
304  for (auto const& path : m_xRoadmapImpl->aPaths)
305  {
306  if ( path.first == m_xRoadmapImpl->nActivePath )
307  // it's the path we are just activating -> no need to check anything
308  continue;
309  // the index from which on both paths differ
310  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
311  if ( nDivergenceIndex <= nCurrentStatePathIndex )
312  // they differ in an index which we have already left behind us
313  // -> this is no conflict anymore
314  continue;
315 
316  // the path conflicts with our new path -> don't activate the
317  // *complete* new path, but only up to the step which is unambiguous
318  nUpperStepBoundary = nDivergenceIndex;
319  bIncompletePath = true;
320  }
321  }
322 
323  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
324  // path, up to (excluding) nUpperStepBoundary
325  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, m_xRoadmapImpl->pRoadmap->GetItemCount() );
326  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
327  {
328  bool bExistentItem = ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() );
329  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
330 
331  bool bInsertItem = false;
332  if ( bExistentItem )
333  {
334  if ( !bNeedItem )
335  {
336  while ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() )
337  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
338  break;
339  }
340  else
341  {
342  // there is an item with this index in the roadmap - does it match what is requested by
343  // the respective state in the active path?
344  RoadmapTypes::ItemId nPresentItemId = m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex );
345  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
346  if ( nPresentItemId != nRequiredState )
347  {
348  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
349  bInsertItem = true;
350  }
351  }
352  }
353  else
354  {
355  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
356  bInsertItem = bNeedItem;
357  }
358 
359  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
360  if ( bInsertItem )
361  {
362  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(
363  nItemIndex,
364  getStateDisplayName( nState ),
365  nState,
366  true
367  );
368  }
369 
370  const bool bEnable = m_xRoadmapImpl->aDisabledStates.find( nState ) == m_xRoadmapImpl->aDisabledStates.end();
371  m_xRoadmapImpl->pRoadmap->EnableRoadmapItem( m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex ), bEnable );
372  }
373 
374  m_xRoadmapImpl->pRoadmap->SetRoadmapComplete( !bIncompletePath );
375  }
376 
378  {
379 
380  DBG_ASSERT( m_pImpl->aPaths.find( m_pImpl->nActivePath ) != m_pImpl->aPaths.end(),
381  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
382  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
383 
384  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
385  if (nCurrentStatePathIndex < 0)
386  return;
387 
388  // determine up to which index (in the new path) we have to display the items
389  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
390  if ( !m_pImpl->bActivePathIsDefinite )
391  {
392  for (auto const& path : m_pImpl->aPaths)
393  {
394  if ( path.first == m_pImpl->nActivePath )
395  // it's the path we are just activating -> no need to check anything
396  continue;
397  // the index from which on both paths differ
398  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
399  if ( nDivergenceIndex <= nCurrentStatePathIndex )
400  // they differ in an index which we have already left behind us
401  // -> this is no conflict anymore
402  continue;
403 
404  // the path conflicts with our new path -> don't activate the
405  // *complete* new path, but only up to the step which is unambiguous
406  nUpperStepBoundary = nDivergenceIndex;
407  }
408  }
409 
410  // can we advance from the current page?
411  bool bCurrentPageCanAdvance = true;
412  BuilderPage* pCurrentPage = GetPage( getCurrentState() );
413  if ( pCurrentPage )
414  {
415  const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
416  OSL_ENSURE( pController != nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
417  bCurrentPageCanAdvance = !pController || pController->canAdvance();
418  }
419 
420  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
421  // path, up to (excluding) nUpperStepBoundary
422  RoadmapTypes::ItemIndex nRoadmapItems = m_xAssistant->get_n_pages();
423  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, nRoadmapItems );
424  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
425  {
426  bool bExistentItem = ( nItemIndex < nRoadmapItems );
427  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
428 
429  bool bInsertItem = false;
430  if ( bExistentItem )
431  {
432  if ( !bNeedItem )
433  {
434  int nPages = nRoadmapItems;
435  for (int i = nPages - 1; i >= nItemIndex; --i)
436  {
437  m_xAssistant->set_page_title(m_xAssistant->get_page_ident(i), "");
438  --nRoadmapItems;
439  }
440  break;
441  }
442  else
443  {
444  // there is an item with this index in the roadmap - does it match what is requested by
445  // the respective state in the active path?
446  RoadmapTypes::ItemId nPresentItemId = m_xAssistant->get_page_ident(nItemIndex).toInt32();
447  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
448  if ( nPresentItemId != nRequiredState )
449  {
450  m_xAssistant->set_page_title(OString::number(nPresentItemId), "");
451  bInsertItem = true;
452  }
453  }
454  }
455  else
456  {
457  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
458  bInsertItem = bNeedItem;
459  }
460 
461  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
462 
463  if ( bInsertItem )
464  {
465  GetOrCreatePage(nState);
466  }
467 
468  OString sIdent(OString::number(nState));
469  m_xAssistant->set_page_index(sIdent, nItemIndex);
470  m_xAssistant->set_page_title(sIdent, getStateDisplayName(nState));
471 
472  // if the item is *after* the current state, but the current page does not
473  // allow advancing, the disable the state. This relieves derived classes
474  // from disabling all future states just because the current state does not
475  // (yet) allow advancing.
476  const bool bUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex );
477  const bool bEnable = !bUnconditionedDisable && ( m_pImpl->aDisabledStates.find( nState ) == m_pImpl->aDisabledStates.end() );
478  m_xAssistant->set_page_sensitive(sIdent, bEnable);
479  }
480  }
481 
483  {
484  sal_Int32 nCurrentStatePathIndex = -1;
485 
486  Paths::const_iterator aActivePathPos = m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath );
487  if ( aActivePathPos != m_xRoadmapImpl->aPaths.end() )
488  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
489 
490  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
491  if ( nCurrentStatePathIndex == -1 )
492  return WZS_INVALID_STATE;
493 
494  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
495 
496  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
497  && ( m_xRoadmapImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_xRoadmapImpl->aDisabledStates.end() )
498  )
499  {
500  ++nNextStateIndex;
501  }
502 
503  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
504  // there is no next state in the current path (at least none which is enabled)
505  return WZS_INVALID_STATE;
506 
507  return aActivePathPos->second[ nNextStateIndex ];
508  }
509 
511  {
512  sal_Int32 nCurrentStatePathIndex = -1;
513 
514  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
515  if ( aActivePathPos != m_pImpl->aPaths.end() )
516  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
517 
518  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
519  if ( nCurrentStatePathIndex == -1 )
520  return WZS_INVALID_STATE;
521 
522  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
523 
524  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
525  && ( m_pImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_pImpl->aDisabledStates.end() )
526  )
527  {
528  ++nNextStateIndex;
529  }
530 
531  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
532  // there is no next state in the current path (at least none which is enabled)
533  return WZS_INVALID_STATE;
534 
535  return aActivePathPos->second[ nNextStateIndex ];
536  }
537 
539  {
540  if ( !m_pImpl->bActivePathIsDefinite )
541  {
542  // check how many paths are still allowed
543  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
544 
545  // if current path has only the base item, it is not possible to proceed without activating another path
546  if(rActivePath.size()<=1)
547  return false;
548 
549  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
550 
551  size_t nPossiblePaths(0);
552  for (auto const& path : m_pImpl->aPaths)
553  {
554  // the index from which on both paths differ
555  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
556 
557  if ( nDivergenceIndex > nCurrentStatePathIndex )
558  // this path is still a possible path
559  nPossiblePaths += 1;
560  }
561 
562  // if we have more than one path which is still possible, then we assume
563  // to always have a next state. Though there might be scenarios where this
564  // is not true, but this is too sophisticated (means not really needed) right now.
565  if ( nPossiblePaths > 1 )
566  return true;
567  }
568 
569  const WizardPath& rPath = m_pImpl->aPaths[ m_pImpl->nActivePath ];
570  return *rPath.rbegin() != getCurrentState();
571  }
572 
574  {
576 
577  // disable the "Previous" button if all states in our history are disabled
578  std::vector< WizardTypes::WizardState > aHistory;
579  getStateHistory( aHistory );
580  bool bHaveEnabledState = false;
581  for (auto const& state : aHistory)
582  {
583  if ( isStateEnabled(state) )
584  {
585  bHaveEnabledState = true;
586  break;
587  }
588  }
589 
590  enableButtons( WizardButtonFlags::PREVIOUS, bHaveEnabledState );
591 
593  }
594 
595  IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void)
596  {
597  RoadmapTypes::ItemId nCurItemId = m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
598  if ( nCurItemId == getCurrentState() )
599  // nothing to do
600  return;
601 
602  if ( isTravelingSuspended() )
603  return;
604 
605  RoadmapWizardTravelSuspension aTravelGuard( *this );
606 
607  sal_Int32 nCurrentIndex = m_xRoadmapImpl->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl->nActivePath );
608  sal_Int32 nNewIndex = m_xRoadmapImpl->getStateIndexInPath( nCurItemId, m_xRoadmapImpl->nActivePath );
609 
610  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
611  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
612  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
613  {
614  return;
615  }
616 
617  bool bResult = true;
618  if ( nNewIndex > nCurrentIndex )
619  {
620  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
621  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
622  while( nTemp )
623  {
624  if( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
625  removePageFromHistory( nTemp );
626  }
627  }
628  else
629  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
630 
631  if ( !bResult )
632  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
633  }
634 
635  IMPL_LINK(RoadmapWizardMachine, OnRoadmapItemSelected, const OString&, rCurItemId, bool)
636  {
637  int nCurItemId = rCurItemId.toInt32();
638 
639  if ( nCurItemId == getCurrentState() )
640  // nothing to do
641  return false;
642 
643  if ( isTravelingSuspended() )
644  return false;
645 
646  WizardTravelSuspension aTravelGuard( *this );
647 
648  sal_Int32 nCurrentIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
649  sal_Int32 nNewIndex = m_pImpl->getStateIndexInPath( nCurItemId, m_pImpl->nActivePath );
650 
651  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
652  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
653  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
654  {
655  return false;
656  }
657 
658  bool bResult = true;
659  if ( nNewIndex > nCurrentIndex )
660  {
661  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
662  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
663  while( nTemp )
664  {
665  if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() )
666  removePageFromHistory( nTemp );
667  }
668  }
669  else
670  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
671 
672  return bResult;
673  }
674 
676  {
677  // synchronize the roadmap
679  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
680  }
681 
683  {
684  WizardMachine::enterState( _nState );
685 
686  // synchronize the roadmap
688  }
689 
691  {
692  OUString sDisplayName;
693 
694  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
695  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
696  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
697  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
698  sDisplayName = pos->second.first;
699 
700  return sDisplayName;
701  }
702 
704  {
705  OUString sDisplayName;
706 
707  StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState );
708  OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(),
709  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
710  if ( pos != m_pImpl->aStateDescriptors.end() )
711  sDisplayName = pos->second.first;
712 
713  return sDisplayName;
714  }
715 
717  {
718  VclPtr<TabPage> pPage;
719 
720  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
721  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
722  "RoadmapWizard::createPage: no default implementation available for this state!" );
723  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
724  {
725  RoadmapPageFactory pFactory = pos->second.second;
726  pPage = (*pFactory)( *this );
727  }
728 
729  return pPage;
730  }
731 
733  {
734  // remember this (in case the state appears in the roadmap later on)
735  if ( _bEnable )
736  m_pImpl->aDisabledStates.erase( _nState );
737  else
738  {
739  m_pImpl->aDisabledStates.insert( _nState );
740  removePageFromHistory( _nState );
741  }
742 
743  // if the state is currently in the roadmap, reflect it's new status
744  m_xAssistant->set_page_sensitive(OString::number(_nState), _bEnable);
745  }
746 
748  {
749  for (auto const& path : m_pImpl->aPaths)
750  {
751  for (auto const& state : path.second)
752  {
753  if ( state == i_nState )
754  return true;
755  }
756  }
757  return false;
758  }
759 
761  {
762  return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end();
763  }
764 
765  void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable)
766  {
767  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable);
768  }
769 
770  void RoadmapWizard::SelectRoadmapItemByID(int nItemId, bool bGrabFocus)
771  {
772  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID(nItemId, bGrabFocus);
773  }
774 
776  {
777  while (m_xRoadmapImpl->pRoadmap->GetItemCount())
778  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem(0);
779  }
780 
782  {
783  m_xRoadmapImpl->pRoadmap->SetItemSelectHdl(_rHdl);
784  }
785 
787  {
788  return m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
789  }
790 
792  {
794  }
795 
796 } // namespace vcl
797 
798 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void declarePath(RoadmapWizardTypes::PathId _nPathId, const RoadmapWizardTypes::WizardPath &_lWizardStates)
declares a valid path in the wizard
sal_Int32 ItemIndex
Definition: roadmap.hxx:41
wizard for a roadmap
Definition: wizdlg.hxx:65
VCL_DLLPRIVATE void implUpdateRoadmap()
updates the roadmap control to show the given path, as far as possible (modulo conflicts with other p...
virtual OUString getStateDisplayName(WizardTypes::WizardState nState) const
returns a human readable name for a given state
virtual WizardTypes::WizardState determineNextState(WizardTypes::WizardState nCurrentState) const override
determine the next state to travel from the given one
void ShowRoadmap(bool bShow)
VclPtr< vcl::Window > mpViewWindow
Definition: wizdlg.hxx:75
A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for refer...
Definition: button.hxx:34
sal_uInt16 mnCurLevel
Definition: wizdlg.hxx:76
Resize runs before repaint, so we won't paint twice.
virtual ~RoadmapWizardMachine() override
std::unique_ptr< WizardMachineImplData > m_xWizardImpl
Definition: wizdlg.hxx:104
virtual void updateTravelUI() override
updates the user interface which deals with traveling in the wizard
void disposeAndClear()
Definition: vclptr.hxx:200
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual Size GetSizePixel() const
Definition: window.cxx:2402
void SetItemSelectHdl(const Link< LinkParamNone *, void > &_rHdl)
sal_Int16 mnLeftAlignCount
Definition: wizdlg.hxx:77
RoadmapWizard(vcl::Window *pParent, WinBits nStyle=WB_STDDIALOG, InitFlag eFlag=InitFlag::Default)
ImplWizPageData * mpFirstPage
Definition: wizdlg.hxx:70
is - no, not a wizard for a roadmap, but the base class for wizards supporting a roadmap.
virtual IWizardPageController * getPageController(BuilderPage *pCurrentPage) const
VclPtr< Button > mpButton
Definition: wizimpldata.hxx:34
virtual void enterState(WizardTypes::WizardState nState) override
will be called when a new page is about to be displayed
WizardButtonFlags
Definition: vclenum.hxx:276
static sal_Int32 getStateIndexInPath(WizardTypes::WizardState _nState, const WizardPath &_rPath)
returns the index of the current state in given path, or -1
sal_Int64 WinBits
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: dialog.cxx:620
WizardTypes::WizardState getCurrentState() const
returns the current state of the machine
Definition: wizdlg.hxx:213
PREVIOUS
size_t pos
VclPtr< TabPage > mpPage
Definition: wizdlg.hxx:32
#define WZS_INVALID_STATE
FactoryFunction GetUITestFactory() const override
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
void removePageFromHistory(WizardTypes::WizardState nToRemove)
removes a page from the history.
void SetLeftAlignedButtonCount(sal_Int16 _nCount)
sets the number of buttons which should be left-aligned.
VclPtr< TabPage > mpCurTabPage
Definition: wizdlg.hxx:72
void RemoveButton(Button *pButton)
VclPtr< TabPage > createPage(WizardTypes::WizardState nState)
to override to create new pages
OUString VclResId(TranslateId aId)
Definition: svdata.cxx:258
ScopedVclPtr< ORoadmap > pRoadmap
ImplWizButtonData * mpFirstBtn
Definition: wizdlg.hxx:71
void clear()
Definition: vclptr.hxx:190
virtual bool canAdvance() const override
determines whether there is a next state to which we can advance
TabPage * GetPage(sal_uInt16 nLevel) const
Point LogicToPixel(const Point &rLogicPt) const
Definition: window3.cxx:131
#define DBG_ASSERT(sCon, aError)
int i
VclPtr< PushButton > m_pNextPage
Definition: wizdlg.hxx:99
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
std::unique_ptr< RoadmapWizardImpl > m_pImpl
sal_Int16 WizardState
virtual bool canAdvance() const =0
determines whether or not it is allowed to advance to a next page
OUString getStateDisplayName(WizardTypes::WizardState nState) const
returns a human readable name for a given state
WizardTypes::WizardState determineNextState(WizardTypes::WizardState nCurrentState) const
determine the next state to travel from the given one
void SetRoadmapHelpId(const OString &_rId)
void activatePath(RoadmapWizardTypes::PathId _nPathId, bool _bDecideForIt=false)
activates a path which has previously been declared with declarePath ...
static sal_Int32 getFirstDifferentIndex(const WizardPath &_rLHS, const WizardPath &_rRHS)
returns the index of the first state in which the two given paths differ
void implUpdateRoadmap()
updates the roadmap control to show the given path, as far as possible (modulo conflicts with other p...
VclPtr< PushButton > mpNextBtn
Definition: wizdlg.hxx:74
sal_Int16 ItemId
Definition: roadmap.hxx:40
implements some kind of finite automata, where the states of the automata exactly correlate with tab ...
WizardTypes::WizardState getCurrentState() const
returns the current state of the machine
void enableState(WizardTypes::WizardState nState, bool _bEnable=true)
en- or disables a state
InitFlag
Definition: dialog.hxx:43
NEXT
helper class to temporarily suspend any traveling in the wizard
Definition: wizdlg.hxx:261
VclPtr< PushButton > mpPrevBtn
Definition: wizdlg.hxx:73
std::unique_ptr< RoadmapWizardImpl > m_xRoadmapImpl
Definition: wizdlg.hxx:106
void SetRoadmapHelpId(const OString &_rId)
bool knowsState(WizardTypes::WizardState nState) const
returns true if and only if the given state is known in at least one declared path ...
void Stop()
Definition: scheduler.cxx:590
void RemovePage(TabPage *pPage)
void implConstruct(const WizardButtonFlags _nButtonFlags)
void getStateHistory(std::vector< WizardTypes::WizardState > &out_rHistory)
retrieves a copy of the state history, i.e.
::std::vector< WizardTypes::WizardState > WizardPath
VclPtr< CancelButton > m_pCancel
Definition: wizdlg.hxx:98
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
void SelectRoadmapItemByID(int nId, bool bGrabFocus=true)
StateDescriptions aStateDescriptors
void enterState(WizardTypes::WizardState _nState)
will be called when a new page is about to be displayed
void enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable)
enable (or disable) buttons
WinBits const WB_TABSTOP
int GetCurrentRoadmapItemID() const
IMPL_LINK(ORoadmap, ImplClickHdl, HyperLabel *, CurHyperLabel, void)
Definition: roadmap.cxx:633
void setHeight(tools::Long nHeight)
BuilderPage * GetPage(WizardTypes::WizardState eState) const
void SetPriority(TaskPriority ePriority)
Definition: scheduler.cxx:597
virtual void updateTravelUI()
updates the user interface which deals with traveling in the wizard
void InsertRoadmapItem(int nIndex, const OUString &rLabel, int nId, bool bEnabled)
VclPtr< PushButton > m_pPrevPage
Definition: wizdlg.hxx:100
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
RoadmapWizardMachine(weld::Window *_pParent)
IMPL_LINK_NOARG(QuickSelectionEngine_Data, SearchStringTimeout, Timer *, void)
bool mbEmptyViewMargin
Definition: wizdlg.hxx:78
BuilderPage * GetOrCreatePage(const WizardTypes::WizardState i_nState)
bool isStateEnabled(WizardTypes::WizardState nState) const
virtual void enterState(WizardTypes::WizardState _nState)
will be called when a new page is about to be displayed
std::unique_ptr< weld::Assistant > m_xAssistant
Definition: weld.hxx:2557
sal_Int32 nState
VclPtr< OKButton > m_pFinish
Definition: wizdlg.hxx:97
VclPtr< HelpButton > m_pHelp
Definition: wizdlg.hxx:101
VclPtr< TabPage >(* RoadmapPageFactory)(RoadmapWizard &)
Definition: wizdlg.hxx:42
Idle maWizardLayoutIdle
Definition: wizdlg.hxx:68
helper class to temporarily suspend any traveling in the wizard
virtual ~RoadmapWizard() override
OUString sDisplayName