/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <tools/debug.hxx>
#include <tools/json_writer.hxx>
#include <osl/diagnose.h>
#include <vcl/event.hxx>
#include <strings.hrc>
#include <svdata.hxx>
#include <wizdlg.hxx>
#include <vector>
#include "wizimpldata.hxx"
#include <uiobject-internal.hxx>
#define WIZARDDIALOG_BUTTON_OFFSET_Y 6
#define WIZARDDIALOG_BUTTON_DLGOFFSET_X 6
#define WIZARDDIALOG_BUTTON_STDOFFSET_X 6
#define WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X 3
#define WIZARDDIALOG_VIEW_DLGOFFSET_X 6
#define WIZARDDIALOG_VIEW_DLGOFFSET_Y 6
namespace vcl
{
sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState,
const WizardPath& _rPath )
{
sal_Int32 nStateIndexInPath = 0;
for (
auto const & path : _rPath)
{
if (path == _nState)
return nStateIndexInPath;
++nStateIndexInPath;
}
return -1;
}
sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState,
PathId _nPathId )
{
sal_Int32 nStateIndexInPath = -1;
Paths::const_iterator aPathPos = aPaths.find( _nPathId );
if ( aPathPos != aPaths.end( ) )
nStateIndexInPath = getStateIndexInPath( _nState, aPathPos->second );
return nStateIndexInPath;
}
sal_Int32 RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS )
{
sal_Int32 nMinLength = ::std::min( _rLHS.size(), _rRHS.size() );
for ( sal_Int32 nCheck = 0; nCheck < nMinLength; ++nCheck )
{
if ( _rLHS[ nCheck ] != _rRHS[ nCheck ] )
return nCheck;
}
return nMinLength;
}
//= RoadmapWizard
RoadmapWizard::RoadmapWizard(vcl::Window* pParent, WinBits nStyle, InitFlag eFlag)
: Dialog(pParent, nStyle, eFlag)
, maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle" )
, m_pFinish(nullptr)
, m_pCancel(nullptr)
, m_pNextPage(nullptr)
, m_pPrevPage(nullptr)
, m_pHelp(nullptr)
, m_xWizardImpl(new WizardMachineImplData)
, m_xRoadmapImpl(new RoadmapWizardImpl)
{
mpFirstPage = nullptr;
mpFirstBtn = nullptr;
mpCurTabPage = nullptr;
mpPrevBtn = nullptr;
mpNextBtn = nullptr;
mnCurLevel = 0;
mbEmptyViewMargin = false ;
mnLeftAlignCount = 0;
maWizardLayoutIdle.SetPriority(TaskPriority::RESIZE);
maWizardLayoutIdle.SetInvokeHandler( LINK( this , RoadmapWizard, ImplHandleWizardLayoutTimerHdl ) );
implConstruct();
SetLeftAlignedButtonCount( 1 );
mbEmptyViewMargin = true ;
mpRoadmap = VclPtr<ORoadmap>::Create(this , WB_TABSTOP);
mpRoadmap->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE ) );
mpRoadmap->SetPosPixel( Point( 0, 0 ) );
mpRoadmap->SetItemSelectHdl( LINK( this , RoadmapWizard, OnRoadmapItemSelected ) );
Size aRoadmapSize = LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont));
aRoadmapSize.setHeight( GetSizePixel().Height() );
mpRoadmap->SetSizePixel( aRoadmapSize );
mpRoadmap->Show();
}
void RoadmapWizard::ShowRoadmap(bool bShow)
{
mpRoadmap->Show(bShow);
CalcAndSetSize();
}
RoadmapWizard::~RoadmapWizard()
{
disposeOnce();
}
void RoadmapWizard::dispose()
{
m_xRoadmapImpl.reset();
m_pFinish.disposeAndClear();
m_pCancel.disposeAndClear();
m_pNextPage.disposeAndClear();
m_pPrevPage.disposeAndClear();
m_pHelp.disposeAndClear();
if (m_xWizardImpl)
{
for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
{
TabPage *pPage = GetPage(i);
if (pPage)
pPage->disposeOnce();
}
m_xWizardImpl.reset();
}
maWizardLayoutIdle.Stop();
// Remove all buttons
while ( mpFirstBtn )
RemoveButton( mpFirstBtn->mpButton );
// Remove all pages
while ( mpFirstPage )
RemovePage( mpFirstPage->mpPage );
mpCurTabPage.reset();
mpPrevBtn.reset();
mpNextBtn.reset();
mpRoadmap.disposeAndClear();
maResponses.clear();
Dialog::dispose();
}
void RoadmapWizard::SetRoadmapHelpId( const OUString& _rId )
{
mpRoadmap->SetHelpId( _rId );
}
void RoadmapWizard::SetRoadmapBitmap(const BitmapEx& rBmp)
{
mpRoadmap->SetRoadmapBitmap(rBmp);
}
void RoadmapWizard::SetLeftAlignedButtonCount( sal_Int16 _nCount )
{
mnLeftAlignCount = _nCount;
}
void RoadmapWizard::ImplCalcSize( Size& rSize )
{
// calculate ButtonBar height and width
tools::Long nMaxHeight = 0;
tools::Long nBarWidth = WIZARDDIALOG_BUTTON_DLGOFFSET_X * 2 + LogicalCoordinateToPixel(6);
ImplWizButtonData* pBtnData = mpFirstBtn;
while (pBtnData)
{
auto nBtnHeight = pBtnData->mpButton->GetSizePixel().Height();
auto nBtnWidth = pBtnData->mpButton->GetSizePixel().Width();
if (pBtnData->mpButton->IsVisible())
{
nBarWidth += nBtnWidth;
nBarWidth += pBtnData->mnOffset;
}
if ( nBtnHeight > nMaxHeight )
nMaxHeight = nBtnHeight;
pBtnData = pBtnData->mpNext;
}
if ( nMaxHeight )
nMaxHeight += WIZARDDIALOG_BUTTON_OFFSET_Y*2;
rSize.AdjustHeight(nMaxHeight);
// add in the view window size
if ( mpRoadmap && mpRoadmap->IsVisible() )
{
Size aViewSize = mpRoadmap->GetSizePixel();
// align left
rSize.AdjustWidth(aViewSize.Width() );
}
if (nBarWidth > rSize.Width())
rSize.setWidth(nBarWidth);
}
void RoadmapWizard::queue_resize(StateChangedType /*eReason*/)
{
if (maWizardLayoutIdle.IsActive())
return ;
if (IsInClose())
return ;
maWizardLayoutIdle.Start();
}
IMPL_LINK_NOARG(RoadmapWizard, ImplHandleWizardLayoutTimerHdl, Timer*, void )
{
ImplPosCtrls();
ImplPosTabPage();
}
void RoadmapWizard::ImplPosCtrls()
{
Size aDlgSize = GetOutputSizePixel();
tools::Long nBtnWidth = 0;
tools::Long nMaxHeight = 0;
tools::Long nOffY = aDlgSize.Height();
ImplWizButtonData* pBtnData = mpFirstBtn;
int j = 0;
while ( pBtnData )
{
if (j >= mnLeftAlignCount)
{
Size aBtnSize = pBtnData->mpButton->GetSizePixel();
tools::Long nBtnHeight = aBtnSize.Height();
if ( nBtnHeight > nMaxHeight )
nMaxHeight = nBtnHeight;
nBtnWidth += aBtnSize.Width();
nBtnWidth += pBtnData->mnOffset;
}
pBtnData = pBtnData->mpNext;
j++;
}
if ( nMaxHeight )
{
tools::Long nOffX = aDlgSize.Width()-nBtnWidth-WIZARDDIALOG_BUTTON_DLGOFFSET_X;
tools::Long nOffLeftAlignX = LogicalCoordinateToPixel(6);
nOffY -= WIZARDDIALOG_BUTTON_OFFSET_Y+nMaxHeight;
pBtnData = mpFirstBtn;
int i = 0;
while ( pBtnData )
{
Size aBtnSize = pBtnData->mpButton->GetSizePixel();
if (i >= mnLeftAlignCount)
{
Point aPos( nOffX, nOffY+((nMaxHeight-aBtnSize.Height())/2) );
pBtnData->mpButton->SetPosPixel( aPos );
nOffX += aBtnSize.Width();
nOffX += pBtnData->mnOffset;
}
else
{
Point aPos( nOffLeftAlignX, nOffY+((nMaxHeight-aBtnSize.Height())/2) );
pBtnData->mpButton->SetPosPixel( aPos );
nOffLeftAlignX += aBtnSize.Width();
nOffLeftAlignX += pBtnData->mnOffset;
}
pBtnData = pBtnData->mpNext;
i++;
}
nOffY -= WIZARDDIALOG_BUTTON_OFFSET_Y;
}
if ( !(mpRoadmap && mpRoadmap->IsVisible()) )
return ;
tools::Long nViewOffX = 0;
tools::Long nViewOffY = 0;
tools::Long nViewWidth = 0;
tools::Long nViewHeight = 0;
tools::Long nDlgHeight = nOffY;
PosSizeFlags nViewPosFlags = PosSizeFlags::Pos;
// align left
{
if ( mbEmptyViewMargin )
{
nViewOffX = 0;
nViewOffY = 0;
nViewHeight = nDlgHeight;
}
else
{
nViewOffX = WIZARDDIALOG_VIEW_DLGOFFSET_X;
nViewOffY = WIZARDDIALOG_VIEW_DLGOFFSET_Y;
nViewHeight = nDlgHeight-(WIZARDDIALOG_VIEW_DLGOFFSET_Y*2);
}
nViewPosFlags |= PosSizeFlags::Height;
}
mpRoadmap->setPosSizePixel( nViewOffX, nViewOffY,
nViewWidth, nViewHeight,
nViewPosFlags );
}
tools::Long RoadmapWizard::LogicalCoordinateToPixel(int iCoordinate) const
{
Size aLocSize = LogicToPixel(Size(iCoordinate, 0), MapMode(MapUnit::MapAppFont));
int iPixelCoordinate = aLocSize.Width();
return iPixelCoordinate;
}
void RoadmapWizard::ImplPosTabPage()
{
if ( !mpCurTabPage )
return ;
if ( !IsInInitShow() )
{
// #100199# - On Unix initial size is equal to screen size, on Windows
// it's 0,0. One cannot calculate the size unless dialog is visible.
if ( !IsReallyVisible() )
return ;
}
// calculate height of ButtonBar
tools::Long nMaxHeight = 0;
ImplWizButtonData* pBtnData = mpFirstBtn;
while ( pBtnData )
{
tools::Long nBtnHeight = pBtnData->mpButton->GetSizePixel().Height();
if ( nBtnHeight > nMaxHeight )
nMaxHeight = nBtnHeight;
pBtnData = pBtnData->mpNext;
}
if ( nMaxHeight )
nMaxHeight += WIZARDDIALOG_BUTTON_OFFSET_Y*2;
// position TabPage
Size aDlgSize = GetOutputSizePixel();
aDlgSize.AdjustHeight( -nMaxHeight );
tools::Long nOffX = 0;
tools::Long nOffY = 0;
if ( mpRoadmap && mpRoadmap->IsVisible() )
{
Size aViewSize = mpRoadmap->GetSizePixel();
// align left
tools::Long nViewOffset = mbEmptyViewMargin ? 0 : WIZARDDIALOG_VIEW_DLGOFFSET_X;
nOffX += aViewSize.Width() + nViewOffset;
aDlgSize.AdjustWidth( -nOffX );
}
Point aPos( nOffX, nOffY );
mpCurTabPage->SetPosSizePixel( aPos, aDlgSize );
}
void RoadmapWizard::ImplShowTabPage( TabPage* pTabPage )
{
if ( mpCurTabPage == pTabPage )
return ;
TabPage* pOldTabPage = mpCurTabPage;
mpCurTabPage = pTabPage;
if ( pTabPage )
{
ImplPosTabPage();
pTabPage->Show();
}
if ( pOldTabPage )
pOldTabPage->Hide();
}
TabPage* RoadmapWizard::ImplGetPage( sal_uInt16 nLevel ) const
{
sal_uInt16 nTempLevel = 0;
ImplWizPageData* pPageData = mpFirstPage;
while ( pPageData )
{
if ( (nTempLevel == nLevel) || !pPageData->mpNext )
break ;
nTempLevel++;
pPageData = pPageData->mpNext;
}
if ( pPageData )
return pPageData->mpPage;
return nullptr;
}
void RoadmapWizard::AddButtonResponse( Button* pButton, int response)
{
maResponses[pButton] = response;
}
void RoadmapWizard::implConstruct()
{
m_xWizardImpl->sTitleBase = GetText();
// create buttons
// the help button
m_pHelp= VclPtr<HelpButton>::Create(this , WB_TABSTOP);
m_pHelp->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
m_pHelp->Show();
m_pHelp->set_id(u"help" _ustr);
AddButtonResponse(m_pHelp, RET_HELP);
AddButton( m_pHelp, WIZARDDIALOG_BUTTON_STDOFFSET_X);
// the previous button
m_pPrevPage = VclPtr<PushButton>::Create(this , WB_TABSTOP);
m_pPrevPage->SetHelpId( HID_WIZARD_PREVIOUS );
m_pPrevPage->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
m_pPrevPage->SetText(VclResId(STR_WIZDLG_PREVIOUS));
m_pPrevPage->Show();
m_pPrevPage->set_id(u"previous" _ustr);
AddButton( m_pPrevPage, ( WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X) ); // half x-offset to the next button
mpPrevBtn = m_pPrevPage;
m_pPrevPage->SetClickHdl( LINK( this , RoadmapWizard, OnPrevPage ) );
// the next button
m_pNextPage = VclPtr<PushButton>::Create(this , WB_TABSTOP);
m_pNextPage->SetHelpId( HID_WIZARD_NEXT );
m_pNextPage->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
m_pNextPage->SetText(VclResId(STR_WIZDLG_NEXT));
m_pNextPage->Show();
m_pNextPage->set_id(u"next" _ustr);
AddButton( m_pNextPage, WIZARDDIALOG_BUTTON_STDOFFSET_X );
mpNextBtn = m_pNextPage;
m_pNextPage->SetClickHdl( LINK( this , RoadmapWizard, OnNextPage ) );
// the finish button
m_pFinish = VclPtr<OKButton>::Create(this , WB_TABSTOP);
m_pFinish->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
m_pFinish->SetText(VclResId(STR_WIZDLG_FINISH));
m_pFinish->Show();
m_pFinish->set_id(u"finish" _ustr);
AddButton( m_pFinish, WIZARDDIALOG_BUTTON_STDOFFSET_X );
m_pFinish->SetClickHdl( LINK( this , RoadmapWizard, OnFinish ) );
// the cancel button
m_pCancel = VclPtr<CancelButton>::Create(this , WB_TABSTOP);
m_pCancel->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
m_pCancel->Show();
AddButton( m_pCancel, WIZARDDIALOG_BUTTON_STDOFFSET_X );
}
void RoadmapWizard::Resize()
{
if ( IsReallyShown() && !IsInInitShow() )
{
ImplPosCtrls();
ImplPosTabPage();
}
Dialog::Resize();
}
void RoadmapWizard::CalcAndSetSize()
{
Size aDlgSize = GetPageSizePixel();
if ( !aDlgSize.Width() || !aDlgSize.Height() )
{
ImplWizPageData* pPageData = mpFirstPage;
while ( pPageData )
{
if ( pPageData->mpPage )
{
Size aPageSize = pPageData->mpPage->GetSizePixel();
if ( aPageSize.Width() > aDlgSize.Width() )
aDlgSize.setWidth( aPageSize.Width() );
if ( aPageSize.Height() > aDlgSize.Height() )
aDlgSize.setHeight( aPageSize.Height() );
}
pPageData = pPageData->mpNext;
}
}
ImplCalcSize( aDlgSize );
SetMinOutputSizePixel( aDlgSize );
SetOutputSizePixel( aDlgSize );
}
void RoadmapWizard::StateChanged( StateChangedType nType )
{
if ( nType == StateChangedType::InitShow )
{
if ( IsDefaultSize() )
{
CalcAndSetSize();
}
ImplPosCtrls();
ImplPosTabPage();
ImplShowTabPage( ImplGetPage( mnCurLevel ) );
}
Dialog::StateChanged( nType );
}
bool RoadmapWizard::EventNotify( NotifyEvent& rNEvt )
{
if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && mpPrevBtn && mpNextBtn )
{
const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
sal_uInt16 nKeyCode = aKeyCode.GetCode();
if ( aKeyCode.IsMod1() )
{
if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
{
if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
{
if ( mpPrevBtn->IsVisible() &&
mpPrevBtn->IsEnabled() && mpPrevBtn->IsInputEnabled() )
{
mpPrevBtn->SetPressed( true );
mpPrevBtn->SetPressed( false );
mpPrevBtn->Click();
}
return true ;
}
}
else
{
if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
{
if ( mpNextBtn->IsVisible() &&
mpNextBtn->IsEnabled() && mpNextBtn->IsInputEnabled() )
{
mpNextBtn->SetPressed( true );
mpNextBtn->SetPressed( false );
mpNextBtn->Click();
}
return true ;
}
}
}
}
return Dialog::EventNotify( rNEvt );
}
void RoadmapWizard::ShowPage(sal_uInt16 nLevel)
{
mnCurLevel = nLevel;
// synchronize the roadmap
implUpdateRoadmap();
mpRoadmap->SelectRoadmapItemByID(getCurrentState());
ImplShowTabPage( ImplGetPage( mnCurLevel ) );
}
void RoadmapWizard::Finish( tools::Long nResult )
{
if ( IsInExecute() )
EndDialog( nResult );
else if ( GetStyle() & WB_CLOSEABLE )
Close();
}
void RoadmapWizard::AddPage( TabPage* pPage )
{
ImplWizPageData* pNewPageData = new ImplWizPageData;
pNewPageData->mpNext = nullptr;
pNewPageData->mpPage = pPage;
if ( !mpFirstPage )
mpFirstPage = pNewPageData;
else
{
pPage->Hide();
ImplWizPageData* pPageData = mpFirstPage;
while ( pPageData->mpNext )
pPageData = pPageData->mpNext;
pPageData->mpNext = pNewPageData;
}
}
void RoadmapWizard::RemovePage( TabPage* pPage )
{
ImplWizPageData* pPrevPageData = nullptr;
ImplWizPageData* pPageData = mpFirstPage;
while ( pPageData )
{
if ( pPageData->mpPage == pPage )
{
if ( pPrevPageData )
pPrevPageData->mpNext = pPageData->mpNext;
else
mpFirstPage = pPageData->mpNext;
if ( pPage == mpCurTabPage )
mpCurTabPage = nullptr;
delete pPageData;
return ;
}
pPrevPageData = pPageData;
pPageData = pPageData->mpNext;
}
OSL_FAIL( "RoadmapWizard::RemovePage() - Page not in list" );
}
void RoadmapWizard::SetPage( sal_uInt16 nLevel, TabPage* pPage )
{
sal_uInt16 nTempLevel = 0;
ImplWizPageData* pPageData = mpFirstPage;
while ( pPageData )
{
if ( (nTempLevel == nLevel) || !pPageData->mpNext )
break ;
nTempLevel++;
pPageData = pPageData->mpNext;
}
if ( pPageData )
{
if ( pPageData->mpPage == mpCurTabPage )
mpCurTabPage = nullptr;
pPageData->mpPage = pPage;
}
}
TabPage* RoadmapWizard::GetPage( sal_uInt16 nLevel ) const
{
sal_uInt16 nTempLevel = 0;
for (ImplWizPageData* pPageData = mpFirstPage; pPageData;
pPageData = pPageData->mpNext)
{
if ( nTempLevel == nLevel )
return pPageData->mpPage;
nTempLevel++;
}
return nullptr;
}
void RoadmapWizard::AddButton( Button* pButton, tools::Long nOffset )
{
ImplWizButtonData* pNewBtnData = new ImplWizButtonData;
pNewBtnData->mpNext = nullptr;
pNewBtnData->mpButton = pButton;
pNewBtnData->mnOffset = nOffset;
if ( !mpFirstBtn )
mpFirstBtn = pNewBtnData;
else
{
ImplWizButtonData* pBtnData = mpFirstBtn;
while ( pBtnData->mpNext )
pBtnData = pBtnData->mpNext;
pBtnData->mpNext = pNewBtnData;
}
}
void RoadmapWizard::RemoveButton( Button* pButton )
{
ImplWizButtonData* pPrevBtnData = nullptr;
ImplWizButtonData* pBtnData = mpFirstBtn;
while ( pBtnData )
{
if ( pBtnData->mpButton == pButton )
{
if ( pPrevBtnData )
pPrevBtnData->mpNext = pBtnData->mpNext;
else
mpFirstBtn = pBtnData->mpNext;
delete pBtnData;
return ;
}
pPrevBtnData = pBtnData;
pBtnData = pBtnData->mpNext;
}
OSL_FAIL( "RoadmapWizard::RemoveButton() - Button not in list" );
}
IMPL_LINK_NOARG(RoadmapWizard, OnFinish, Button*, void )
{
if ( isTravelingSuspended() )
return ;
RoadmapWizardTravelSuspension aTravelGuard( *this );
Finish( RET_OK );
}
void RoadmapWizard::skipBackwardUntil(WizardTypes::WizardState _nTargetState)
{
// don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
std::stack< WizardTypes::WizardState > aTravelVirtually = m_xWizardImpl->aStateHistory;
WizardTypes::WizardState nCurrentRollbackState = getCurrentState();
while ( nCurrentRollbackState != _nTargetState )
{
assert(!aTravelVirtually.empty() && "RoadmapWizard::skipBackwardUntil: this target state does not exist in the history!" );
nCurrentRollbackState = aTravelVirtually.top();
aTravelVirtually.pop();
}
m_xWizardImpl->aStateHistory = std::move(aTravelVirtually);
ShowPage(_nTargetState);
}
void RoadmapWizard::skipUntil(WizardTypes::WizardState _nTargetState)
{
WizardTypes::WizardState nCurrentState = getCurrentState();
// don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
std::stack< WizardTypes::WizardState > aTravelVirtually = m_xWizardImpl->aStateHistory;
while ( nCurrentState != _nTargetState )
{
WizardTypes::WizardState nNextState = determineNextState( nCurrentState );
assert(nNextState != WZS_INVALID_STATE && "RoadmapWizard::skipUntil: the given target state does not exist!" );
// remember the skipped state in the history
aTravelVirtually.push( nCurrentState );
// get the next state
nCurrentState = nNextState;
}
m_xWizardImpl->aStateHistory = std::move(aTravelVirtually);
// show the target page
ShowPage(nCurrentState);
}
void RoadmapWizard::travelNext()
{
// determine the next state to travel to
WizardTypes::WizardState nCurrentState = getCurrentState();
WizardTypes::WizardState nNextState = determineNextState(nCurrentState);
if (WZS_INVALID_STATE == nNextState)
return ;
// the state history is used by the enterState method
// all fine
m_xWizardImpl->aStateHistory.push(nCurrentState);
ShowPage(nNextState);
}
void RoadmapWizard::travelPrevious()
{
DBG_ASSERT(!m_xWizardImpl->aStateHistory.empty(), "RoadmapWizard::travelPrevious: have no previous page!" );
// the next state to switch to
WizardTypes::WizardState nPreviousState = m_xWizardImpl->aStateHistory.top();
// the state history is used by the enterState method
m_xWizardImpl->aStateHistory.pop();
// show this page
ShowPage(nPreviousState);
}
void RoadmapWizard::removePageFromHistory( WizardTypes::WizardState nToRemove )
{
std::stack< WizardTypes::WizardState > aTemp;
while (!m_xWizardImpl->aStateHistory.empty())
{
WizardTypes::WizardState nPreviousState = m_xWizardImpl->aStateHistory.top();
m_xWizardImpl->aStateHistory.pop();
if (nPreviousState != nToRemove)
aTemp.push( nPreviousState );
else
break ;
}
while (!aTemp.empty())
{
m_xWizardImpl->aStateHistory.push( aTemp.top() );
aTemp.pop();
}
}
IMPL_LINK_NOARG(RoadmapWizard, OnPrevPage, Button*, void )
{
if ( isTravelingSuspended() )
return ;
RoadmapWizardTravelSuspension aTravelGuard( *this );
travelPrevious();
}
IMPL_LINK_NOARG(RoadmapWizard, OnNextPage, Button*, void )
{
if ( isTravelingSuspended() )
return ;
RoadmapWizardTravelSuspension aTravelGuard( *this );
travelNext();
}
bool RoadmapWizard::isTravelingSuspended() const
{
return m_xWizardImpl->m_bTravelingSuspended;
}
void RoadmapWizard::suspendTraveling( AccessGuard )
{
DBG_ASSERT( !m_xWizardImpl->m_bTravelingSuspended, "RoadmapWizard::suspendTraveling: already suspended!" );
m_xWizardImpl->m_bTravelingSuspended = true ;
}
void RoadmapWizard::resumeTraveling( AccessGuard )
{
DBG_ASSERT( m_xWizardImpl->m_bTravelingSuspended, "RoadmapWizard::resumeTraveling: nothing to resume!" );
m_xWizardImpl->m_bTravelingSuspended = false ;
}
void RoadmapWizard::implUpdateRoadmap( )
{
DBG_ASSERT( m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath ) != m_xRoadmapImpl->aPaths.end(),
"RoadmapWizard::implUpdateRoadmap: there is no such path!" );
const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
if (nCurrentStatePathIndex < 0)
return ;
assert(nCurrentStatePathIndex >= 0 && o3tl::make_unsigned(nCurrentStatePathIndex) < rActivePath.size());
// determine up to which index (in the new path) we have to display the items
RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast <RoadmapTypes::ItemIndex>(rActivePath.size());
bool bIncompletePath = false ;
if ( !m_xRoadmapImpl->bActivePathIsDefinite )
{
for (auto const & path : m_xRoadmapImpl->aPaths)
{
if ( path.first == m_xRoadmapImpl->nActivePath )
// it's the path we are just activating -> no need to check anything
continue ;
// the index from which on both paths differ
sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
if ( nDivergenceIndex <= nCurrentStatePathIndex )
// they differ in an index which we have already left behind us
// -> this is no conflict anymore
continue ;
// the path conflicts with our new path -> don't activate the
// *complete* new path, but only up to the step which is unambiguous
nUpperStepBoundary = nDivergenceIndex;
bIncompletePath = true ;
}
}
// now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
// path, up to (excluding) nUpperStepBoundary
RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, mpRoadmap->GetItemCount() );
for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
{
bool bExistentItem = ( nItemIndex < mpRoadmap->GetItemCount() );
bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
bool bInsertItem = false ;
if ( bExistentItem )
{
if ( !bNeedItem )
{
while ( nItemIndex < mpRoadmap->GetItemCount() )
mpRoadmap->DeleteRoadmapItem( nItemIndex );
break ;
}
else
{
// there is an item with this index in the roadmap - does it match what is requested by
// the respective state in the active path?
RoadmapTypes::ItemId nPresentItemId = mpRoadmap->GetItemID( nItemIndex );
WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
if ( nPresentItemId != nRequiredState )
{
mpRoadmap->DeleteRoadmapItem( nItemIndex );
bInsertItem = true ;
}
}
}
else
{
DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
bInsertItem = bNeedItem;
}
WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
if ( bInsertItem )
{
mpRoadmap->InsertRoadmapItem(
nItemIndex,
getStateDisplayName( nState ),
nState,
true
);
}
const bool bEnable = m_xRoadmapImpl->aDisabledStates.find( nState ) == m_xRoadmapImpl->aDisabledStates.end();
mpRoadmap->EnableRoadmapItem( mpRoadmap->GetItemID( nItemIndex ), bEnable );
}
mpRoadmap->SetRoadmapComplete( !bIncompletePath );
}
WizardTypes::WizardState RoadmapWizard::determineNextState( WizardTypes::WizardState _nCurrentState ) const
{
sal_Int32 nCurrentStatePathIndex = -1;
Paths::const_iterator aActivePathPos = m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath );
if ( aActivePathPos != m_xRoadmapImpl->aPaths.end() )
nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
if (nCurrentStatePathIndex < 0)
return WZS_INVALID_STATE;
assert(nCurrentStatePathIndex >= 0 && o3tl::make_unsigned(nCurrentStatePathIndex) < aActivePathPos->second.size());
sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
while ( ( nNextStateIndex < static_cast <sal_Int32>(aActivePathPos->second.size()) )
&& ( m_xRoadmapImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_xRoadmapImpl->aDisabledStates.end() )
)
{
++nNextStateIndex;
}
if ( nNextStateIndex >= static_cast <sal_Int32>(aActivePathPos->second.size()) )
// there is no next state in the current path (at least none which is enabled)
return WZS_INVALID_STATE;
return aActivePathPos->second[ nNextStateIndex ];
}
IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void )
{
RoadmapTypes::ItemId nCurItemId = mpRoadmap->GetCurrentRoadmapItemID();
if ( nCurItemId == getCurrentState() )
// nothing to do
return ;
if ( isTravelingSuspended() )
return ;
RoadmapWizardTravelSuspension aTravelGuard( *this );
sal_Int32 nCurrentIndex = m_xRoadmapImpl->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl->nActivePath );
sal_Int32 nNewIndex = m_xRoadmapImpl->getStateIndexInPath( nCurItemId, m_xRoadmapImpl->nActivePath );
DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
"RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
{
return ;
}
if ( nNewIndex > nCurrentIndex )
{
skipUntil(static_cast <WizardTypes::WizardState>(nCurItemId));
WizardTypes::WizardState nTemp = static_cast <WizardTypes::WizardState>(nCurItemId);
while ( nTemp )
{
if ( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
removePageFromHistory( nTemp );
}
}
else
skipBackwardUntil(static_cast <WizardTypes::WizardState>(nCurItemId));
}
OUString RoadmapWizard::getStateDisplayName( WizardTypes::WizardState /* _nState */)
{
SAL_WARN("vcl" , "RoadmapWizard::getStateDisplayName: no name available for this state!" );
return OUString();
}
void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable)
{
mpRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable);
}
void RoadmapWizard::SelectRoadmapItemByID(int nItemId, bool bGrabFocus)
{
mpRoadmap->SelectRoadmapItemByID(nItemId, bGrabFocus);
}
void RoadmapWizard::DeleteRoadmapItems()
{
while (mpRoadmap->GetItemCount())
mpRoadmap->DeleteRoadmapItem(0);
}
void RoadmapWizard::SetItemSelectHdl( const Link<LinkParamNone*,void >& _rHdl )
{
mpRoadmap->SetItemSelectHdl(_rHdl);
}
int RoadmapWizard::GetCurrentRoadmapItemID() const
{
return mpRoadmap->GetCurrentRoadmapItemID();
}
FactoryFunction RoadmapWizard::GetUITestFactory() const
{
return RoadmapWizardUIObject::create;
}
namespace
{
bool isButton(WindowType eType)
{
return eType == WindowType::PUSHBUTTON || eType == WindowType::OKBUTTON
|| eType == WindowType::CANCELBUTTON || eType == WindowType::HELPBUTTON;
}
}
void RoadmapWizard::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
{
rJsonWriter.put("id" , get_id());
rJsonWriter.put("type" , "dialog" );
rJsonWriter.put("title" , GetText());
OUString sDialogId = GetHelpId();
sal_Int32 nStartPos = sDialogId.lastIndexOf('/' );
nStartPos = nStartPos >= 0 ? nStartPos + 1 : 0;
rJsonWriter.put("dialogid" , sDialogId.copy(nStartPos));
{
auto aResponses = rJsonWriter.startArray("responses" );
for (const auto & rResponse : maResponses)
{
auto aResponse = rJsonWriter.startStruct();
rJsonWriter.put("id" , rResponse.first->get_id());
rJsonWriter.put("response" , rResponse.second);
}
}
vcl::Window* pFocusControl = GetFirstControlForFocus();
if (pFocusControl)
rJsonWriter.put("init_focus_id" , pFocusControl->get_id());
{
auto childrenNode = rJsonWriter.startArray("children" );
auto containerNode = rJsonWriter.startStruct();
rJsonWriter.put("id" , "container" );
rJsonWriter.put("type" , "container" );
rJsonWriter.put("vertical" , true );
{
auto containerChildrenNode = rJsonWriter.startArray("children" );
// tabpages
for (int i = 0; i < GetChildCount(); i++)
{
vcl::Window* pChild = GetChild(i);
if (!isButton(pChild->GetType()) && pChild != mpRoadmap)
{
auto childNode = rJsonWriter.startStruct();
pChild->DumpAsPropertyTree(rJsonWriter);
}
}
// buttons
{
auto buttonsNode = rJsonWriter.startStruct();
rJsonWriter.put("id" , "buttons" );
rJsonWriter.put("type" , "buttonbox" );
rJsonWriter.put("layoutstyle" , "end" );
{
auto buttonsChildrenNode = rJsonWriter.startArray("children" );
for (int i = 0; i < GetChildCount(); i++)
{
vcl::Window* pChild = GetChild(i);
if (isButton(pChild->GetType()))
{
auto childNode = rJsonWriter.startStruct();
pChild->DumpAsPropertyTree(rJsonWriter);
}
}
}
}
}
}
}
} // namespace vcl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 C=96 H=82 G=89
¤ Dauer der Verarbeitung: 0.10 Sekunden
¤
*© Formatika GbR, Deutschland