/* -*- 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 <comphelper/string.hxx>
#include <vcl/svapp.hxx>
#include <sal/log.hxx>
#include "parawin.hxx"
#include <formula/IFunctionDescription.hxx>
#include <formula/funcvarargs.h>
#include <strings.hrc>
#include <bitmaps.hlst>
#include <core_resource.hxx>
#include <rtl/math.hxx>
namespace formula
{
// Formula token argument count is sal_uInt8, max 255, edit offset 254.
constexpr sal_uInt16 kMaxArgCount = 255 ;
constexpr sal_uInt16 kMaxArgOffset = kMaxArgCount - 1 ;
ParaWin::ParaWin(weld::Container* pParent,IControlReferenceHandler* _pDlg)
: pFuncDesc(nullptr)
, pMyParent(_pDlg)
, m_sOptional(ForResId(STR_OPTIONAL))
, m_sRequired(ForResId(STR_REQUIRED))
, m_xBuilder(Application::CreateBuilder(pParent, u"formula/ui/parameter.ui" _ustr))
, m_xContainer(m_xBuilder->weld_container(u"ParameterPage" _ustr))
, m_xSlider(m_xBuilder->weld_scrolled_window(u"scrollbar" _ustr, true ))
, m_xParamGrid(m_xBuilder->weld_widget(u"paramgrid" _ustr))
, m_xGrid(m_xBuilder->weld_widget(u"grid" _ustr))
, m_xFtEditDesc(m_xBuilder->weld_label(u"editdesc" _ustr))
, m_xFtArgName(m_xBuilder->weld_label(u"parname" _ustr))
, m_xFtArgDesc(m_xBuilder->weld_label(u"pardesc" _ustr))
, m_xBtnFx1(m_xBuilder->weld_button(u"FX1" _ustr))
, m_xBtnFx2(m_xBuilder->weld_button(u"FX2" _ustr))
, m_xBtnFx3(m_xBuilder->weld_button(u"FX3" _ustr))
, m_xBtnFx4(m_xBuilder->weld_button(u"FX4" _ustr))
, m_xFtArg1(m_xBuilder->weld_label(u"FT_ARG1" _ustr))
, m_xFtArg2(m_xBuilder->weld_label(u"FT_ARG2" _ustr))
, m_xFtArg3(m_xBuilder->weld_label(u"FT_ARG3" _ustr))
, m_xFtArg4(m_xBuilder->weld_label(u"FT_ARG4" _ustr))
, m_xEdArg1(new ArgEdit(m_xBuilder->weld_entry(u"ED_ARG1" _ustr)))
, m_xEdArg2(new ArgEdit(m_xBuilder->weld_entry(u"ED_ARG2" _ustr)))
, m_xEdArg3(new ArgEdit(m_xBuilder->weld_entry(u"ED_ARG3" _ustr)))
, m_xEdArg4(new ArgEdit(m_xBuilder->weld_entry(u"ED_ARG4" _ustr)))
, m_xRefBtn1(new RefButton(m_xBuilder->weld_button(u"RB_ARG1" _ustr)))
, m_xRefBtn2(new RefButton(m_xBuilder->weld_button(u"RB_ARG2" _ustr)))
, m_xRefBtn3(new RefButton(m_xBuilder->weld_button(u"RB_ARG3" _ustr)))
, m_xRefBtn4(new RefButton(m_xBuilder->weld_button(u"RB_ARG4" _ustr)))
{
// Space for three lines of text in function description.
m_xFtEditDesc->set_label(u"X\nX\nX\n" _ustr);
auto nEditHeight = m_xFtEditDesc->get_preferred_size().Height();
m_xFtEditDesc->set_size_request(-1 , nEditHeight);
m_xFtEditDesc->set_label(u"" _ustr);
// Space for two lines of text in parameter description.
m_xFtArgDesc->set_label(u"X\nX\n" _ustr);
auto nArgHeight = m_xFtArgDesc->get_preferred_size().Height();
m_xFtArgDesc->set_size_request(-1 , nArgHeight);
m_xFtArgDesc->set_label(u"" _ustr);
m_xBtnFx1->set_from_icon_name(BMP_FX);
m_xBtnFx2->set_from_icon_name(BMP_FX);
m_xBtnFx3->set_from_icon_name(BMP_FX);
m_xBtnFx4->set_from_icon_name(BMP_FX);
//lock down initial preferences
m_xParamGrid->set_size_request(-1 , m_xParamGrid->get_preferred_size().Height());
Size aSize(m_xContainer->get_preferred_size());
m_xContainer->set_size_request(aSize.Width(), aSize.Height());
aDefaultString = m_xFtEditDesc->get_label();
nEdFocus = NOT_FOUND;
nActiveLine = 0 ;
m_xSlider->connect_vadjustment_changed(LINK(this , ParaWin, ScrollHdl));
InitArgInput( 0 , *m_xFtArg1, *m_xBtnFx1, *m_xEdArg1, *m_xRefBtn1);
InitArgInput( 1 , *m_xFtArg2, *m_xBtnFx2, *m_xEdArg2, *m_xRefBtn2);
InitArgInput( 2 , *m_xFtArg3, *m_xBtnFx3, *m_xEdArg3, *m_xRefBtn3);
InitArgInput( 3 , *m_xFtArg4, *m_xBtnFx4, *m_xEdArg4, *m_xRefBtn4);
ClearAll();
}
void ParaWin::UpdateArgDesc( sal_uInt16 nArg )
{
if (nArg == NOT_FOUND)
return ;
if (nMaxArgs > 4 )
nArg = sal::static_int_cast<sal_uInt16>( nArg + GetSliderPos() );
if ((nMaxArgs <= 0 ) || (nArg >= nMaxArgs))
return ;
OUString aArgDesc;
OUString aArgName;
SetArgumentDesc( OUString() );
SetArgumentText( OUString() );
if ( nArgs < VAR_ARGS )
{
sal_uInt16 nRealArg = (nArg < aVisibleArgMapping.size()) ? aVisibleArgMapping[nArg] : nArg;
aArgDesc = pFuncDesc->getParameterDescription(nRealArg);
aArgName = pFuncDesc->getParameterName(nRealArg) + " " +
((pFuncDesc->isParameterOptional(nRealArg)) ? m_sOptional : m_sRequired);
}
else if ( nArgs < PAIRED_VAR_ARGS )
{
sal_uInt16 nFix = nArgs - VAR_ARGS;
sal_uInt16 nPos = std::min( nArg, nFix );
sal_uInt16 nRealArg = (nPos < aVisibleArgMapping.size() ?
aVisibleArgMapping[nPos] : aVisibleArgMapping.back());
aArgDesc = pFuncDesc->getParameterDescription(nRealArg);
aArgName = pFuncDesc->getParameterName(nRealArg);
sal_uInt16 nVarArgsStart = pFuncDesc->getVarArgsStart();
if ( nArg >= nVarArgsStart )
aArgName += OUString::number( nArg-nVarArgsStart+1 );
aArgName += " " + ((nArg > nFix || pFuncDesc->isParameterOptional(nRealArg)) ? m_sOptional : m_sRequired) ;
}
else
{
sal_uInt16 nFix = nArgs - PAIRED_VAR_ARGS;
sal_uInt16 nPos;
if ( nArg < nFix )
nPos = nArg;
else
nPos = nFix + ( (nArg-nFix) % 2 );
sal_uInt16 nRealArg = (nPos < aVisibleArgMapping.size() ?
aVisibleArgMapping[nPos] : aVisibleArgMapping.back());
aArgDesc = pFuncDesc->getParameterDescription(nRealArg);
aArgName = pFuncDesc->getParameterName(nRealArg);
sal_uInt16 nVarArgsStart = pFuncDesc->getVarArgsStart();
if ( nArg >= nVarArgsStart )
{
sal_Int16 nShifted = pFuncDesc->getFunctionName().equalsIgnoreAsciiCase(u"LET" ) ? nPos / 2 : 0 ;
aArgName += OUString::number( (nArg-nVarArgsStart)/2 + 1 + nShifted );
}
aArgName += " " + ((nArg > (nFix+1 ) || pFuncDesc->isParameterOptional(nRealArg)) ? m_sOptional : m_sRequired) ;
}
SetArgumentDesc(aArgDesc);
SetArgumentText(aArgName);
}
void ParaWin::UpdateArgInput( sal_uInt16 nOffset, sal_uInt16 i )
{
sal_uInt16 nArg = nOffset + i;
if (nArg > kMaxArgOffset)
return ;
if ( nArgs < VAR_ARGS)
{
if (nArg < nMaxArgs)
{
sal_uInt16 nRealArg = aVisibleArgMapping[nArg];
SetArgNameFont (i,(pFuncDesc->isParameterOptional(nRealArg))
? aFntLight : aFntBold );
SetArgName (i,pFuncDesc->getParameterName(nRealArg));
}
}
else if ( nArgs < PAIRED_VAR_ARGS)
{
sal_uInt16 nFix = nArgs - VAR_ARGS;
sal_uInt16 nPos = std::min( nArg, nFix );
sal_uInt16 nRealArg = (nPos < aVisibleArgMapping.size() ?
aVisibleArgMapping[nPos] : aVisibleArgMapping.back());
SetArgNameFont( i,
(nArg > nFix || pFuncDesc->isParameterOptional(nRealArg)) ?
aFntLight : aFntBold );
sal_uInt16 nVarArgsStart = pFuncDesc->getVarArgsStart();
if ( nArg >= nVarArgsStart )
{
OUString aArgName = pFuncDesc->getParameterName(nRealArg) +
OUString::number(nArg-nVarArgsStart+1 );
SetArgName( i, aArgName );
}
else
SetArgName( i, pFuncDesc->getParameterName(nRealArg) );
}
else
{
sal_uInt16 nFix = nArgs - PAIRED_VAR_ARGS;
sal_uInt16 nPos;
if ( nArg < nFix )
nPos = nArg;
else
nPos = nFix + ( (nArg-nFix) % 2 );
sal_uInt16 nRealArg = (nPos < aVisibleArgMapping.size() ?
aVisibleArgMapping[nPos] : aVisibleArgMapping.back());
SetArgNameFont( i,
(nArg > (nFix+1 ) || pFuncDesc->isParameterOptional(nRealArg)) ?
aFntLight : aFntBold );
sal_uInt16 nVarArgsStart = pFuncDesc->getVarArgsStart();
if ( nArg >= nVarArgsStart )
{
sal_Int16 nShifted = pFuncDesc->getFunctionName().equalsIgnoreAsciiCase(u"LET" ) ? nPos / 2 : 0 ;
OUString aArgName = pFuncDesc->getParameterName(nRealArg) +
OUString::number( (nArg-nVarArgsStart)/2 + 1 + nShifted);
SetArgName( i, aArgName );
}
else
SetArgName( i, pFuncDesc->getParameterName(nRealArg) );
}
if (nArg < nMaxArgs)
aArgInput[i].SetArgVal(aParaArray[nArg]);
}
ParaWin::~ParaWin()
{
// #i66422# if the focus changes during destruction of the controls,
// don't call the focus handlers
Link<weld::Widget&,void > aEmptyLink;
m_xBtnFx1->connect_focus_in(aEmptyLink);
m_xBtnFx2->connect_focus_in(aEmptyLink);
m_xBtnFx3->connect_focus_in(aEmptyLink);
m_xBtnFx4->connect_focus_in(aEmptyLink);
}
void ParaWin::SetActiveLine(sal_uInt16 no)
{
if (no >= nMaxArgs)
return ;
tools::Long nOffset = GetSliderPos();
nActiveLine=no;
tools::Long nNewEdPos=static_cast <tools::Long >(nActiveLine)-nOffset;
if (nNewEdPos<0 || nNewEdPos>3 )
{
nOffset+=nNewEdPos;
SetSliderPos(static_cast <sal_uInt16>(nOffset));
nOffset=GetSliderPos();
}
nEdFocus=no-static_cast <sal_uInt16>(nOffset);
UpdateArgDesc( nEdFocus );
}
RefEdit* ParaWin::GetActiveEdit()
{
if (nMaxArgs > 0 && nEdFocus != NOT_FOUND)
{
return aArgInput[nEdFocus].GetArgEdPtr();
}
else
{
return nullptr;
}
}
OUString ParaWin::GetArgument(sal_uInt16 no)
{
OUString aStr;
if (no<aParaArray.size())
{
aStr=aParaArray[no];
if (no==nActiveLine && aStr.isEmpty())
aStr += " " ;
}
return aStr;
}
OUString ParaWin::GetActiveArgName() const
{
OUString aStr;
if (nMaxArgs > 0 && nEdFocus != NOT_FOUND)
{
aStr=aArgInput[nEdFocus].GetArgName();
}
return aStr;
}
void ParaWin::SetArgument(sal_uInt16 no, std::u16string_view aString)
{
if (no < aParaArray.size())
aParaArray[no] = comphelper::string::stripStart(aString, ' ' );
}
void ParaWin::SetArgumentFonts(const vcl::Font&aBoldFont,const vcl::Font&aLightFont)
{
aFntBold=aBoldFont;
aFntLight=aLightFont;
}
void ParaWin::SetFunctionDesc(const IFunctionDescription* pFDesc)
{
pFuncDesc=pFDesc;
SetArgumentDesc( OUString() );
SetArgumentText( OUString() );
SetEditDesc( OUString() );
nMaxArgs = nArgs = 0 ;
if ( pFuncDesc!=nullptr)
{
if ( !pFuncDesc->getDescription().isEmpty() )
{
SetEditDesc(pFuncDesc->getDescription());
}
else
{
SetEditDesc(aDefaultString);
}
nArgs = pFuncDesc->getSuppressedArgumentCount();
nMaxArgs = std::min( nArgs, kMaxArgCount);
if (sal_uInt16 nVarArgsLimit = pFuncDesc->getVarArgsLimit())
nMaxArgs = std::min( nVarArgsLimit, nMaxArgs);
pFuncDesc->fillVisibleArgumentMapping(aVisibleArgMapping);
m_xSlider->set_vpolicy(VclPolicyType::NEVER);
m_xSlider->set_size_request(-1 , -1 );
OUString sHelpId = pFuncDesc->getHelpId();
m_xContainer->set_help_id(sHelpId);
m_xEdArg1->GetWidget()->set_help_id(sHelpId);
m_xEdArg2->GetWidget()->set_help_id(sHelpId);
m_xEdArg3->GetWidget()->set_help_id(sHelpId);
m_xEdArg4->GetWidget()->set_help_id(sHelpId);
SetActiveLine(0 );
}
else
{
nActiveLine=0 ;
}
}
void ParaWin::SetArgumentText(const OUString& aText)
{
m_xFtArgName->set_label(aText);
}
void ParaWin::SetArgumentDesc(const OUString& aText)
{
m_xFtArgDesc->set_label(aText);
}
void ParaWin::SetEditDesc(const OUString& aText)
{
m_xFtEditDesc->set_label(aText);
}
void ParaWin::SetArgName(sal_uInt16 no,const OUString& aText)
{
aArgInput[no].SetArgName(aText);
aArgInput[no].UpdateAccessibleNames();
}
void ParaWin::SetArgNameFont(sal_uInt16 no,const vcl::Font& aFont)
{
aArgInput[no].SetArgNameFont(aFont);
}
void ParaWin::SetEdFocus()
{
UpdateArgDesc(0 );
if (!aParaArray.empty())
aArgInput[0 ].GetArgEdPtr()->GrabFocus();
}
void ParaWin::InitArgInput(sal_uInt16 nPos, weld::Label& rFtArg, weld::Button& rBtnFx,
ArgEdit& rEdArg, RefButton& rRefBtn)
{
rRefBtn.SetReferences(pMyParent, &rEdArg);
rEdArg.SetReferences(pMyParent, &rFtArg);
aArgInput[nPos].InitArgInput (&rFtArg,&rBtnFx,&rEdArg,&rRefBtn);
aArgInput[nPos].Hide();
aArgInput[nPos].SetFxClickHdl ( LINK( this , ParaWin, GetFxHdl ) );
aArgInput[nPos].SetFxFocusHdl ( LINK( this , ParaWin, GetFxFocusHdl ) );
aArgInput[nPos].SetEdFocusHdl ( LINK( this , ParaWin, GetEdFocusHdl ) );
aArgInput[nPos].SetEdModifyHdl ( LINK( this , ParaWin, ModifyHdl ) );
aArgInput[nPos].UpdateAccessibleNames();
}
void ParaWin::ClearAll()
{
SetFunctionDesc(nullptr);
SetArgumentOffset(0 );
}
void ParaWin::SetArgumentOffset(sal_uInt16 nOffset)
{
aParaArray.clear();
m_xSlider->vadjustment_set_value(0 );
aParaArray.resize(nMaxArgs);
if (nMaxArgs > 0 )
{
for ( int i=0 ; i<4 && i<nMaxArgs; i++ )
{
aArgInput[i].SetArgVal(OUString());
aArgInput[i].GetArgEdPtr()->Init(
(i==0 ) ? nullptr : aArgInput[i-1 ].GetArgEdPtr(),
(i==3 || i==nMaxArgs-1 ) ? nullptr : aArgInput[i+1 ].GetArgEdPtr(),
*m_xSlider, *this , nMaxArgs );
}
}
UpdateParas();
if (nMaxArgs < 5 )
{
m_xSlider->set_vpolicy(VclPolicyType::NEVER);
m_xSlider->set_size_request(-1 , -1 );
}
else
{
m_xSlider->vadjustment_configure(nOffset, 0 , nMaxArgs, 1 , 4 , 4 );
m_xSlider->set_vpolicy(VclPolicyType::ALWAYS);
Size aPrefSize(m_xGrid->get_preferred_size());
m_xSlider->set_size_request(aPrefSize.Width(), aPrefSize.Height());
}
}
void ParaWin::UpdateParas()
{
sal_uInt16 i;
sal_uInt16 nOffset = GetSliderPos();
if ( nMaxArgs > 0 )
{
for ( i=0 ; (i<nMaxArgs) && (i<4 ); i++ )
{
UpdateArgInput( nOffset, i );
aArgInput[i].Show();
}
}
for ( i=nMaxArgs; i<4 ; i++ )
aArgInput[i].Hide();
}
sal_uInt16 ParaWin::GetSliderPos() const
{
return static_cast <sal_uInt16>(m_xSlider->vadjustment_get_value());
}
void ParaWin::SetSliderPos(sal_uInt16 nSliderPos)
{
sal_uInt16 nOffset = GetSliderPos();
if (m_xSlider->get_visible() && nOffset!=nSliderPos)
{
m_xSlider->vadjustment_set_value(nSliderPos);
for ( sal_uInt16 i=0 ; i<4 ; i++ )
{
UpdateArgInput( nSliderPos, i );
}
}
}
void ParaWin::SliderMoved()
{
sal_uInt16 nOffset = GetSliderPos();
for ( sal_uInt16 i=0 ; i<4 ; i++ )
{
UpdateArgInput( nOffset, i );
}
if (nEdFocus!=NOT_FOUND)
{
UpdateArgDesc( nEdFocus );
aArgInput[nEdFocus].SelectAll();
nActiveLine=nEdFocus+nOffset;
ArgumentModified();
aArgInput[nEdFocus].SelectAll(); // ensure all is still selected
aArgInput[nEdFocus].UpdateAccessibleNames();
}
}
void ParaWin::ArgumentModified()
{
aArgModifiedLink.Call(*this );
}
IMPL_LINK( ParaWin, GetFxHdl, ArgInput&, rPtr, void )
{
sal_uInt16 nOffset = GetSliderPos();
nEdFocus=NOT_FOUND;
for (size_t nPos=0 ; nPos < std::size(aArgInput); ++nPos)
{
if (&rPtr == &aArgInput[nPos])
{
nEdFocus=nPos;
break ;
}
}
if (nEdFocus!=NOT_FOUND)
{
aArgInput[nEdFocus].SelectAll();
nActiveLine=nEdFocus+nOffset;
aFxLink.Call(*this );
}
}
IMPL_LINK( ParaWin, GetFxFocusHdl, ArgInput&, rPtr, void )
{
sal_uInt16 nOffset = GetSliderPos();
nEdFocus=NOT_FOUND;
for (size_t nPos=0 ; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
{
if (&rPtr == &aArgInput[nPos])
{
nEdFocus=nPos;
break ;
}
}
if (nEdFocus!=NOT_FOUND)
{
aArgInput[nEdFocus].SelectAll();
UpdateArgDesc( nEdFocus );
nActiveLine=nEdFocus+nOffset;
}
}
IMPL_LINK( ParaWin, GetEdFocusHdl, ArgInput&, rPtr, void )
{
sal_uInt16 nOffset = GetSliderPos();
nEdFocus=NOT_FOUND;
for (size_t nPos=0 ; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
{
if (&rPtr == &aArgInput[nPos])
{
nEdFocus=nPos;
break ;
}
}
if (nEdFocus!=NOT_FOUND)
{
aArgInput[nEdFocus].SelectAll();
UpdateArgDesc( nEdFocus );
nActiveLine=nEdFocus+nOffset;
ArgumentModified();
aArgInput[nEdFocus].SelectAll(); // ensure all is still selected
aArgInput[nEdFocus].UpdateAccessibleNames();
}
}
IMPL_LINK_NOARG(ParaWin, ScrollHdl, weld::ScrolledWindow&, void )
{
SliderMoved();
}
IMPL_LINK( ParaWin, ModifyHdl, ArgInput&, rPtr, void )
{
sal_uInt16 nOffset = GetSliderPos();
nEdFocus=NOT_FOUND;
for (size_t nPos=0 ; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
{
if (&rPtr == &aArgInput[nPos])
{
nEdFocus=nPos;
break ;
}
}
if (nEdFocus!=NOT_FOUND)
{
size_t nPara = nEdFocus + nOffset;
if (nPara < aParaArray.size())
aParaArray[nPara] = aArgInput[nEdFocus].GetArgVal();
else
{
SAL_WARN("formula.ui" ,"ParaWin::ModifyHdl - shot in foot: nPara " <<
nPara << " >= aParaArray.size() " << aParaArray.size() <<
" with nEdFocus " << nEdFocus <<
" and aArgInput[nEdFocus].GetArgVal() '" << aArgInput[nEdFocus].GetArgVal() << "'" );
}
UpdateArgDesc( nEdFocus);
nActiveLine = static_cast <sal_uInt16>(nPara);
}
ArgumentModified();
}
} // formula
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=98 H=88 G=93
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland