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  , m_pFinish(nullptr)
127  , m_pCancel(nullptr)
128  , m_pNextPage(nullptr)
129  , m_pPrevPage(nullptr)
130  , m_pHelp(nullptr)
131  , m_xWizardImpl(new WizardMachineImplData)
132  , m_xRoadmapImpl(new RoadmapWizardImpl)
133  {
134  mpFirstPage = nullptr;
135  mpFirstBtn = nullptr;
136  mpCurTabPage = nullptr;
137  mpPrevBtn = nullptr;
138  mpNextBtn = nullptr;
139  mpViewWindow = nullptr;
140  mnCurLevel = 0;
141  mbEmptyViewMargin = false;
142  mnLeftAlignCount = 0;
143 
145  maWizardLayoutIdle.SetInvokeHandler( LINK( this, RoadmapWizard, ImplHandleWizardLayoutTimerHdl ) );
146 
148 
150  mbEmptyViewMargin = true;
151 
152  m_xRoadmapImpl->pRoadmap.disposeAndReset( VclPtr<ORoadmap>::Create( this, WB_TABSTOP ) );
153  m_xRoadmapImpl->pRoadmap->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE ) );
154  m_xRoadmapImpl->pRoadmap->SetPosPixel( Point( 0, 0 ) );
155  m_xRoadmapImpl->pRoadmap->SetItemSelectHdl( LINK( this, RoadmapWizard, OnRoadmapItemSelected ) );
156 
157  Size aRoadmapSize = LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont));
158  aRoadmapSize.setHeight( GetSizePixel().Height() );
159  m_xRoadmapImpl->pRoadmap->SetSizePixel( aRoadmapSize );
160 
161  mpViewWindow = m_xRoadmapImpl->pRoadmap;
162  m_xRoadmapImpl->pRoadmap->Show();
163  }
164 
167  , m_pImpl( new RoadmapWizardImpl )
168  {
169  m_xAssistant->connect_jump_page(LINK(this, RoadmapWizardMachine, OnRoadmapItemSelected));
170  }
171 
172  void RoadmapWizard::ShowRoadmap(bool bShow)
173  {
174  m_xRoadmapImpl->pRoadmap->Show(bShow);
175  CalcAndSetSize();
176  }
177 
179  {
180  disposeOnce();
181  }
182 
184  {
185  }
186 
188  {
189  m_xRoadmapImpl.reset();
190 
196 
197  if (m_xWizardImpl)
198  {
199  for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
200  {
201  TabPage *pPage = GetPage(i);
202  if (pPage)
203  pPage->disposeOnce();
204  }
205  m_xWizardImpl.reset();
206  }
207 
209 
210  // Remove all buttons
211  while ( mpFirstBtn )
213 
214  // Remove all pages
215  while ( mpFirstPage )
217 
219  mpPrevBtn.clear();
220  mpNextBtn.clear();
222  Dialog::dispose();
223  }
224 
225  void RoadmapWizard::SetRoadmapHelpId( const OString& _rId )
226  {
227  m_xRoadmapImpl->pRoadmap->SetHelpId( _rId );
228  }
229 
230  void RoadmapWizardMachine::SetRoadmapHelpId(const OString& rId)
231  {
232  m_xAssistant->set_page_side_help_id(rId);
233  }
234 
235  void RoadmapWizardMachine::declarePath( PathId _nPathId, const WizardPath& _lWizardStates)
236  {
237  m_pImpl->aPaths.emplace( _nPathId, _lWizardStates );
238 
239  if ( m_pImpl->aPaths.size() == 1 )
240  // the very first path -> activate it
241  activatePath( _nPathId );
242  else
244  }
245 
246  void RoadmapWizardMachine::activatePath( PathId _nPathId, bool _bDecideForIt )
247  {
248  if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) )
249  // nothing to do
250  return;
251 
252  // does the given path exist?
253  Paths::const_iterator aNewPathPos = m_pImpl->aPaths.find( _nPathId );
254  DBG_ASSERT( aNewPathPos != m_pImpl->aPaths.end(), "RoadmapWizard::activate: there is no such path!" );
255  if ( aNewPathPos == m_pImpl->aPaths.end() )
256  return;
257 
258  // determine the index of the current state in the current path
259  sal_Int32 nCurrentStatePathIndex = -1;
260  if ( m_pImpl->nActivePath != -1 )
261  nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
262 
263  DBG_ASSERT( static_cast<sal_Int32>(aNewPathPos->second.size()) > nCurrentStatePathIndex,
264  "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
265  // If this asserts, this for instance means that we are already in state number, say, 5
266  // of our current path, and the caller tries to activate a path which has less than 5
267  // states
268  if ( static_cast<sal_Int32>(aNewPathPos->second.size()) <= nCurrentStatePathIndex )
269  return;
270 
271  // assert that the current and the new path are equal, up to nCurrentStatePathIndex
272  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
273  if ( aActivePathPos != m_pImpl->aPaths.end() )
274  {
275  if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos->second, aNewPathPos->second ) <= nCurrentStatePathIndex )
276  {
277  OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
278  return;
279  }
280  }
281 
282  m_pImpl->nActivePath = _nPathId;
283  m_pImpl->bActivePathIsDefinite = _bDecideForIt;
284 
286  }
287 
289  {
290  DBG_ASSERT( m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath ) != m_xRoadmapImpl->aPaths.end(),
291  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
292  const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
293 
294  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
295  if (nCurrentStatePathIndex < 0)
296  return;
297 
298  // determine up to which index (in the new path) we have to display the items
299  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
300  bool bIncompletePath = false;
301  if ( !m_xRoadmapImpl->bActivePathIsDefinite )
302  {
303  for (auto const& path : m_xRoadmapImpl->aPaths)
304  {
305  if ( path.first == m_xRoadmapImpl->nActivePath )
306  // it's the path we are just activating -> no need to check anything
307  continue;
308  // the index from which on both paths differ
309  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
310  if ( nDivergenceIndex <= nCurrentStatePathIndex )
311  // they differ in an index which we have already left behind us
312  // -> this is no conflict anymore
313  continue;
314 
315  // the path conflicts with our new path -> don't activate the
316  // *complete* new path, but only up to the step which is unambiguous
317  nUpperStepBoundary = nDivergenceIndex;
318  bIncompletePath = true;
319  }
320  }
321 
322  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
323  // path, up to (excluding) nUpperStepBoundary
324  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, m_xRoadmapImpl->pRoadmap->GetItemCount() );
325  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
326  {
327  bool bExistentItem = ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() );
328  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
329 
330  bool bInsertItem = false;
331  if ( bExistentItem )
332  {
333  if ( !bNeedItem )
334  {
335  while ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() )
336  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
337  break;
338  }
339  else
340  {
341  // there is an item with this index in the roadmap - does it match what is requested by
342  // the respective state in the active path?
343  RoadmapTypes::ItemId nPresentItemId = m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex );
344  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
345  if ( nPresentItemId != nRequiredState )
346  {
347  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
348  bInsertItem = true;
349  }
350  }
351  }
352  else
353  {
354  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
355  bInsertItem = bNeedItem;
356  }
357 
358  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
359  if ( bInsertItem )
360  {
361  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(
362  nItemIndex,
363  getStateDisplayName( nState ),
364  nState,
365  true
366  );
367  }
368 
369  const bool bEnable = m_xRoadmapImpl->aDisabledStates.find( nState ) == m_xRoadmapImpl->aDisabledStates.end();
370  m_xRoadmapImpl->pRoadmap->EnableRoadmapItem( m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex ), bEnable );
371  }
372 
373  m_xRoadmapImpl->pRoadmap->SetRoadmapComplete( !bIncompletePath );
374  }
375 
377  {
378 
379  DBG_ASSERT( m_pImpl->aPaths.find( m_pImpl->nActivePath ) != m_pImpl->aPaths.end(),
380  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
381  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
382 
383  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
384  if (nCurrentStatePathIndex < 0)
385  return;
386 
387  // determine up to which index (in the new path) we have to display the items
388  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
389  if ( !m_pImpl->bActivePathIsDefinite )
390  {
391  for (auto const& path : m_pImpl->aPaths)
392  {
393  if ( path.first == m_pImpl->nActivePath )
394  // it's the path we are just activating -> no need to check anything
395  continue;
396  // the index from which on both paths differ
397  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
398  if ( nDivergenceIndex <= nCurrentStatePathIndex )
399  // they differ in an index which we have already left behind us
400  // -> this is no conflict anymore
401  continue;
402 
403  // the path conflicts with our new path -> don't activate the
404  // *complete* new path, but only up to the step which is unambiguous
405  nUpperStepBoundary = nDivergenceIndex;
406  }
407  }
408 
409  // can we advance from the current page?
410  bool bCurrentPageCanAdvance = true;
411  BuilderPage* pCurrentPage = GetPage( getCurrentState() );
412  if ( pCurrentPage )
413  {
414  const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
415  OSL_ENSURE( pController != nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
416  bCurrentPageCanAdvance = !pController || pController->canAdvance();
417  }
418 
419  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
420  // path, up to (excluding) nUpperStepBoundary
421  RoadmapTypes::ItemIndex nRoadmapItems = m_xAssistant->get_n_pages();
422  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, nRoadmapItems );
423  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
424  {
425  bool bExistentItem = ( nItemIndex < nRoadmapItems );
426  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
427 
428  bool bInsertItem = false;
429  if ( bExistentItem )
430  {
431  if ( !bNeedItem )
432  {
433  int nPages = nRoadmapItems;
434  for (int i = nPages - 1; i >= nItemIndex; --i)
435  {
436  m_xAssistant->set_page_title(m_xAssistant->get_page_ident(i), "");
437  --nRoadmapItems;
438  }
439  break;
440  }
441  else
442  {
443  // there is an item with this index in the roadmap - does it match what is requested by
444  // the respective state in the active path?
445  RoadmapTypes::ItemId nPresentItemId = m_xAssistant->get_page_ident(nItemIndex).toInt32();
446  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
447  if ( nPresentItemId != nRequiredState )
448  {
449  m_xAssistant->set_page_title(OString::number(nPresentItemId), "");
450  bInsertItem = true;
451  }
452  }
453  }
454  else
455  {
456  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
457  bInsertItem = bNeedItem;
458  }
459 
460  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
461 
462  if ( bInsertItem )
463  {
464  GetOrCreatePage(nState);
465  }
466 
467  OString sIdent(OString::number(nState));
468  m_xAssistant->set_page_index(sIdent, nItemIndex);
469  m_xAssistant->set_page_title(sIdent, getStateDisplayName(nState));
470 
471  // if the item is *after* the current state, but the current page does not
472  // allow advancing, the disable the state. This relieves derived classes
473  // from disabling all future states just because the current state does not
474  // (yet) allow advancing.
475  const bool bUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex );
476  const bool bEnable = !bUnconditionedDisable && ( m_pImpl->aDisabledStates.find( nState ) == m_pImpl->aDisabledStates.end() );
477  m_xAssistant->set_page_sensitive(sIdent, bEnable);
478  }
479  }
480 
482  {
483  sal_Int32 nCurrentStatePathIndex = -1;
484 
485  Paths::const_iterator aActivePathPos = m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath );
486  if ( aActivePathPos != m_xRoadmapImpl->aPaths.end() )
487  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
488 
489  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
490  if ( nCurrentStatePathIndex == -1 )
491  return WZS_INVALID_STATE;
492 
493  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
494 
495  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
496  && ( m_xRoadmapImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_xRoadmapImpl->aDisabledStates.end() )
497  )
498  {
499  ++nNextStateIndex;
500  }
501 
502  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
503  // there is no next state in the current path (at least none which is enabled)
504  return WZS_INVALID_STATE;
505 
506  return aActivePathPos->second[ nNextStateIndex ];
507  }
508 
510  {
511  sal_Int32 nCurrentStatePathIndex = -1;
512 
513  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
514  if ( aActivePathPos != m_pImpl->aPaths.end() )
515  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
516 
517  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
518  if ( nCurrentStatePathIndex == -1 )
519  return WZS_INVALID_STATE;
520 
521  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
522 
523  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
524  && ( m_pImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_pImpl->aDisabledStates.end() )
525  )
526  {
527  ++nNextStateIndex;
528  }
529 
530  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
531  // there is no next state in the current path (at least none which is enabled)
532  return WZS_INVALID_STATE;
533 
534  return aActivePathPos->second[ nNextStateIndex ];
535  }
536 
538  {
539  if ( !m_pImpl->bActivePathIsDefinite )
540  {
541  // check how many paths are still allowed
542  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
543 
544  // if current path has only the base item, it is not possible to proceed without activating another path
545  if(rActivePath.size()<=1)
546  return false;
547 
548  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
549 
550  size_t nPossiblePaths(0);
551  for (auto const& path : m_pImpl->aPaths)
552  {
553  // the index from which on both paths differ
554  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
555 
556  if ( nDivergenceIndex > nCurrentStatePathIndex )
557  // this path is still a possible path
558  nPossiblePaths += 1;
559  }
560 
561  // if we have more than one path which is still possible, then we assume
562  // to always have a next state. Though there might be scenarios where this
563  // is not true, but this is too sophisticated (means not really needed) right now.
564  if ( nPossiblePaths > 1 )
565  return true;
566  }
567 
568  const WizardPath& rPath = m_pImpl->aPaths[ m_pImpl->nActivePath ];
569  return *rPath.rbegin() != getCurrentState();
570  }
571 
573  {
575 
576  // disable the "Previous" button if all states in our history are disabled
577  std::vector< WizardTypes::WizardState > aHistory;
578  getStateHistory( aHistory );
579  bool bHaveEnabledState = false;
580  for (auto const& state : aHistory)
581  {
582  if ( isStateEnabled(state) )
583  {
584  bHaveEnabledState = true;
585  break;
586  }
587  }
588 
589  enableButtons( WizardButtonFlags::PREVIOUS, bHaveEnabledState );
590 
592  }
593 
594  IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void)
595  {
596  RoadmapTypes::ItemId nCurItemId = m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
597  if ( nCurItemId == getCurrentState() )
598  // nothing to do
599  return;
600 
601  if ( isTravelingSuspended() )
602  return;
603 
604  RoadmapWizardTravelSuspension aTravelGuard( *this );
605 
606  sal_Int32 nCurrentIndex = m_xRoadmapImpl->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl->nActivePath );
607  sal_Int32 nNewIndex = m_xRoadmapImpl->getStateIndexInPath( nCurItemId, m_xRoadmapImpl->nActivePath );
608 
609  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
610  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
611  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
612  {
613  return;
614  }
615 
616  bool bResult = true;
617  if ( nNewIndex > nCurrentIndex )
618  {
619  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
620  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
621  while( nTemp )
622  {
623  if( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
624  removePageFromHistory( nTemp );
625  }
626  }
627  else
628  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
629 
630  if ( !bResult )
631  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
632  }
633 
634  IMPL_LINK(RoadmapWizardMachine, OnRoadmapItemSelected, const OString&, rCurItemId, bool)
635  {
636  int nCurItemId = rCurItemId.toInt32();
637 
638  if ( nCurItemId == getCurrentState() )
639  // nothing to do
640  return false;
641 
642  if ( isTravelingSuspended() )
643  return false;
644 
645  WizardTravelSuspension aTravelGuard( *this );
646 
647  sal_Int32 nCurrentIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
648  sal_Int32 nNewIndex = m_pImpl->getStateIndexInPath( nCurItemId, m_pImpl->nActivePath );
649 
650  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
651  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
652  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
653  {
654  return false;
655  }
656 
657  bool bResult = true;
658  if ( nNewIndex > nCurrentIndex )
659  {
660  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
661  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
662  while( nTemp )
663  {
664  if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() )
665  removePageFromHistory( nTemp );
666  }
667  }
668  else
669  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
670 
671  return bResult;
672  }
673 
675  {
676  // synchronize the roadmap
678  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
679  }
680 
682  {
683  WizardMachine::enterState( _nState );
684 
685  // synchronize the roadmap
687  }
688 
690  {
691  OUString sDisplayName;
692 
693  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
694  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
695  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
696  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
697  sDisplayName = pos->second.first;
698 
699  return sDisplayName;
700  }
701 
703  {
704  OUString sDisplayName;
705 
706  StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState );
707  OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(),
708  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
709  if ( pos != m_pImpl->aStateDescriptors.end() )
710  sDisplayName = pos->second.first;
711 
712  return sDisplayName;
713  }
714 
716  {
717  VclPtr<TabPage> pPage;
718 
719  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
720  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
721  "RoadmapWizard::createPage: no default implementation available for this state!" );
722  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
723  {
724  RoadmapPageFactory pFactory = pos->second.second;
725  pPage = (*pFactory)( *this );
726  }
727 
728  return pPage;
729  }
730 
732  {
733  // remember this (in case the state appears in the roadmap later on)
734  if ( _bEnable )
735  m_pImpl->aDisabledStates.erase( _nState );
736  else
737  {
738  m_pImpl->aDisabledStates.insert( _nState );
739  removePageFromHistory( _nState );
740  }
741 
742  // if the state is currently in the roadmap, reflect it's new status
743  m_xAssistant->set_page_sensitive(OString::number(_nState), _bEnable);
744  }
745 
747  {
748  for (auto const& path : m_pImpl->aPaths)
749  {
750  for (auto const& state : path.second)
751  {
752  if ( state == i_nState )
753  return true;
754  }
755  }
756  return false;
757  }
758 
760  {
761  return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end();
762  }
763 
764  void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable)
765  {
766  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable);
767  }
768 
769  void RoadmapWizard::SelectRoadmapItemByID(int nItemId, bool bGrabFocus)
770  {
771  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID(nItemId, bGrabFocus);
772  }
773 
775  {
776  while (m_xRoadmapImpl->pRoadmap->GetItemCount())
777  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem(0);
778  }
779 
781  {
782  m_xRoadmapImpl->pRoadmap->SetItemSelectHdl(_rHdl);
783  }
784 
786  {
787  return m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
788  }
789 
791  {
793  }
794 
795 } // namespace vcl
796 
797 /* 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:2391
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:278
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
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
OUString VclResId(std::string_view aId)
Definition: svdata.cxx:259
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:2551
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