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