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 
35 namespace vcl
36 {
37  using namespace RoadmapWizardTypes;
38 
39  namespace
40  {
41  typedef ::std::set< WizardTypes::WizardState > StateSet;
42 
43  typedef ::std::map<
44  PathId,
46  > Paths;
47 
48  typedef ::std::map<
50  ::std::pair<
51  OUString,
53  >
54  > StateDescriptions;
55  }
56 
58  {
60  Paths aPaths;
62  StateDescriptions aStateDescriptors;
63  StateSet aDisabledStates;
65 
67  :pRoadmap( nullptr )
68  ,nActivePath( -1 )
69  ,bActivePathIsDefinite( false )
70  {
71  }
72 
74  static sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath );
76  sal_Int32 getStateIndexInPath( WizardTypes::WizardState _nState, PathId _nPathId );
78  static sal_Int32 getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS );
79  };
80 
81 
83  {
84  sal_Int32 nStateIndexInPath = 0;
85  bool bFound = false;
86  for (auto const& path : _rPath)
87  {
88  if (path == _nState)
89  {
90  bFound = true;
91  break;
92  }
93  ++nStateIndexInPath;
94  }
95  if (!bFound)
96  nStateIndexInPath = -1;
97  return nStateIndexInPath;
98  }
99 
100 
102  {
103  sal_Int32 nStateIndexInPath = -1;
104  Paths::const_iterator aPathPos = aPaths.find( _nPathId );
105  if ( aPathPos != aPaths.end( ) )
106  nStateIndexInPath = getStateIndexInPath( _nState, aPathPos->second );
107  return nStateIndexInPath;
108  }
109 
110 
111  sal_Int32 RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS )
112  {
113  sal_Int32 nMinLength = ::std::min( _rLHS.size(), _rRHS.size() );
114  for ( sal_Int32 nCheck = 0; nCheck < nMinLength; ++nCheck )
115  {
116  if ( _rLHS[ nCheck ] != _rRHS[ nCheck ] )
117  return nCheck;
118  }
119  return nMinLength;
120  }
121 
122  //= RoadmapWizard
124  : Dialog(pParent, nStyle, eFlag)
125  , m_pFinish(nullptr)
126  , m_pCancel(nullptr)
127  , m_pNextPage(nullptr)
128  , m_pPrevPage(nullptr)
129  , m_pHelp(nullptr)
130  , m_xWizardImpl(new WizardMachineImplData)
131  , m_xRoadmapImpl(new RoadmapWizardImpl)
132  {
133  ImplInitData();
134 
136 
137  impl_construct();
138  }
139 
142  , m_pImpl( new RoadmapWizardImpl )
143  {
144  m_xAssistant->connect_jump_page(LINK(this, RoadmapWizardMachine, OnRoadmapItemSelected));
145  }
146 
148  {
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  SetViewWindow( m_xRoadmapImpl->pRoadmap );
162  SetViewAlign( WindowAlign::Left );
163  m_xRoadmapImpl->pRoadmap->Show();
164  }
165 
166  void RoadmapWizard::ShowRoadmap(bool bShow)
167  {
168  m_xRoadmapImpl->pRoadmap->Show(bShow);
169  CalcAndSetSize();
170  }
171 
173  {
174  disposeOnce();
175  }
176 
178  {
179  }
180 
182  {
183  m_xRoadmapImpl.reset();
184 
190 
191  if (m_xWizardImpl)
192  {
193  for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
194  {
195  TabPage *pPage = GetPage(i);
196  if (pPage)
197  pPage->disposeOnce();
198  }
199  m_xWizardImpl.reset();
200  }
201 
203 
204  // Remove all buttons
205  while ( mpFirstBtn )
207 
208  // Remove all pages
209  while ( mpFirstPage )
211 
213  mpPrevBtn.clear();
214  mpNextBtn.clear();
216  Dialog::dispose();
217  }
218 
219  void RoadmapWizard::SetRoadmapHelpId( const OString& _rId )
220  {
221  m_xRoadmapImpl->pRoadmap->SetHelpId( _rId );
222  }
223 
224  void RoadmapWizardMachine::SetRoadmapHelpId(const OString& rId)
225  {
226  m_xAssistant->set_page_side_help_id(rId);
227  }
228 
229  void RoadmapWizardMachine::declarePath( PathId _nPathId, const WizardPath& _lWizardStates)
230  {
231  m_pImpl->aPaths.emplace( _nPathId, _lWizardStates );
232 
233  if ( m_pImpl->aPaths.size() == 1 )
234  // the very first path -> activate it
235  activatePath( _nPathId );
236  else
238  }
239 
240  void RoadmapWizardMachine::activatePath( PathId _nPathId, bool _bDecideForIt )
241  {
242  if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) )
243  // nothing to do
244  return;
245 
246  // does the given path exist?
247  Paths::const_iterator aNewPathPos = m_pImpl->aPaths.find( _nPathId );
248  DBG_ASSERT( aNewPathPos != m_pImpl->aPaths.end(), "RoadmapWizard::activate: there is no such path!" );
249  if ( aNewPathPos == m_pImpl->aPaths.end() )
250  return;
251 
252  // determine the index of the current state in the current path
253  sal_Int32 nCurrentStatePathIndex = -1;
254  if ( m_pImpl->nActivePath != -1 )
255  nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
256 
257  DBG_ASSERT( static_cast<sal_Int32>(aNewPathPos->second.size()) > nCurrentStatePathIndex,
258  "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" );
259  // If this asserts, this for instance means that we are already in state number, say, 5
260  // of our current path, and the caller tries to activate a path which has less than 5
261  // states
262  if ( static_cast<sal_Int32>(aNewPathPos->second.size()) <= nCurrentStatePathIndex )
263  return;
264 
265  // assert that the current and the new path are equal, up to nCurrentStatePathIndex
266  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
267  if ( aActivePathPos != m_pImpl->aPaths.end() )
268  {
269  if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos->second, aNewPathPos->second ) <= nCurrentStatePathIndex )
270  {
271  OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" );
272  return;
273  }
274  }
275 
276  m_pImpl->nActivePath = _nPathId;
277  m_pImpl->bActivePathIsDefinite = _bDecideForIt;
278 
280  }
281 
283  {
284  DBG_ASSERT( m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath ) != m_xRoadmapImpl->aPaths.end(),
285  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
286  const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
287 
288  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
289  if (nCurrentStatePathIndex < 0)
290  return;
291 
292  // determine up to which index (in the new path) we have to display the items
293  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
294  bool bIncompletePath = false;
295  if ( !m_xRoadmapImpl->bActivePathIsDefinite )
296  {
297  for (auto const& path : m_xRoadmapImpl->aPaths)
298  {
299  if ( path.first == m_xRoadmapImpl->nActivePath )
300  // it's the path we are just activating -> no need to check anything
301  continue;
302  // the index from which on both paths differ
303  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
304  if ( nDivergenceIndex <= nCurrentStatePathIndex )
305  // they differ in an index which we have already left behind us
306  // -> this is no conflict anymore
307  continue;
308 
309  // the path conflicts with our new path -> don't activate the
310  // *complete* new path, but only up to the step which is unambiguous
311  nUpperStepBoundary = nDivergenceIndex;
312  bIncompletePath = true;
313  }
314  }
315 
316  // can we advance from the current page?
317  bool bCurrentPageCanAdvance = true;
318  TabPage* pCurrentPage = GetPage( getCurrentState() );
319  if ( pCurrentPage )
320  {
321  const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
322  OSL_ENSURE( pController != nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
323  bCurrentPageCanAdvance = !pController || pController->canAdvance();
324  }
325 
326  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
327  // path, up to (excluding) nUpperStepBoundary
328  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, m_xRoadmapImpl->pRoadmap->GetItemCount() );
329  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
330  {
331  bool bExistentItem = ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() );
332  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
333 
334  bool bInsertItem = false;
335  if ( bExistentItem )
336  {
337  if ( !bNeedItem )
338  {
339  while ( nItemIndex < m_xRoadmapImpl->pRoadmap->GetItemCount() )
340  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
341  break;
342  }
343  else
344  {
345  // there is an item with this index in the roadmap - does it match what is requested by
346  // the respective state in the active path?
347  RoadmapTypes::ItemId nPresentItemId = m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex );
348  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
349  if ( nPresentItemId != nRequiredState )
350  {
351  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem( nItemIndex );
352  bInsertItem = true;
353  }
354  }
355  }
356  else
357  {
358  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
359  bInsertItem = bNeedItem;
360  }
361 
362  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
363  if ( bInsertItem )
364  {
365  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(
366  nItemIndex,
367  getStateDisplayName( nState ),
368  nState,
369  true
370  );
371  }
372 
373  // if the item is *after* the current state, but the current page does not
374  // allow advancing, the disable the state. This relieves derived classes
375  // from disabling all future states just because the current state does not
376  // (yet) allow advancing.
377  const bool bUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex );
378  const bool bEnable = !bUnconditionedDisable && ( m_xRoadmapImpl->aDisabledStates.find( nState ) == m_xRoadmapImpl->aDisabledStates.end() );
379 
380  m_xRoadmapImpl->pRoadmap->EnableRoadmapItem( m_xRoadmapImpl->pRoadmap->GetItemID( nItemIndex ), bEnable );
381  }
382 
383  m_xRoadmapImpl->pRoadmap->SetRoadmapComplete( !bIncompletePath );
384  }
385 
387  {
388 
389  DBG_ASSERT( m_pImpl->aPaths.find( m_pImpl->nActivePath ) != m_pImpl->aPaths.end(),
390  "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
391  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
392 
393  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
394  if (nCurrentStatePathIndex < 0)
395  return;
396 
397  // determine up to which index (in the new path) we have to display the items
398  RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
399  if ( !m_pImpl->bActivePathIsDefinite )
400  {
401  for (auto const& path : m_pImpl->aPaths)
402  {
403  if ( path.first == m_pImpl->nActivePath )
404  // it's the path we are just activating -> no need to check anything
405  continue;
406  // the index from which on both paths differ
407  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
408  if ( nDivergenceIndex <= nCurrentStatePathIndex )
409  // they differ in an index which we have already left behind us
410  // -> this is no conflict anymore
411  continue;
412 
413  // the path conflicts with our new path -> don't activate the
414  // *complete* new path, but only up to the step which is unambiguous
415  nUpperStepBoundary = nDivergenceIndex;
416  }
417  }
418 
419  // can we advance from the current page?
420  bool bCurrentPageCanAdvance = true;
421  BuilderPage* pCurrentPage = GetPage( getCurrentState() );
422  if ( pCurrentPage )
423  {
424  const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) );
425  OSL_ENSURE( pController != nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" );
426  bCurrentPageCanAdvance = !pController || pController->canAdvance();
427  }
428 
429  // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
430  // path, up to (excluding) nUpperStepBoundary
431  RoadmapTypes::ItemIndex nRoadmapItems = m_xAssistant->get_n_pages();
432  RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, nRoadmapItems );
433  for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
434  {
435  bool bExistentItem = ( nItemIndex < nRoadmapItems );
436  bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
437 
438  bool bInsertItem = false;
439  if ( bExistentItem )
440  {
441  if ( !bNeedItem )
442  {
443  int nPages = nRoadmapItems;
444  for (int i = nPages - 1; i >= nItemIndex; --i)
445  {
446  m_xAssistant->set_page_title(m_xAssistant->get_page_ident(i), "");
447  --nRoadmapItems;
448  }
449  break;
450  }
451  else
452  {
453  // there is an item with this index in the roadmap - does it match what is requested by
454  // the respective state in the active path?
455  RoadmapTypes::ItemId nPresentItemId = m_xAssistant->get_page_ident(nItemIndex).toInt32();
456  WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
457  if ( nPresentItemId != nRequiredState )
458  {
459  m_xAssistant->set_page_title(OString::number(nPresentItemId), "");
460  bInsertItem = true;
461  }
462  }
463  }
464  else
465  {
466  DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
467  bInsertItem = bNeedItem;
468  }
469 
470  WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
471 
472  if ( bInsertItem )
473  {
474  GetOrCreatePage(nState);
475  }
476 
477  OString sIdent(OString::number(nState));
478  m_xAssistant->set_page_index(sIdent, nItemIndex);
479  m_xAssistant->set_page_title(sIdent, getStateDisplayName(nState));
480 
481  // if the item is *after* the current state, but the current page does not
482  // allow advancing, the disable the state. This relieves derived classes
483  // from disabling all future states just because the current state does not
484  // (yet) allow advancing.
485  const bool bUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex );
486  const bool bEnable = !bUnconditionedDisable && ( m_pImpl->aDisabledStates.find( nState ) == m_pImpl->aDisabledStates.end() );
487  m_xAssistant->set_page_sensitive(sIdent, bEnable);
488  }
489  }
490 
492  {
493  sal_Int32 nCurrentStatePathIndex = -1;
494 
495  Paths::const_iterator aActivePathPos = m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath );
496  if ( aActivePathPos != m_xRoadmapImpl->aPaths.end() )
497  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
498 
499  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
500  if ( nCurrentStatePathIndex == -1 )
501  return WZS_INVALID_STATE;
502 
503  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
504 
505  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
506  && ( m_xRoadmapImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_xRoadmapImpl->aDisabledStates.end() )
507  )
508  {
509  ++nNextStateIndex;
510  }
511 
512  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
513  // there is no next state in the current path (at least none which is enabled)
514  return WZS_INVALID_STATE;
515 
516  return aActivePathPos->second[ nNextStateIndex ];
517  }
518 
520  {
521  sal_Int32 nCurrentStatePathIndex = -1;
522 
523  Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath );
524  if ( aActivePathPos != m_pImpl->aPaths.end() )
525  nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
526 
527  DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
528  if ( nCurrentStatePathIndex == -1 )
529  return WZS_INVALID_STATE;
530 
531  sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
532 
533  while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
534  && ( m_pImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_pImpl->aDisabledStates.end() )
535  )
536  {
537  ++nNextStateIndex;
538  }
539 
540  if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
541  // there is no next state in the current path (at least none which is enabled)
542  return WZS_INVALID_STATE;
543 
544  return aActivePathPos->second[ nNextStateIndex ];
545  }
546 
548  {
549  if ( !m_xRoadmapImpl->bActivePathIsDefinite )
550  {
551  // check how many paths are still allowed
552  const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
553  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
554 
555  size_t nPossiblePaths(0);
556  for (auto const& path : m_xRoadmapImpl->aPaths)
557  {
558  // the index from which on both paths differ
559  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
560 
561  if ( nDivergenceIndex > nCurrentStatePathIndex )
562  // this path is still a possible path
563  nPossiblePaths += 1;
564  }
565 
566  // if we have more than one path which is still possible, then we assume
567  // to always have a next state. Though there might be scenarios where this
568  // is not true, but this is too sophisticated (means not really needed) right now.
569  if ( nPossiblePaths > 1 )
570  return true;
571  }
572 
573  const WizardPath& rPath = m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ];
574  return *rPath.rbegin() != getCurrentState();
575  }
576 
578  {
579  if ( !m_pImpl->bActivePathIsDefinite )
580  {
581  // check how many paths are still allowed
582  const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] );
583  sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
584 
585  size_t nPossiblePaths(0);
586  for (auto const& path : m_pImpl->aPaths)
587  {
588  // the index from which on both paths differ
589  sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
590 
591  if ( nDivergenceIndex > nCurrentStatePathIndex )
592  // this path is still a possible path
593  nPossiblePaths += 1;
594  }
595 
596  // if we have more than one path which is still possible, then we assume
597  // to always have a next state. Though there might be scenarios where this
598  // is not true, but this is too sophisticated (means not really needed) right now.
599  if ( nPossiblePaths > 1 )
600  return true;
601  }
602 
603  const WizardPath& rPath = m_pImpl->aPaths[ m_pImpl->nActivePath ];
604  return *rPath.rbegin() != getCurrentState();
605  }
606 
608  {
610 
611  // disable the "Previous" button if all states in our history are disabled
612  std::vector< WizardTypes::WizardState > aHistory;
613  getStateHistory( aHistory );
614  bool bHaveEnabledState = false;
615  for (auto const& state : aHistory)
616  {
617  if ( isStateEnabled(state) )
618  {
619  bHaveEnabledState = true;
620  break;
621  }
622  }
623 
624  enableButtons( WizardButtonFlags::PREVIOUS, bHaveEnabledState );
625 
627  }
628 
629  IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void)
630  {
631  RoadmapTypes::ItemId nCurItemId = m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
632  if ( nCurItemId == getCurrentState() )
633  // nothing to do
634  return;
635 
636  if ( isTravelingSuspended() )
637  return;
638 
639  RoadmapWizardTravelSuspension aTravelGuard( *this );
640 
641  sal_Int32 nCurrentIndex = m_xRoadmapImpl->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl->nActivePath );
642  sal_Int32 nNewIndex = m_xRoadmapImpl->getStateIndexInPath( nCurItemId, m_xRoadmapImpl->nActivePath );
643 
644  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
645  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
646  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
647  {
648  return;
649  }
650 
651  bool bResult = true;
652  if ( nNewIndex > nCurrentIndex )
653  {
654  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
655  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
656  while( nTemp )
657  {
658  if( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
659  removePageFromHistory( nTemp );
660  }
661  }
662  else
663  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
664 
665  if ( !bResult )
666  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
667  }
668 
669  IMPL_LINK(RoadmapWizardMachine, OnRoadmapItemSelected, const OString&, rCurItemId, bool)
670  {
671  int nCurItemId = rCurItemId.toInt32();
672 
673  if ( nCurItemId == getCurrentState() )
674  // nothing to do
675  return false;
676 
677  if ( isTravelingSuspended() )
678  return false;
679 
680  WizardTravelSuspension aTravelGuard( *this );
681 
682  sal_Int32 nCurrentIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath );
683  sal_Int32 nNewIndex = m_pImpl->getStateIndexInPath( nCurItemId, m_pImpl->nActivePath );
684 
685  DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
686  "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
687  if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
688  {
689  return false;
690  }
691 
692  bool bResult = true;
693  if ( nNewIndex > nCurrentIndex )
694  {
695  bResult = skipUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
696  WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
697  while( nTemp )
698  {
699  if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() )
700  removePageFromHistory( nTemp );
701  }
702  }
703  else
704  bResult = skipBackwardUntil( static_cast<WizardTypes::WizardState>(nCurItemId) );
705 
706  return bResult;
707  }
708 
710  {
711  // tell the page
712  IWizardPageController* pController = getPageController( GetPage( nState ) );
713  if (pController)
714  {
715  pController->initializePage();
716 
719 
720  enableButtons( WizardButtonFlags::PREVIOUS, !m_xWizardImpl->aStateHistory.empty() );
721 
722  // set the new title - it depends on the current page (i.e. state)
723  implUpdateTitle();
724  }
725 
726  // synchronize the roadmap
728  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() );
729  }
730 
732  {
733  WizardMachine::enterState( _nState );
734 
735  // synchronize the roadmap
737  }
738 
740  {
741  OUString sDisplayName;
742 
743  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
744  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
745  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
746  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
747  sDisplayName = pos->second.first;
748 
749  return sDisplayName;
750  }
751 
753  {
754  OUString sDisplayName;
755 
756  StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState );
757  OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(),
758  "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" );
759  if ( pos != m_pImpl->aStateDescriptors.end() )
760  sDisplayName = pos->second.first;
761 
762  return sDisplayName;
763  }
764 
766  {
767  VclPtr<TabPage> pPage;
768 
769  StateDescriptions::const_iterator pos = m_xRoadmapImpl->aStateDescriptors.find( _nState );
770  OSL_ENSURE( pos != m_xRoadmapImpl->aStateDescriptors.end(),
771  "RoadmapWizard::createPage: no default implementation available for this state!" );
772  if ( pos != m_xRoadmapImpl->aStateDescriptors.end() )
773  {
774  RoadmapPageFactory pFactory = pos->second.second;
775  pPage = (*pFactory)( *this );
776  }
777 
778  return pPage;
779  }
780 
782  {
783  // remember this (in case the state appears in the roadmap later on)
784  if ( _bEnable )
785  m_pImpl->aDisabledStates.erase( _nState );
786  else
787  {
788  m_pImpl->aDisabledStates.insert( _nState );
789  removePageFromHistory( _nState );
790  }
791 
792  // if the state is currently in the roadmap, reflect it's new status
793  m_xAssistant->set_page_sensitive(OString::number(_nState), _bEnable);
794  }
795 
797  {
798  for (auto const& path : m_pImpl->aPaths)
799  {
800  for (auto const& state : path.second)
801  {
802  if ( state == i_nState )
803  return true;
804  }
805  }
806  return false;
807  }
808 
810  {
811  return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end();
812  }
813 
814  void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable)
815  {
816  m_xRoadmapImpl->pRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable);
817  }
818 
820  {
821  m_xRoadmapImpl->pRoadmap->SelectRoadmapItemByID(nItemId);
822  }
823 
825  {
826  while (m_xRoadmapImpl->pRoadmap->GetItemCount())
827  m_xRoadmapImpl->pRoadmap->DeleteRoadmapItem(0);
828  }
829 
831  {
832  m_xRoadmapImpl->pRoadmap->SetItemSelectHdl(_rHdl);
833  }
834 
836  {
837  return m_xRoadmapImpl->pRoadmap->GetCurrentRoadmapItemID();
838  }
839 
840 } // namespace vcl
841 
842 /* 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:40
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
virtual void initializePage()=0
A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for refer...
Definition: button.hxx:32
virtual ~RoadmapWizardMachine() override
std::unique_ptr< WizardMachineImplData > m_xWizardImpl
Definition: wizdlg.hxx:112
virtual void updateTravelUI() override
updates the user interface which deals with traveling in the wizard
void disposeAndClear()
Definition: vclptr.hxx:200
virtual Size GetSizePixel() const
Definition: window.cxx:2365
void SetItemSelectHdl(const Link< LinkParamNone *, void > &_rHdl)
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:608
WizardTypes::WizardState getCurrentState() const
returns the current state of the machine
Definition: wizdlg.hxx:255
PREVIOUS
VclPtr< TabPage > mpPage
Definition: wizdlg.hxx:32
#define WZS_INVALID_STATE
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
void SelectRoadmapItemByID(int nId)
TabPage * GetPage(sal_uInt16 nLevel) const
#define DBG_ASSERT(sCon, aError)
VclPtr< PushButton > m_pNextPage
Definition: wizdlg.hxx:107
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
int i
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:39
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 SetEmptyViewMargin()
declares the view area to have an empty margin
void enableState(WizardTypes::WizardState nState, bool _bEnable=true)
en- or disables a state
InitFlag
Definition: dialog.hxx:37
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:940
NEXT
helper class to temporarily suspend any traveling in the wizard
Definition: wizdlg.hxx:311
VclPtr< PushButton > mpPrevBtn
Definition: wizdlg.hxx:73
std::unique_ptr< RoadmapWizardImpl > m_xRoadmapImpl
Definition: wizdlg.hxx:114
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:593
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
void SetViewWindow(vcl::Window *pWindow)
Definition: wizdlg.hxx:144
VclPtr< CancelButton > m_pCancel
Definition: wizdlg.hxx:106
StateDescriptions aStateDescriptors
void enterState(WizardTypes::WizardState _nState)
will be called when a new page is about to be displayed
void SetViewAlign(WindowAlign eAlign)
Definition: wizdlg.hxx:145
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:626
BuilderPage * GetPage(WizardTypes::WizardState eState) const
OUString VclResId(const char *pId)
Definition: svdata.cxx:258
void enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable)
enable (or disable) buttons
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:108
RoadmapWizardMachine(weld::Window *_pParent)
IMPL_LINK_NOARG(QuickSelectionEngine_Data, SearchStringTimeout, Timer *, void)
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:2113
static IWizardPageController * getPageController(TabPage *_pCurrentPage)
VclPtr< OKButton > m_pFinish
Definition: wizdlg.hxx:105
VclPtr< HelpButton > m_pHelp
Definition: wizdlg.hxx:109
bool isAutomaticNextButtonStateEnabled() const
enables the automatic enabled/disabled state of the "Next" button
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
void setHeight(long nHeight)
bool canAdvance() const
determines whether there is a next state to which we can advance