1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/lok.hxx>
21 #include <officecfg/Office/Common.hxx>
22 #include <vcl/event.hxx>
23 #include <tools/debug.hxx>
24 #include <comphelper/diagnose_ex.hxx>
25 #include <strings.hrc>
29 #include "wizimpldata.hxx"
31 constexpr OUStringLiteral HID_WIZARD_NEXT
= u
"SVT_HID_WIZARD_NEXT";
32 constexpr OUStringLiteral HID_WIZARD_PREVIOUS
= u
"SVT_HID_WIZARD_PREVIOUS";
34 #define WIZARDDIALOG_BUTTON_OFFSET_Y 6
35 #define WIZARDDIALOG_BUTTON_DLGOFFSET_X 6
36 #define WIZARDDIALOG_VIEW_DLGOFFSET_X 6
37 #define WIZARDDIALOG_VIEW_DLGOFFSET_Y 6
41 //= WizardPageImplData
42 OWizardPage::OWizardPage(weld::Container
* pPage
, weld::DialogController
* pController
, const OUString
& rUIXMLDescription
, const OUString
& rID
)
43 : BuilderPage(pPage
, pController
, rUIXMLDescription
, rID
)
47 OWizardPage::~OWizardPage()
51 void OWizardPage::initializePage()
55 void OWizardPage::Activate()
57 BuilderPage::Activate();
58 updateDialogTravelUI();
61 void OWizardPage::updateDialogTravelUI()
63 auto pWizardMachine
= dynamic_cast<RoadmapWizardMachine
*>(m_pDialogController
);
65 pWizardMachine
->updateTravelUI();
68 bool OWizardPage::canAdvance() const
73 bool OWizardPage::commitPage( WizardTypes::CommitPageReason
)
78 void RoadmapWizard::SetLeftAlignedButtonCount( sal_Int16 _nCount
)
80 mnLeftAlignCount
= _nCount
;
83 void RoadmapWizard::ImplCalcSize( Size
& rSize
)
85 // calculate ButtonBar height and width
86 tools::Long nMaxHeight
= 0;
87 tools::Long nBarWidth
= WIZARDDIALOG_BUTTON_DLGOFFSET_X
* 2 + LogicalCoordinateToPixel(6);
88 ImplWizButtonData
* pBtnData
= mpFirstBtn
;
91 auto nBtnHeight
= pBtnData
->mpButton
->GetSizePixel().Height();
92 auto nBtnWidth
= pBtnData
->mpButton
->GetSizePixel().Width();
93 if (pBtnData
->mpButton
->IsVisible())
95 nBarWidth
+= nBtnWidth
;
96 nBarWidth
+= pBtnData
->mnOffset
;
98 if ( nBtnHeight
> nMaxHeight
)
99 nMaxHeight
= nBtnHeight
;
100 pBtnData
= pBtnData
->mpNext
;
103 nMaxHeight
+= WIZARDDIALOG_BUTTON_OFFSET_Y
*2;
104 rSize
.AdjustHeight(nMaxHeight
);
106 // add in the view window size
107 if ( mpViewWindow
&& mpViewWindow
->IsVisible() )
109 Size aViewSize
= mpViewWindow
->GetSizePixel();
111 rSize
.AdjustWidth(aViewSize
.Width() );
114 if (nBarWidth
> rSize
.Width())
115 rSize
.setWidth(nBarWidth
);
118 void RoadmapWizard::queue_resize(StateChangedType
/*eReason*/)
120 if (maWizardLayoutIdle
.IsActive())
124 maWizardLayoutIdle
.Start();
127 IMPL_LINK_NOARG(RoadmapWizard
, ImplHandleWizardLayoutTimerHdl
, Timer
*, void)
133 void RoadmapWizard::ImplPosCtrls()
135 Size aDlgSize
= GetOutputSizePixel();
136 tools::Long nBtnWidth
= 0;
137 tools::Long nMaxHeight
= 0;
138 tools::Long nOffY
= aDlgSize
.Height();
140 ImplWizButtonData
* pBtnData
= mpFirstBtn
;
144 if (j
>= mnLeftAlignCount
)
146 Size aBtnSize
= pBtnData
->mpButton
->GetSizePixel();
147 tools::Long nBtnHeight
= aBtnSize
.Height();
148 if ( nBtnHeight
> nMaxHeight
)
149 nMaxHeight
= nBtnHeight
;
150 nBtnWidth
+= aBtnSize
.Width();
151 nBtnWidth
+= pBtnData
->mnOffset
;
153 pBtnData
= pBtnData
->mpNext
;
159 tools::Long nOffX
= aDlgSize
.Width()-nBtnWidth
-WIZARDDIALOG_BUTTON_DLGOFFSET_X
;
160 tools::Long nOffLeftAlignX
= LogicalCoordinateToPixel(6);
161 nOffY
-= WIZARDDIALOG_BUTTON_OFFSET_Y
+nMaxHeight
;
163 pBtnData
= mpFirstBtn
;
167 Size aBtnSize
= pBtnData
->mpButton
->GetSizePixel();
168 if (i
>= mnLeftAlignCount
)
170 Point
aPos( nOffX
, nOffY
+((nMaxHeight
-aBtnSize
.Height())/2) );
171 pBtnData
->mpButton
->SetPosPixel( aPos
);
172 nOffX
+= aBtnSize
.Width();
173 nOffX
+= pBtnData
->mnOffset
;
177 Point
aPos( nOffLeftAlignX
, nOffY
+((nMaxHeight
-aBtnSize
.Height())/2) );
178 pBtnData
->mpButton
->SetPosPixel( aPos
);
179 nOffLeftAlignX
+= aBtnSize
.Width();
180 nOffLeftAlignX
+= pBtnData
->mnOffset
;
183 pBtnData
= pBtnData
->mpNext
;
187 nOffY
-= WIZARDDIALOG_BUTTON_OFFSET_Y
;
190 if ( !(mpViewWindow
&& mpViewWindow
->IsVisible()) )
193 tools::Long nViewOffX
= 0;
194 tools::Long nViewOffY
= 0;
195 tools::Long nViewWidth
= 0;
196 tools::Long nViewHeight
= 0;
197 tools::Long nDlgHeight
= nOffY
;
198 PosSizeFlags nViewPosFlags
= PosSizeFlags::Pos
;
201 if ( mbEmptyViewMargin
)
205 nViewHeight
= nDlgHeight
;
209 nViewOffX
= WIZARDDIALOG_VIEW_DLGOFFSET_X
;
210 nViewOffY
= WIZARDDIALOG_VIEW_DLGOFFSET_Y
;
211 nViewHeight
= nDlgHeight
-(WIZARDDIALOG_VIEW_DLGOFFSET_Y
*2);
213 nViewPosFlags
|= PosSizeFlags::Height
;
215 mpViewWindow
->setPosSizePixel( nViewOffX
, nViewOffY
,
216 nViewWidth
, nViewHeight
,
220 tools::Long
RoadmapWizard::LogicalCoordinateToPixel(int iCoordinate
) const
222 Size aLocSize
= LogicToPixel(Size(iCoordinate
, 0), MapMode(MapUnit::MapAppFont
));
223 int iPixelCoordinate
= aLocSize
.Width();
224 return iPixelCoordinate
;
227 void RoadmapWizard::ImplPosTabPage()
232 if ( !IsInInitShow() )
234 // #100199# - On Unix initial size is equal to screen size, on Windows
235 // it's 0,0. One cannot calculate the size unless dialog is visible.
236 if ( !IsReallyVisible() )
240 // calculate height of ButtonBar
241 tools::Long nMaxHeight
= 0;
242 ImplWizButtonData
* pBtnData
= mpFirstBtn
;
245 tools::Long nBtnHeight
= pBtnData
->mpButton
->GetSizePixel().Height();
246 if ( nBtnHeight
> nMaxHeight
)
247 nMaxHeight
= nBtnHeight
;
248 pBtnData
= pBtnData
->mpNext
;
251 nMaxHeight
+= WIZARDDIALOG_BUTTON_OFFSET_Y
*2;
254 Size aDlgSize
= GetOutputSizePixel();
255 aDlgSize
.AdjustHeight( -nMaxHeight
);
256 tools::Long nOffX
= 0;
257 tools::Long nOffY
= 0;
258 if ( mpViewWindow
&& mpViewWindow
->IsVisible() )
260 Size aViewSize
= mpViewWindow
->GetSizePixel();
262 tools::Long nViewOffset
= mbEmptyViewMargin
? 0 : WIZARDDIALOG_VIEW_DLGOFFSET_X
;
263 nOffX
+= aViewSize
.Width() + nViewOffset
;
264 aDlgSize
.AdjustWidth( -nOffX
);
266 Point
aPos( nOffX
, nOffY
);
267 mpCurTabPage
->SetPosSizePixel( aPos
, aDlgSize
);
270 void RoadmapWizard::ImplShowTabPage( TabPage
* pTabPage
)
272 if ( mpCurTabPage
== pTabPage
)
275 TabPage
* pOldTabPage
= mpCurTabPage
;
277 mpCurTabPage
= pTabPage
;
288 TabPage
* RoadmapWizard::ImplGetPage( sal_uInt16 nLevel
) const
290 sal_uInt16 nTempLevel
= 0;
291 ImplWizPageData
* pPageData
= mpFirstPage
;
294 if ( (nTempLevel
== nLevel
) || !pPageData
->mpNext
)
298 pPageData
= pPageData
->mpNext
;
302 return pPageData
->mpPage
;
306 void RoadmapWizard::implConstruct( const WizardButtonFlags _nButtonFlags
)
308 m_xWizardImpl
->sTitleBase
= GetText();
310 // create the buttons according to the wizard button flags
312 if (_nButtonFlags
& WizardButtonFlags::HELP
)
314 m_pHelp
= VclPtr
<HelpButton
>::Create(this, WB_TABSTOP
);
315 m_pHelp
->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont
)));
317 AddButton( m_pHelp
, WIZARDDIALOG_BUTTON_STDOFFSET_X
);
320 // the previous button
321 if (_nButtonFlags
& WizardButtonFlags::PREVIOUS
)
323 m_pPrevPage
= VclPtr
<PushButton
>::Create(this, WB_TABSTOP
);
324 m_pPrevPage
->SetHelpId( HID_WIZARD_PREVIOUS
);
325 m_pPrevPage
->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont
)));
326 m_pPrevPage
->SetText(VclResId(STR_WIZDLG_PREVIOUS
));
328 m_pPrevPage
->set_id("previous");
330 if (_nButtonFlags
& WizardButtonFlags::NEXT
)
331 AddButton( m_pPrevPage
, ( WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X
) ); // half x-offset to the next button
333 AddButton( m_pPrevPage
, WIZARDDIALOG_BUTTON_STDOFFSET_X
);
334 mpPrevBtn
= m_pPrevPage
;
335 m_pPrevPage
->SetClickHdl( LINK( this, RoadmapWizard
, OnPrevPage
) );
339 if (_nButtonFlags
& WizardButtonFlags::NEXT
)
341 m_pNextPage
= VclPtr
<PushButton
>::Create(this, WB_TABSTOP
);
342 m_pNextPage
->SetHelpId( HID_WIZARD_NEXT
);
343 m_pNextPage
->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont
)));
344 m_pNextPage
->SetText(VclResId(STR_WIZDLG_NEXT
));
346 m_pNextPage
->set_id("next");
348 AddButton( m_pNextPage
, WIZARDDIALOG_BUTTON_STDOFFSET_X
);
349 mpNextBtn
= m_pNextPage
;
350 m_pNextPage
->SetClickHdl( LINK( this, RoadmapWizard
, OnNextPage
) );
354 if (_nButtonFlags
& WizardButtonFlags::FINISH
)
356 m_pFinish
= VclPtr
<OKButton
>::Create(this, WB_TABSTOP
);
357 m_pFinish
->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont
)));
358 m_pFinish
->SetText(VclResId(STR_WIZDLG_FINISH
));
360 m_pFinish
->set_id("finish");
362 AddButton( m_pFinish
, WIZARDDIALOG_BUTTON_STDOFFSET_X
);
363 m_pFinish
->SetClickHdl( LINK( this, RoadmapWizard
, OnFinish
) );
367 if (_nButtonFlags
& WizardButtonFlags::CANCEL
)
369 m_pCancel
= VclPtr
<CancelButton
>::Create(this, WB_TABSTOP
);
370 m_pCancel
->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont
)));
373 AddButton( m_pCancel
, WIZARDDIALOG_BUTTON_STDOFFSET_X
);
377 void RoadmapWizard::Resize()
379 if ( IsReallyShown() && !IsInInitShow() )
388 void RoadmapWizard::CalcAndSetSize()
390 Size aDlgSize
= GetPageSizePixel();
391 if ( !aDlgSize
.Width() || !aDlgSize
.Height() )
393 ImplWizPageData
* pPageData
= mpFirstPage
;
396 if ( pPageData
->mpPage
)
398 Size aPageSize
= pPageData
->mpPage
->GetSizePixel();
399 if ( aPageSize
.Width() > aDlgSize
.Width() )
400 aDlgSize
.setWidth( aPageSize
.Width() );
401 if ( aPageSize
.Height() > aDlgSize
.Height() )
402 aDlgSize
.setHeight( aPageSize
.Height() );
405 pPageData
= pPageData
->mpNext
;
408 ImplCalcSize( aDlgSize
);
409 SetMinOutputSizePixel( aDlgSize
);
410 SetOutputSizePixel( aDlgSize
);
413 void RoadmapWizard::StateChanged( StateChangedType nType
)
415 if ( nType
== StateChangedType::InitShow
)
417 if ( IsDefaultSize() )
424 ImplShowTabPage( ImplGetPage( mnCurLevel
) );
427 Dialog::StateChanged( nType
);
430 bool RoadmapWizard::EventNotify( NotifyEvent
& rNEvt
)
432 if ( (rNEvt
.GetType() == NotifyEventType::KEYINPUT
) && mpPrevBtn
&& mpNextBtn
)
434 const KeyEvent
* pKEvt
= rNEvt
.GetKeyEvent();
435 vcl::KeyCode aKeyCode
= pKEvt
->GetKeyCode();
436 sal_uInt16 nKeyCode
= aKeyCode
.GetCode();
438 if ( aKeyCode
.IsMod1() )
440 if ( aKeyCode
.IsShift() || (nKeyCode
== KEY_PAGEUP
) )
442 if ( (nKeyCode
== KEY_TAB
) || (nKeyCode
== KEY_PAGEUP
) )
444 if ( mpPrevBtn
->IsVisible() &&
445 mpPrevBtn
->IsEnabled() && mpPrevBtn
->IsInputEnabled() )
447 mpPrevBtn
->SetPressed( true );
448 mpPrevBtn
->SetPressed( false );
456 if ( (nKeyCode
== KEY_TAB
) || (nKeyCode
== KEY_PAGEDOWN
) )
458 if ( mpNextBtn
->IsVisible() &&
459 mpNextBtn
->IsEnabled() && mpNextBtn
->IsInputEnabled() )
461 mpNextBtn
->SetPressed( true );
462 mpNextBtn
->SetPressed( false );
471 return Dialog::EventNotify( rNEvt
);
474 void RoadmapWizard::GetOrCreatePage( const WizardTypes::WizardState i_nState
)
476 if ( nullptr != GetPage( i_nState
) )
479 VclPtr
<TabPage
> pNewPage
= createPage( i_nState
);
480 DBG_ASSERT( pNewPage
, "RoadmapWizard::GetOrCreatePage: invalid new page (NULL)!" );
482 // fill up the page sequence of our base class (with dummies)
483 while ( m_xWizardImpl
->nFirstUnknownPage
< i_nState
)
486 ++m_xWizardImpl
->nFirstUnknownPage
;
489 if ( m_xWizardImpl
->nFirstUnknownPage
== i_nState
)
491 // encountered this page number the first time
493 ++m_xWizardImpl
->nFirstUnknownPage
;
496 // already had this page - just change it
497 SetPage( i_nState
, pNewPage
);
500 void RoadmapWizard::ActivatePage()
502 WizardTypes::WizardState nCurrentLevel
= GetCurLevel();
503 GetOrCreatePage( nCurrentLevel
);
505 enterState( nCurrentLevel
);
508 bool RoadmapWizard::ShowPage( sal_uInt16 nLevel
)
512 ImplShowTabPage( ImplGetPage( mnCurLevel
) );
516 void RoadmapWizard::Finish( tools::Long nResult
)
519 EndDialog( nResult
);
520 else if ( GetStyle() & WB_CLOSEABLE
)
524 void RoadmapWizard::AddPage( TabPage
* pPage
)
526 ImplWizPageData
* pNewPageData
= new ImplWizPageData
;
527 pNewPageData
->mpNext
= nullptr;
528 pNewPageData
->mpPage
= pPage
;
531 mpFirstPage
= pNewPageData
;
535 ImplWizPageData
* pPageData
= mpFirstPage
;
536 while ( pPageData
->mpNext
)
537 pPageData
= pPageData
->mpNext
;
538 pPageData
->mpNext
= pNewPageData
;
542 void RoadmapWizard::RemovePage( TabPage
* pPage
)
544 ImplWizPageData
* pPrevPageData
= nullptr;
545 ImplWizPageData
* pPageData
= mpFirstPage
;
548 if ( pPageData
->mpPage
== pPage
)
551 pPrevPageData
->mpNext
= pPageData
->mpNext
;
553 mpFirstPage
= pPageData
->mpNext
;
554 if ( pPage
== mpCurTabPage
)
555 mpCurTabPage
= nullptr;
560 pPrevPageData
= pPageData
;
561 pPageData
= pPageData
->mpNext
;
564 OSL_FAIL( "RoadmapWizard::RemovePage() - Page not in list" );
567 void RoadmapWizard::SetPage( sal_uInt16 nLevel
, TabPage
* pPage
)
569 sal_uInt16 nTempLevel
= 0;
570 ImplWizPageData
* pPageData
= mpFirstPage
;
573 if ( (nTempLevel
== nLevel
) || !pPageData
->mpNext
)
577 pPageData
= pPageData
->mpNext
;
582 if ( pPageData
->mpPage
== mpCurTabPage
)
583 mpCurTabPage
= nullptr;
584 pPageData
->mpPage
= pPage
;
588 TabPage
* RoadmapWizard::GetPage( sal_uInt16 nLevel
) const
590 sal_uInt16 nTempLevel
= 0;
592 for (ImplWizPageData
* pPageData
= mpFirstPage
; pPageData
;
593 pPageData
= pPageData
->mpNext
)
595 if ( nTempLevel
== nLevel
)
596 return pPageData
->mpPage
;
603 void RoadmapWizard::AddButton( Button
* pButton
, tools::Long nOffset
)
605 ImplWizButtonData
* pNewBtnData
= new ImplWizButtonData
;
606 pNewBtnData
->mpNext
= nullptr;
607 pNewBtnData
->mpButton
= pButton
;
608 pNewBtnData
->mnOffset
= nOffset
;
611 mpFirstBtn
= pNewBtnData
;
614 ImplWizButtonData
* pBtnData
= mpFirstBtn
;
615 while ( pBtnData
->mpNext
)
616 pBtnData
= pBtnData
->mpNext
;
617 pBtnData
->mpNext
= pNewBtnData
;
621 void RoadmapWizard::RemoveButton( Button
* pButton
)
623 ImplWizButtonData
* pPrevBtnData
= nullptr;
624 ImplWizButtonData
* pBtnData
= mpFirstBtn
;
627 if ( pBtnData
->mpButton
== pButton
)
630 pPrevBtnData
->mpNext
= pBtnData
->mpNext
;
632 mpFirstBtn
= pBtnData
->mpNext
;
637 pPrevBtnData
= pBtnData
;
638 pBtnData
= pBtnData
->mpNext
;
641 OSL_FAIL( "RoadmapWizard::RemoveButton() - Button not in list" );
644 IMPL_LINK_NOARG(RoadmapWizard
, OnFinish
, Button
*, void)
646 if ( isTravelingSuspended() )
648 RoadmapWizardTravelSuspension
aTravelGuard( *this );
652 bool RoadmapWizard::skipBackwardUntil( WizardTypes::WizardState _nTargetState
)
654 // don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
655 std::stack
< WizardTypes::WizardState
> aTravelVirtually
= m_xWizardImpl
->aStateHistory
;
656 std::stack
< WizardTypes::WizardState
> aOldStateHistory
= m_xWizardImpl
->aStateHistory
;
658 WizardTypes::WizardState nCurrentRollbackState
= getCurrentState();
659 while ( nCurrentRollbackState
!= _nTargetState
)
661 DBG_ASSERT( !aTravelVirtually
.empty(), "RoadmapWizard::skipBackwardUntil: this target state does not exist in the history!" );
662 nCurrentRollbackState
= aTravelVirtually
.top();
663 aTravelVirtually
.pop();
665 m_xWizardImpl
->aStateHistory
= aTravelVirtually
;
666 if ( !ShowPage( _nTargetState
) )
668 m_xWizardImpl
->aStateHistory
= aOldStateHistory
;
674 bool RoadmapWizard::skipUntil( WizardTypes::WizardState _nTargetState
)
676 WizardTypes::WizardState nCurrentState
= getCurrentState();
678 // don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
679 std::stack
< WizardTypes::WizardState
> aTravelVirtually
= m_xWizardImpl
->aStateHistory
;
680 std::stack
< WizardTypes::WizardState
> aOldStateHistory
= m_xWizardImpl
->aStateHistory
;
681 while ( nCurrentState
!= _nTargetState
)
683 WizardTypes::WizardState nNextState
= determineNextState( nCurrentState
);
684 if ( WZS_INVALID_STATE
== nNextState
)
686 OSL_FAIL( "RoadmapWizard::skipUntil: the given target state does not exist!" );
690 // remember the skipped state in the history
691 aTravelVirtually
.push( nCurrentState
);
693 // get the next state
694 nCurrentState
= nNextState
;
696 m_xWizardImpl
->aStateHistory
= aTravelVirtually
;
697 // show the target page
698 if ( !ShowPage( nCurrentState
) )
700 // argh! prepareLeaveCurrentPage succeeded, determineNextState succeeded,
701 // but ShowPage doesn't? Somebody behaves very strange here...
702 OSL_FAIL( "RoadmapWizard::skipUntil: very unpolite..." );
703 m_xWizardImpl
->aStateHistory
= aOldStateHistory
;
709 void RoadmapWizard::travelNext()
711 // determine the next state to travel to
712 WizardTypes::WizardState nCurrentState
= getCurrentState();
713 WizardTypes::WizardState nNextState
= determineNextState(nCurrentState
);
714 if (WZS_INVALID_STATE
== nNextState
)
717 // the state history is used by the enterState method
719 m_xWizardImpl
->aStateHistory
.push(nCurrentState
);
720 if (!ShowPage(nNextState
))
722 m_xWizardImpl
->aStateHistory
.pop();
726 void RoadmapWizard::travelPrevious()
728 DBG_ASSERT(!m_xWizardImpl
->aStateHistory
.empty(), "RoadmapWizard::travelPrevious: have no previous page!");
730 // the next state to switch to
731 WizardTypes::WizardState nPreviousState
= m_xWizardImpl
->aStateHistory
.top();
733 // the state history is used by the enterState method
734 m_xWizardImpl
->aStateHistory
.pop();
736 if (!ShowPage(nPreviousState
))
738 m_xWizardImpl
->aStateHistory
.push(nPreviousState
);
744 void RoadmapWizard::removePageFromHistory( WizardTypes::WizardState nToRemove
)
747 std::stack
< WizardTypes::WizardState
> aTemp
;
748 while(!m_xWizardImpl
->aStateHistory
.empty())
750 WizardTypes::WizardState nPreviousState
= m_xWizardImpl
->aStateHistory
.top();
751 m_xWizardImpl
->aStateHistory
.pop();
752 if(nPreviousState
!= nToRemove
)
753 aTemp
.push( nPreviousState
);
757 while(!aTemp
.empty())
759 m_xWizardImpl
->aStateHistory
.push( aTemp
.top() );
764 IMPL_LINK_NOARG(RoadmapWizard
, OnPrevPage
, Button
*, void)
766 if ( isTravelingSuspended() )
768 RoadmapWizardTravelSuspension
aTravelGuard( *this );
772 IMPL_LINK_NOARG(RoadmapWizard
, OnNextPage
, Button
*, void)
774 if ( isTravelingSuspended() )
776 RoadmapWizardTravelSuspension
aTravelGuard( *this );
780 bool RoadmapWizard::isTravelingSuspended() const
782 return m_xWizardImpl
->m_bTravelingSuspended
;
785 void RoadmapWizard::suspendTraveling( AccessGuard
)
787 DBG_ASSERT( !m_xWizardImpl
->m_bTravelingSuspended
, "RoadmapWizard::suspendTraveling: already suspended!" );
788 m_xWizardImpl
->m_bTravelingSuspended
= true;
791 void RoadmapWizard::resumeTraveling( AccessGuard
)
793 DBG_ASSERT( m_xWizardImpl
->m_bTravelingSuspended
, "RoadmapWizard::resumeTraveling: nothing to resume!" );
794 m_xWizardImpl
->m_bTravelingSuspended
= false;
797 WizardMachine::WizardMachine(weld::Window
* pParent
, WizardButtonFlags nButtonFlags
)
798 : AssistantController(pParent
, "vcl/ui/wizard.ui", "Wizard")
799 , m_pCurTabPage(nullptr)
801 , m_pFirstPage(nullptr)
802 , m_xFinish(m_xAssistant
->weld_widget_for_response(RET_OK
))
803 , m_xCancel(m_xAssistant
->weld_widget_for_response(RET_CANCEL
))
804 , m_xNextPage(m_xAssistant
->weld_widget_for_response(RET_YES
))
805 , m_xPrevPage(m_xAssistant
->weld_widget_for_response(RET_NO
))
806 , m_xHelp(m_xAssistant
->weld_widget_for_response(RET_HELP
))
807 , m_pImpl(new WizardMachineImplData
)
809 implConstruct(nButtonFlags
);
812 void WizardMachine::implConstruct(const WizardButtonFlags nButtonFlags
)
814 m_pImpl
->sTitleBase
= m_xAssistant
->get_title();
816 const bool bHideHelp
= comphelper::LibreOfficeKit::isActive() &&
817 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
818 // create the buttons according to the wizard button flags
820 if (nButtonFlags
& WizardButtonFlags::HELP
&& !bHideHelp
)
825 // the previous button
826 if (nButtonFlags
& WizardButtonFlags::PREVIOUS
)
828 m_xPrevPage
->set_help_id( HID_WIZARD_PREVIOUS
);
831 m_xPrevPage
->connect_clicked( LINK( this, WizardMachine
, OnPrevPage
) );
837 if (nButtonFlags
& WizardButtonFlags::NEXT
)
839 m_xNextPage
->set_help_id( HID_WIZARD_NEXT
);
842 m_xNextPage
->connect_clicked( LINK( this, WizardMachine
, OnNextPage
) );
848 if (nButtonFlags
& WizardButtonFlags::FINISH
)
852 m_xFinish
->connect_clicked( LINK( this, WizardMachine
, OnFinish
) );
858 if (nButtonFlags
& WizardButtonFlags::CANCEL
)
861 m_xCancel
->connect_clicked( LINK( this, WizardMachine
, OnCancel
) );
867 WizardMachine::~WizardMachine()
872 RemovePage(m_pFirstPage
->mxPage
.get());
877 void WizardMachine::implUpdateTitle()
879 OUString
sCompleteTitle(m_pImpl
->sTitleBase
);
881 // append the page title
882 BuilderPage
* pCurrentPage
= GetPage(getCurrentState());
883 if ( pCurrentPage
&& !pCurrentPage
->GetPageTitle().isEmpty() )
885 sCompleteTitle
+= " - " + pCurrentPage
->GetPageTitle();
888 m_xAssistant
->set_title(sCompleteTitle
);
891 void WizardMachine::setTitleBase(const OUString
& _rTitleBase
)
893 m_pImpl
->sTitleBase
= _rTitleBase
;
897 OUString
WizardMachine::getPageIdentForState(WizardTypes::WizardState nState
) const
899 return OUString::number(nState
);
902 WizardTypes::WizardState
WizardMachine::getStateFromPageIdent(const OUString
& rIdent
) const
904 return rIdent
.toInt32();
907 BuilderPage
* WizardMachine::GetOrCreatePage( const WizardTypes::WizardState i_nState
)
909 if ( nullptr == GetPage( i_nState
) )
911 std::unique_ptr
<BuilderPage
> xNewPage
= createPage( i_nState
);
912 DBG_ASSERT( xNewPage
, "WizardMachine::GetOrCreatePage: invalid new page (NULL)!" );
914 // fill up the page sequence of our base class (with dummies)
915 while ( m_pImpl
->nFirstUnknownPage
< i_nState
)
918 ++m_pImpl
->nFirstUnknownPage
;
921 if ( m_pImpl
->nFirstUnknownPage
== i_nState
)
923 // encountered this page number the first time
924 AddPage(std::move(xNewPage
));
925 ++m_pImpl
->nFirstUnknownPage
;
928 // already had this page - just change it
929 SetPage(i_nState
, std::move(xNewPage
));
931 return GetPage( i_nState
);
934 void WizardMachine::ActivatePage()
936 WizardTypes::WizardState nCurrentLevel
= m_nCurState
;
937 GetOrCreatePage( nCurrentLevel
);
939 enterState( nCurrentLevel
);
942 bool WizardMachine::DeactivatePage()
944 WizardTypes::WizardState nCurrentState
= getCurrentState();
945 return leaveState(nCurrentState
);
948 void WizardMachine::defaultButton(WizardButtonFlags _nWizardButtonFlags
)
950 // the new default button
951 weld::Button
* pNewDefButton
= nullptr;
952 if (_nWizardButtonFlags
& WizardButtonFlags::FINISH
)
953 pNewDefButton
= m_xFinish
.get();
954 if (_nWizardButtonFlags
& WizardButtonFlags::NEXT
)
955 pNewDefButton
= m_xNextPage
.get();
956 if (_nWizardButtonFlags
& WizardButtonFlags::PREVIOUS
)
957 pNewDefButton
= m_xPrevPage
.get();
958 if (_nWizardButtonFlags
& WizardButtonFlags::HELP
)
959 pNewDefButton
= m_xHelp
.get();
960 if (_nWizardButtonFlags
& WizardButtonFlags::CANCEL
)
961 pNewDefButton
= m_xCancel
.get();
963 defaultButton(pNewDefButton
);
966 void WizardMachine::defaultButton(weld::Button
* _pNewDefButton
)
968 // loop through all (direct and indirect) descendants which participate in our tabbing order, and
969 // reset the WB_DEFBUTTON for every window which is a button and set _pNewDefButton as the new
971 m_xAssistant
->change_default_widget(nullptr, _pNewDefButton
);
974 void WizardMachine::enableButtons(WizardButtonFlags _nWizardButtonFlags
, bool _bEnable
)
976 if (_nWizardButtonFlags
& WizardButtonFlags::FINISH
)
977 m_xFinish
->set_sensitive(_bEnable
);
978 if (_nWizardButtonFlags
& WizardButtonFlags::NEXT
)
979 m_xNextPage
->set_sensitive(_bEnable
);
980 if (_nWizardButtonFlags
& WizardButtonFlags::PREVIOUS
)
981 m_xPrevPage
->set_sensitive(_bEnable
);
982 if (_nWizardButtonFlags
& WizardButtonFlags::HELP
)
983 m_xHelp
->set_sensitive(_bEnable
);
984 if (_nWizardButtonFlags
& WizardButtonFlags::CANCEL
)
985 m_xCancel
->set_sensitive(_bEnable
);
988 void WizardMachine::enterState(WizardTypes::WizardState _nState
)
991 IWizardPageController
* pController
= getPageController( GetPage( _nState
) );
992 OSL_ENSURE( pController
, "WizardMachine::enterState: no controller for the given page!" );
994 pController
->initializePage();
996 if ( isAutomaticNextButtonStateEnabled() )
997 enableButtons( WizardButtonFlags::NEXT
, canAdvance() );
999 enableButtons( WizardButtonFlags::PREVIOUS
, !m_pImpl
->aStateHistory
.empty() );
1001 // set the new title - it depends on the current page (i.e. state)
1005 bool WizardMachine::leaveState(WizardTypes::WizardState
)
1007 // no need to ask the page here.
1008 // If we reach this point, we already gave the current page the chance to commit it's data,
1009 // and it was allowed to commit it's data
1014 bool WizardMachine::onFinish()
1016 return Finish(RET_OK
);
1019 IMPL_LINK_NOARG(WizardMachine
, OnFinish
, weld::Button
&, void)
1021 if ( isTravelingSuspended() )
1024 // prevent WizardTravelSuspension from using this instance
1025 // after will be destructed due to onFinish and async response call
1027 WizardTravelSuspension
aTravelGuard( *this );
1028 if (!prepareLeaveCurrentState(WizardTypes::eFinish
))
1037 IMPL_LINK_NOARG(WizardMachine
, OnCancel
, weld::Button
&, void)
1039 m_xAssistant
->response(RET_CANCEL
);
1042 WizardTypes::WizardState
WizardMachine::determineNextState(WizardTypes::WizardState _nCurrentState
) const
1044 return _nCurrentState
+ 1;
1047 bool WizardMachine::prepareLeaveCurrentState( WizardTypes::CommitPageReason _eReason
)
1049 IWizardPageController
* pController
= getPageController( GetPage( getCurrentState() ) );
1050 ENSURE_OR_RETURN( pController
!= nullptr, "WizardMachine::prepareLeaveCurrentState: no controller for the current page!", true );
1051 return pController
->commitPage( _eReason
);
1054 bool WizardMachine::skipBackwardUntil(WizardTypes::WizardState _nTargetState
)
1056 // allowed to leave the current page?
1057 if ( !prepareLeaveCurrentState( WizardTypes::eTravelBackward
) )
1060 // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong
1061 std::stack
< WizardTypes::WizardState
> aTravelVirtually
= m_pImpl
->aStateHistory
;
1062 std::stack
< WizardTypes::WizardState
> aOldStateHistory
= m_pImpl
->aStateHistory
;
1064 WizardTypes::WizardState nCurrentRollbackState
= getCurrentState();
1065 while ( nCurrentRollbackState
!= _nTargetState
)
1067 DBG_ASSERT( !aTravelVirtually
.empty(), "WizardMachine::skipBackwardUntil: this target state does not exist in the history!" );
1068 nCurrentRollbackState
= aTravelVirtually
.top();
1069 aTravelVirtually
.pop();
1071 m_pImpl
->aStateHistory
= aTravelVirtually
;
1072 if ( !ShowPage( _nTargetState
) )
1074 m_pImpl
->aStateHistory
= aOldStateHistory
;
1080 bool WizardMachine::skipUntil( WizardTypes::WizardState _nTargetState
)
1082 WizardTypes::WizardState nCurrentState
= getCurrentState();
1084 // allowed to leave the current page?
1085 if ( !prepareLeaveCurrentState( nCurrentState
< _nTargetState
? WizardTypes::eTravelForward
: WizardTypes::eTravelBackward
) )
1088 // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong
1089 std::stack
< WizardTypes::WizardState
> aTravelVirtually
= m_pImpl
->aStateHistory
;
1090 std::stack
< WizardTypes::WizardState
> aOldStateHistory
= m_pImpl
->aStateHistory
;
1091 while ( nCurrentState
!= _nTargetState
)
1093 WizardTypes::WizardState nNextState
= determineNextState( nCurrentState
);
1094 if ( WZS_INVALID_STATE
== nNextState
)
1096 OSL_FAIL( "WizardMachine::skipUntil: the given target state does not exist!" );
1100 // remember the skipped state in the history
1101 aTravelVirtually
.push( nCurrentState
);
1103 // get the next state
1104 nCurrentState
= nNextState
;
1106 m_pImpl
->aStateHistory
= aTravelVirtually
;
1107 // show the target page
1108 if ( !ShowPage( nCurrentState
) )
1110 // argh! prepareLeaveCurrentPage succeeded, determineNextState succeeded,
1111 // but ShowPage doesn't? Somebody behaves very strange here...
1112 OSL_FAIL( "WizardMachine::skipUntil: very unpolite..." );
1113 m_pImpl
->aStateHistory
= aOldStateHistory
;
1119 void WizardMachine::skip()
1121 // allowed to leave the current page?
1122 if ( !prepareLeaveCurrentState( WizardTypes::eTravelForward
) )
1125 WizardTypes::WizardState nCurrentState
= getCurrentState();
1126 WizardTypes::WizardState nNextState
= determineNextState(nCurrentState
);
1128 if (WZS_INVALID_STATE
== nNextState
)
1131 // remember the skipped state in the history
1132 m_pImpl
->aStateHistory
.push(nCurrentState
);
1134 // get the next state
1135 nCurrentState
= nNextState
;
1137 // show the (n+1)th page
1138 if (!ShowPage(nCurrentState
))
1140 // TODO: this leaves us in a state where we have no current page and an inconsistent state history.
1141 // Perhaps we should rollback the skipping here...
1142 OSL_FAIL("RoadmapWizard::skip: very unpolite...");
1143 // if somebody does a skip and then does not allow to leave...
1144 // (can't be a commit error, as we've already committed the current page. So if ShowPage fails here,
1145 // somebody behaves really strange ...)
1152 bool WizardMachine::travelNext()
1154 // allowed to leave the current page?
1155 if ( !prepareLeaveCurrentState( WizardTypes::eTravelForward
) )
1158 // determine the next state to travel to
1159 WizardTypes::WizardState nCurrentState
= getCurrentState();
1160 WizardTypes::WizardState nNextState
= determineNextState(nCurrentState
);
1161 if (WZS_INVALID_STATE
== nNextState
)
1164 // the state history is used by the enterState method
1166 m_pImpl
->aStateHistory
.push(nCurrentState
);
1167 if (!ShowPage(nNextState
))
1169 m_pImpl
->aStateHistory
.pop();
1176 bool WizardMachine::ShowPage(WizardTypes::WizardState nState
)
1178 if (DeactivatePage())
1180 BuilderPage
* pOldTabPage
= m_pCurTabPage
;
1182 m_nCurState
= nState
;
1186 pOldTabPage
->Deactivate();
1188 m_xAssistant
->set_current_page(getPageIdentForState(nState
));
1190 m_pCurTabPage
= GetPage(m_nCurState
);
1191 m_pCurTabPage
->Activate();
1198 bool WizardMachine::ShowNextPage()
1200 return ShowPage(m_nCurState
+ 1);
1203 bool WizardMachine::ShowPrevPage()
1207 return ShowPage(m_nCurState
- 1);
1210 bool WizardMachine::travelPrevious()
1212 DBG_ASSERT(!m_pImpl
->aStateHistory
.empty(), "WizardMachine::travelPrevious: have no previous page!");
1214 // allowed to leave the current page?
1215 if ( !prepareLeaveCurrentState( WizardTypes::eTravelBackward
) )
1218 // the next state to switch to
1219 WizardTypes::WizardState nPreviousState
= m_pImpl
->aStateHistory
.top();
1221 // the state history is used by the enterState method
1222 m_pImpl
->aStateHistory
.pop();
1224 if (!ShowPage(nPreviousState
))
1226 m_pImpl
->aStateHistory
.push(nPreviousState
);
1235 void WizardMachine::removePageFromHistory( WizardTypes::WizardState nToRemove
)
1238 std::stack
< WizardTypes::WizardState
> aTemp
;
1239 while(!m_pImpl
->aStateHistory
.empty())
1241 WizardTypes::WizardState nPreviousState
= m_pImpl
->aStateHistory
.top();
1242 m_pImpl
->aStateHistory
.pop();
1243 if(nPreviousState
!= nToRemove
)
1244 aTemp
.push( nPreviousState
);
1248 while(!aTemp
.empty())
1250 m_pImpl
->aStateHistory
.push( aTemp
.top() );
1256 void WizardMachine::enableAutomaticNextButtonState()
1258 m_pImpl
->m_bAutoNextButtonState
= true;
1262 bool WizardMachine::isAutomaticNextButtonStateEnabled() const
1264 return m_pImpl
->m_bAutoNextButtonState
;
1267 IMPL_LINK_NOARG(WizardMachine
, OnPrevPage
, weld::Button
&, void)
1269 if ( isTravelingSuspended() )
1271 WizardTravelSuspension
aTravelGuard( *this );
1275 IMPL_LINK_NOARG(WizardMachine
, OnNextPage
, weld::Button
&, void)
1277 if ( isTravelingSuspended() )
1279 WizardTravelSuspension
aTravelGuard( *this );
1283 IWizardPageController
* WizardMachine::getPageController(BuilderPage
* pCurrentPage
) const
1285 IWizardPageController
* pController
= dynamic_cast<IWizardPageController
*>(pCurrentPage
);
1289 void WizardMachine::getStateHistory( std::vector
< WizardTypes::WizardState
>& _out_rHistory
)
1291 std::stack
< WizardTypes::WizardState
> aHistoryCopy( m_pImpl
->aStateHistory
);
1292 while ( !aHistoryCopy
.empty() )
1294 _out_rHistory
.push_back( aHistoryCopy
.top() );
1299 bool WizardMachine::canAdvance() const
1301 return WZS_INVALID_STATE
!= determineNextState( getCurrentState() );
1304 void WizardMachine::updateTravelUI()
1306 const IWizardPageController
* pController
= getPageController( GetPage( getCurrentState() ) );
1307 OSL_ENSURE( pController
!= nullptr, "RoadmapWizard::updateTravelUI: no controller for the current page!" );
1310 ( !pController
|| pController
->canAdvance() ) // the current page allows to advance
1311 && canAdvance(); // the dialog as a whole allows to advance
1312 enableButtons( WizardButtonFlags::NEXT
, bCanAdvance
);
1315 bool WizardMachine::isTravelingSuspended() const
1317 return m_pImpl
->m_bTravelingSuspended
;
1320 void WizardMachine::suspendTraveling( AccessGuard
)
1322 DBG_ASSERT( !m_pImpl
->m_bTravelingSuspended
, "WizardMachine::suspendTraveling: already suspended!" );
1323 m_pImpl
->m_bTravelingSuspended
= true;
1326 void WizardMachine::resumeTraveling( AccessGuard
)
1331 DBG_ASSERT( m_pImpl
->m_bTravelingSuspended
, "WizardMachine::resumeTraveling: nothing to resume!" );
1332 m_pImpl
->m_bTravelingSuspended
= false;
1335 bool WizardMachine::Finish(short nResult
)
1337 if ( DeactivatePage() )
1340 m_pCurTabPage
->Deactivate();
1342 m_xAssistant
->response(nResult
);
1349 void WizardMachine::AddPage(std::unique_ptr
<BuilderPage
> xPage
)
1351 WizPageData
* pNewPageData
= new WizPageData
;
1352 pNewPageData
->mpNext
= nullptr;
1353 pNewPageData
->mxPage
= std::move(xPage
);
1355 if ( !m_pFirstPage
)
1356 m_pFirstPage
= pNewPageData
;
1359 WizPageData
* pPageData
= m_pFirstPage
;
1360 while ( pPageData
->mpNext
)
1361 pPageData
= pPageData
->mpNext
;
1362 pPageData
->mpNext
= pNewPageData
;
1366 void WizardMachine::RemovePage(const BuilderPage
* pPage
)
1368 WizPageData
* pPrevPageData
= nullptr;
1369 WizPageData
* pPageData
= m_pFirstPage
;
1372 if (pPageData
->mxPage
.get() == pPage
)
1375 pPrevPageData
->mpNext
= pPageData
->mpNext
;
1377 m_pFirstPage
= pPageData
->mpNext
;
1378 if (pPage
== m_pCurTabPage
)
1379 m_pCurTabPage
= nullptr;
1384 pPrevPageData
= pPageData
;
1385 pPageData
= pPageData
->mpNext
;
1388 OSL_FAIL( "WizardMachine::RemovePage() - Page not in list" );
1391 void WizardMachine::SetPage(WizardTypes::WizardState nLevel
, std::unique_ptr
<BuilderPage
> xPage
)
1393 sal_uInt16 nTempLevel
= 0;
1394 WizPageData
* pPageData
= m_pFirstPage
;
1397 if ( (nTempLevel
== nLevel
) || !pPageData
->mpNext
)
1401 pPageData
= pPageData
->mpNext
;
1406 if (pPageData
->mxPage
.get() == m_pCurTabPage
)
1407 m_pCurTabPage
= nullptr;
1408 pPageData
->mxPage
= std::move(xPage
);
1412 BuilderPage
* WizardMachine::GetPage(WizardTypes::WizardState nLevel
) const
1414 sal_uInt16 nTempLevel
= 0;
1416 for (WizPageData
* pPageData
= m_pFirstPage
; pPageData
;
1417 pPageData
= pPageData
->mpNext
)
1419 if ( nTempLevel
== nLevel
)
1420 return pPageData
->mxPage
.get();
1429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */